#! /s/perl/bin/perl

@files = ();

@defined = ();
@undefined = ();

$undef = 0;
$def = 0;

foreach $item (@ARGV){

    $seen = 1;
    if ($def || $undef){
        if ($undef) {
            $undef = 0;
            push(@undefined,$item);
        } elsif ($def){
            $def = 0;
            push(@defined,$item);
        }

    } elsif (substr($item,0,1) ne '-'){
        push(@files,$item);
    } elsif ($item eq '-D'){
        $def = 1;
    } elsif ($item eq '-U'){
        $undef = 1;
    } elsif (substr($item,0,2) eq '-D') {
        $file = substr($item,2);
        push(@defined,$file);
    } elsif (substr($item,0,2) eq '-U') {
        $file = substr($item,2);
        push(@undefined,$file);
    } else {
        print "$item: Unrecognized option\n";
        &usage;
    }
}

&usage if (!$seen);
&usage if ((@defined == ()) && (@undefined == ()) || (@files == ()));


foreach $file (@files){

    rename("$file", "${file}.bak") || die "Couldn't mv $file to ${file}.bak\n";

    open(IN, "${file}.bak");
    open(OUT, "> $file");
    
   
    &preproc(1,1); 
    
    close OUT;
    close IN;
}

exit 0;

##########################

sub in_list {

    my($item, @list) = @_;
    my($tmp_item);

    foreach $tmp_item (@list){
        if ($tmp_item eq $item){
            return 1;
        }
    }

    return 0;
}

##########################

sub grabdef {

    my($line) = @_;

    if (( $line =~ /\#\s*ifdef\s+([a-zA-Z0-9_]+)/ )
       || ( $line =~ /\#\s*ifndef\s+([a-zA-Z0-9_]+)/ )) {
        return $1;
    }
    return "";
}

##########################

sub preproc {

  my($printing,$verb) = @_;
  my($def);

  while (<IN>){

    if (substr($_,0,1) ne '#'){
        print OUT if ($printing);
        next;
    }

    if ( /#\s*ifdef/ ){
        if ($printing){
            $def = &grabdef($_);
            if ( &in_list($def, @defined) ){
                &preproc(0,0) if (&preproc(1,0));
            } elsif ( &in_list($def, @undefined) ){
                &preproc(1,0) if (&preproc(0,0));
            } else {
                print OUT;
                &preproc(1,1) if (&preproc(1,1));
            }
        } else {
            &preproc(0,0) if (&preproc(0,0));
        }

    } elsif ( /#\s*ifndef/ ){
        if ($printing){
            $def = &grabdef($_);
            if ( &in_list($def, @defined) ){
                &preproc(1,0) if (&preproc(0,0));
            } elsif ( &in_list($def, @undefined) ){
                &preproc(0,0) if (&preproc(1,0));
            } else {
                print OUT;
                &preproc(1,1) if (&preproc(1,1));
            }
        } else {
            &preproc(0,0) if (&preproc(0,0));
        }

    } elsif ( /#\s*if/ ){
        if ($printing){
            print OUT;
            &preproc(1,1) if (&preproc(1,1));
        } else {
            &preproc(0,0) if (&preproc(0,0));
        }
    } elsif ( /#\s*else/ ){
        print OUT if ($verb && $printing);
        return 1;
    } elsif ( /#\s*endif/ ){
        print OUT if ($verb && $printing);
        return 0;
    } else {
        #  define, include, etc
        print OUT if ($printing);
    }

  }
}

##########################

sub usage {

    print "\nUsage: elim [-D<defined name>] [-U<undefined name>] files\n";

    print "\n-D:    Save the defined version of the ifdef.\n";
    print "-U:    Save the undefined version of the ifdef.\n";
    print "\nExample:\n\n"; 

    print "#ifdef    BLAH\n";
    print "        for(i=0; i<5; i++){\n";
    print "#    else\n";
    print "        for(i=5; i>0; i-){\n";
    print "#endif\n\n";

    print "Running this code through 'elim -DBLAH' will result in:\n";
    print "\n        for(i=0; i<5; i++){\n";

    print
    "Note that the other version would have resulted if the test was #ifndef\n";

    die "\n";
}

##########################
