#!/usr/bin/perl -w
#
# Read a file and generate the proper C to define a set of enums and their descriptions
#
$cfile = $hfile = undef;	# Output filenames (.{c,h})
$indent = 4;			# number of spaces to indent
$prefix = "PS_ERR";		# Prefix for enums
$verbose = 0;			# be chatty?
#
while ($ARGV[0] =~ /^-/) {
   if ($ARGV[0] eq "-?") {
      &usage();
      exit(0);
   } elsif ($ARGV[0] =~ /^-[chp]$/) {
      $arg = $ARGV[1];
      if (!$arg) {
	 warn "$ARGV[0] expects an argument\n";
      } else {
	 if ($ARGV[0] eq "-c") {
	    $cfile = "$arg";
	 } elsif ($ARGV[0] eq "-h") {
	    $hfile = "$arg";
	 } elsif ($ARGV[0] eq "-p") {
	    $prefix = "$arg";
	 } else {
	    die "Impossible condition: $ARGV[0]\n";
	 }
      }
      shift(@ARGV);
   } elsif($ARGV[0] eq "-v") {
      $verbose++;
   } else {
      warn "Unknown argument $ARGV[0]\n";
   }

   shift(@ARGV);
}

if (!defined($cfile) && !defined($hfile)) {
   warn "Surely you want some output? Please specify -c and/or -h\n";
   &usage();
   exit 1;
}

if (!@ARGV) {
   warn "Please specify some input files!\n";
   &usage();
   exit 1;
}
#
# OK, read files
#
$input_files = join(" ", @ARGV);
foreach $file (@ARGV) {
   if ($verbose > 1) {
      warn "   $file\n";
   }

   open(FD, $file) or die "Failed to open $file:$! \n";
   while (<FD>) {
      chomp;
      
      s/(^|[^\\])\#.*/$1/;	# strip comments
      s/\\\#/\#/g;		# unprotect #

      if (!$_) {
	 next;
      }
      
      #print "$_\n";

      ($name, undef, $val, $descrip) = /^\s*([^ \t]+)\s*(=\s*(\d+))?\s*,\s*(.*)/;

      push(@names,$name);
      $values{$name} = defined($val) ? $val : undef;
      $descrips{$name} = $descrip;
   }
}

close(FD);
#
# And an entry for the total number of error codes
#
$name = "N_ERR_CLASSES";
$values{$name} = undef;
$descrips{$name} = undef;

push(@names, $name);
#
# Generate .c file
#
if (defined($cfile)) {
   open(FD, ">$cfile") or die("Cannot open $cfile for write\n");
   
   print FD<<"EOT";
/*
 * This file was machine generated from $input_files;
 * please do not modify it
 */

static struct {
    psErrorCode code;
    char *descrip;
} errorStrings[] = {
EOT

   foreach $name (@names) {
      printf FD "%*s{ ${prefix}_%s, ", $indent, "", $name;
      if (defined($descrips{$name})) {
	 printf FD "\"%s\"", $descrips{$name};
      } else {
	 printf FD "NULL";
      }
      printf FD "},\n";
   }

print FD <<"EOT";
};
EOT
}
#
# Generate .h file
#
if (defined($hfile)) {
   open(FD, ">$hfile") or die("Cannot open $hfile for write\n");
   
   print FD <<"EOT";
#if !defined(PS_ERROR_CODES_H)
#define PS_ERROR_CODES_H
/*
 * This file was machine generated from $input_files;
 * please do not modify it
 */
typedef enum {
EOT

   foreach $name (@names) {
      printf FD "%*s${prefix}_%s", $indent, "", $name;
      if (defined($values{$name})) {
	 printf FD " = %d", $values{$name};
      }
      printf FD ",\n";
   }
	 
   print FD <<"EOT";
} psErrorCode;

#endif
EOT
   close(FD);
}
    
###############################################################################

sub usage
{
      warn "\
Usage: makeErrorClasses [options] file [file ...]

Read a file containing lines of the format
   NAME [ = val], description
and generate the proper C to define a set of enums and their descriptions.
Comments start with a # and extend to the end of the line

Options:
        -?		Print this message
        -c file.c       Generate file.c
        -h file.h       Generate file.h
	-p prefix	Change enum prefix from PS_ERR to \"prefix\"
	-v		Be chatty (repeat for even more output)
";
}
