#!/usr/cs/bin/perl

# This script processes a C or C++ file and outputs the code as it would look
# after processing -D directives. 

# Written by David Coppit (david@coppit.org,
# http://www.coppit.org/index.html)
# Please send me any modifications you make. (for the better, that is. :) Feel
# free to modify, adapt, or redistribute, but please leave original authorship
# credit to me.

# Usage: removedef -Dflag -Dflag -f <file.c>

if ($#ARGV == -1)
{
  $0 =~ s/^\.\///;
  print ("Usage: $0 -Dflag -Dflag -f file.c\n");
  print (" -f flips the output, showing how the preprocessor wouldn't process it.\n");
  exit(0);
}

while ($#ARGV != 0) {
  $argument = shift (@ARGV);
  if ($argument =~ /-D(.*)/) {
    push (@defines,$1);
  }

  if ($argument eq "-f") {
    $flipOutput = 1;
  }
}

open (INFILE, $ARGV[0]) || die "Can't open file.\n";
@file = <INFILE>;
close INFILE;

$printing = 1;

for ($line = 0;$line <= $#file;$line++) {
  if ($file[$line] =~ /^#ifdef ([^ ]*)/) {
    $define = $1;
    chomp ($define);

    if (grep (/^$define$/,@definesStack)) {
      print STDERR "Line $line: Saw a nested #ifdef or #ifndef.\n";
    }

    push (@definesStack, $define);
    push (@printingStack, $printing);

    if (!grep (/^$define$/,@defines)) {
      $printing = 0;
    }
    next;
  }

  if ($file[$line] =~ /^#endif(\W)?/) {
    if ($#definesStack == -1) {
      print STDERR "Line $line: Saw an #endif without a matching #ifdef or #ifndef.\n";
    } else {
      pop @definesStack;
      $printing = pop @printingStack;
    }
    next;
  }

  if ($file[$line] =~ /^#else(\W)?/) {
    if ($#definesStack == -1) {
      print STDERR "Line $line: Saw an #else without a previous #ifdef or #ifndef.\n";
    } else {
      $printing = !$printing;
    }
    next;
  }

  if ($file[$line] =~ /^#ifndef ([^ ]*)/) {
    $define = $1;
    chomp ($define);

    if (grep (/^$define$/,@definesStack)) {
      print STDERR "Line $line: Saw a nested #ifdef or #ifndef.\n";
    }

    push (@definesStack, $define);
    push (@printingStack, $printing);

    if (grep (/^$define$/,@defines)) {
      $printing = 0;
    }
    next;
  }

  if ($flipOutput) {
    if (!$printing) {
      print $file[$line];
    }
  } else {
    if ($printing) {
      print $file[$line];
    }
  }
}
