#! /usr/bin/perl
# Copyright (c) 1994 James Clark
# See the file COPYING for copying permission.

$prog = $0;
$prog =~ s@.*/@@;

do 'getopts.pl';
&Getopts('C');

# -C generates separate .C and .H files.
# without -C a single .H file is generated which can be included only
# in only one file

die "Usage: $prog [-C] file\n" unless $#ARGV == 0;

$def_file = $ARGV[0];

$file_base = $def_file;
$file_base =~ s/\.[^.]*$//;

$class = $file_base;
$class =~ s|.*/||;


open(DEF, $def_file) || die "can't open \`$def_file': $!\n";

while (<DEF>) {
    chop;
    next if /^[ 	]*#/;
    next if /^[ 	]*$/;
    @field = split('\+', $_, 5);
    &error("too few fields") if $#field < 3;
    $field[0] =~ /^[IWQXE][0-9]$/ || &error("invalid first field");;
    push(@type, substr($field[0], 0, 1));
    $argc = int(substr($field[0], 1, 1));
    push(@nargs, $argc);
    $field[1] =~ /^[a-zA-Z_][a-zA-Z0-9_]+$/ || &error("invalid tag");
    push(@tag, $field[1]);
    &error("duplicate tag $field[1]") if defined($tag_used{$field[1]});
    $tag_used{$field[1]} = 1;
    $field[2] =~ /^([0-9]+(\.[0-9]+)*(p[0-9]+)?( [0-9]+(\.[0-9]+)*(p[0-9]+)?)*)?$/
	|| &error("invalid clauses field");
    # push @clauses, $field[2];
    if ($argc == 0) {
	$field[3] =~ /^([^%]|%%)*$/ || &error("invalid character after %");
    }
    else {
	$field[3] =~ /^([^%]|%[%1-$argc])*$/ || &error("invalid character after %");
    }
    push(@auxloc, ($#field == 4 ? "L" : ""));
    $field[3] =~ s|\\|\\\\|g;
    $field[3] =~ s|"|\\"|g;
    push(@message, $field[3]);
    if ($#field == 4) {
	$field[4] =~ s|\\|\\\\|g;
	$field[4] =~ s|"|\\"|g;
	$message2[$#message] = $field[4];
    }
}

close(DEF);

unlink("$file_base.H");
open(OUT, ">$file_base.H");
chmod 0444, "$file_base.H";
select(OUT);

print <<END;
// This file was automatically generated from $def_file by $prog.
END
print <<END if $opt_C;
#ifndef ${class}_INCLUDED
#define ${class}_INCLUDED 1

#ifdef __GNUG__
#pragma interface
#endif
END

print <<END;
#include "Message.H"

struct $class {
END

foreach $i (0 .. $#message) {
    if (defined($message[$i])) {
	print "  static const MessageType$nargs[$i]$auxloc[$i] $tag[$i];\n";
    }
}
print "  static const char domain_[];\n";
print "};\n";


print <<END if $opt_C;

#endif /* not ${class}_INCLUDED */
END

if ($opt_C) {
    close(OUT);
    unlink("$file_base.C");
    open(OUT, ">$file_base.C");
    chmod 0444, "$file_base.C";
    select(OUT);

    print <<END;
// This file was automatically generated from $def_file by $prog.

#ifdef __GNUG__
#pragma implementation
#endif

#include "config.h"
#include "$class.H"
END
}
print <<END;
const char ${class}::domain_[] = "$class";
END

foreach $i (0 .. $#message) {
    if (defined($message[$i])) {
	print "const MessageType$nargs[$i]$auxloc[$i] ${class}::$tag[$i](";
	print "MessageType::";
	if ($type[$i] eq 'I') {
	    print 'info';
	}
	elsif ($type[$i] eq 'W') {
	    print 'warning';
	}
	elsif ($type[$i] eq 'Q') {
	    print 'quantityError';
	}
	elsif ($type[$i] eq 'X') {
	    print 'idrefError';
	}
	else {
	    print 'error';
	}
	print ", domain_,\n";
	printf "\"%s\",\n", $tag[$i];
	printf "\"%s\"", $message[$i];
	if ($auxloc[$i]) {
	    printf ",\n\"%s\"", $message2[$i];
	}
	print "\n);\n";
    }
}

close(OUT);

sub error {
    die "$def_file:$.: $_[0]\n";
}
