http://invisible-island.net/autoconf/my-autoconf/
Copyright © 2019-2020,2021 by Thomas E. Dickey


#!/usr/bin/env perl
# $Id: xpg3-fixup.pl,v 1.5 2019/01/27 01:40:00 tom Exp $
# -----------------------------------------------------------------------------
# Copyright 2019 by Thomas E. Dickey
#
#                         All Rights Reserved
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name(s) of the above copyright
# holders shall not be used in advertising or otherwise to promote the
# sale, use or other dealings in this Software without prior written
# authorization.
# -----------------------------------------------------------------------------
# convert xpg4 case-statements to xpg3 format in shell scripts

 
use strict;
use warnings;
 
use Getopt::Std;
 
$| = 1;
 
our ( $opt_d$opt_n$opt_v );
 
sub doit($) {
    my $path = shift;
    printf "** $path\n" if ($opt_v);
    if ( openmy $fh$path ) ) {
        my @data = <$fh>;
        close $fh;
        my $changes = 0;
        my $b4_here = 0;
        my $literal = "";
        my $level   = 0;
        my $errors  = 0;
        for my $n ( 0 .. $#data ) {
 
            # When in a here-document, autoconf may a case-statement which
            # may/may not be a fragment.
            if ( $data[$n] =~ /^\s*cat\s+\>[^\s]+\s+\</ ) {
                $b4_here = $level;
                $literal = $data[$n];
                chomp $literal;
                $literal =~ s/^.*<//;
                $literal =~ s/['\\]//g;
                printf "%s:%d: begin here-doc '$literal'\n"$path$n + 1
                  if ($opt_d);
            }
            elsif ( $literal ne "" ) {
                if ( $data[$n] =~ /^\s*$literal\b/ ) {
                    printf "%s:%d: finish here-doc '$literal'\n"$path$n + 1
                      if ($opt_d);
                    $literal = "";
                    $level   = $b4_here;
                }
            }
 
            # The patterns skip zero or more "[" or space at the beginning of a
            # line to accommodate autoconf's use of "[" and "]" delimiters.
            # There could be more complicated patterns, but much harder to deal
            # with.
            if ( $data[$n] =~ /^[\[\s]*case\s+.*\s+in\s*(#.*)?$/ ) {
                printf "%s:%d: push %s"$path$n + 1$data[$nif ($opt_d);
                ++$level;
            }
            elsif ( $data[$n] =~ /^\s*case\b.*:/ ) {
 
                # ignore, C code
            }
            elsif ( $data[$n] =~ /^[\[\s]*case\b/ ) {
                printf STDERR "%s:%d: unexpected case\n"$path$n + 1;
                ++$errors;
            }
            elsif ( $data[$n] =~ /^[\[\s]*esac\s*(#.*)?$/ ) {
                printf "%s:%d: pop  %s"$path$n + 1$data[$nif ($opt_d);
                if ( --$level < 0 ) {
                    if ( $literal eq "" ) {
                        printf STDERR "%s:%d: case/esac unbalanced\n"$path,
                          $n + 1;
                        return;
                    }
                }
            }
            elsif ( $data[$n] =~
                /^\s*\((set|void|int|short|char|long|float|double)\)/ )
            {
 
                # ignore, special cases for autoconf
            }
            elsif ( $level > 0
                and $data[$n] =~
                /^[\[\s]*\((\\.|'[^']+'|\s*\|\s*|\S)+\)(\s+\S.*)?$/ )
            {
                printf "%s:%d: edit %s"$path$n + 1$data[$nif ($opt_d);
                $data[$n] =~ s/\(//;
                printf "%s:%d: ->   %s"$path$n + 1$data[$nif ($opt_d);
                $changes++;
            }
            elsif ( $level > 0
                and $data[$n] =~ /^[\[\s]*\(.\).*;;/ )
            {
                printf "%s:%d: edit %s"$path$n + 1$data[$nif ($opt_d);
                $data[$n] =~ s/\(//;
                printf "%s:%d: ->   %s"$path$n + 1$data[$nif ($opt_d);
                $changes++;
            }
        }
        if ( $changes > 0 ) {
            if ( not $opt_n ) {
                my $save = $path . ".orig";
                if ( -f $save ) {
                    printf STDERR "%s: already exists\n"$save;
                    return;
                }
                if ( not rename$path$save ) ) {
                    printf STDERR "%s: cannot rename to %s\n"$save$path;
                    return;
                }
                if ( openmy $fh">$path" ) ) {
                    for my $n ( 0 .. $#data ) {
                        printf $fh "%s"$data[$n];
                    }
                    close $fh;
                    chmod 0755$path if ( -x $save );
                }
                else {
                    printf STDERR "%s: cannot create\n"$path;
                    rename$save$path );
                    return;
                }
            }
            printf "%d changes %smade\n"$changes$opt_n ? "would be " : "";
        }
        else {
            printf "No changes %smade\n"$opt_n ? "would be " : "";
        }
    }
}
 
sub main::HELP_MESSAGE() {
    printf STDERR <<EOF
Usage: $0 [options] [files]
Convert xpg4 case-statements to xpg3 format in shell scripts.
 
Options:
  -d     debug (more verbose)
  -n     dry-run/noop (do not modify files)
  -v     verbose
EOF
      ;
    exit 1;
}
 
$Getopt::Std::STANDARD_HELP_VERSION = 1;
&getopts('dnv') || &main::HELP_MESSAGE;
$opt_v = 1 if ($opt_d);
&main::HELP_MESSAGE if ( $#ARGV < 0 );
 
while ( $#ARGV >= 0 ) {
    &doitpop @ARGV );
}
 
1;