#!/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})
$prefix = "ps";			# 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);
}

$prefix = lc("$prefix");	# e.g. ps
$PREFIX = uc("$prefix");	#      PS


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);

#
# 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
 */
#include "psError.h"
#include "${prefix}ErrorCodes.h"

void ${prefix}ErrorRegister(void)
{
    static psErrorDescription errors[] = {
EOT

    foreach $name (@names) {
       printf FD "        { ${PREFIX}_ERR_%s, ", $name;
       if (defined($descrips{$name})) {
	  printf FD "\"%s\"", $descrips{$name};
       } else {
	  printf FD "NULL";
       }
       printf FD " },\n";
   }


$names = @names;
print FD <<"EOT";
    };
    static int nerror = $names;		// number of values in enum

    p_psErrorRegister(errors, nerror);
    nerror = 0;			                // don't register more than once
}
EOT
}
#
# Generate .h file
#
if (defined($hfile)) {
   open(FD, ">$hfile") or die("Cannot open $hfile for write\n");
   
   print FD <<"EOT";
#if !defined(${PREFIX}_ERROR_CODES_H)
#define ${PREFIX}_ERROR_CODES_H
/*
 * This file was machine generated from $input_files;
 * please do not modify it
 */
typedef enum {
EOT

   foreach $name (@names) {
      printf FD "    ${PREFIX}_ERR_%s", $name;
      if (defined($values{$name})) {
	 printf FD " = %d", $values{$name};
      }
      printf FD ",\n";
   }
	 
   print FD <<"EOT";
} ${prefix}ErrorCode;

void ${prefix}ErrorRegister(void);

#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/PS to \"prefix/PREFIX\"
	-v		Be chatty (repeat for even more output)
";
}
