#!/usr/bin/perl
#
# Generate pg_stat_log_errcodes.h from errcodes.txt
#
# Produces a static lookup table mapping packed sqlerrcode values to their
# human-readable condition names (e.g. ERRCODE_DIVISION_BY_ZERO -> "division_by_zero").
#

use strict;
use warnings FATAL => 'all';
use Getopt::Long;

my $outfile = '';

GetOptions('outfile=s' => \$outfile) or die "$0: wrong arguments";

open my $errcodes, '<', $ARGV[0]
  or die "$0: could not open input file '$ARGV[0]': $!\n";

my $outfh;
if ($outfile)
{
	open $outfh, '>', $outfile
	  or die "$0: could not open output file '$outfile': $!\n";
}
else
{
	$outfh = *STDOUT;
}

print $outfh "/* autogenerated from errcodes.txt, do not edit */\n\n";
print $outfh "typedef struct PgStatLogErrCode\n";
print $outfh "{\n";
print $outfh "\tint\t\t\tsqlerrcode;\n";
print $outfh "\tconst char *name;\n";
print $outfh "} PgStatLogErrCode;\n\n";
print $outfh "static const PgStatLogErrCode pg_stat_log_errcodes[] = {\n";

while (<$errcodes>)
{
	chomp;
	next if /^#/;
	next if /^\s*$/;
	next if /^Section:/;

	# Parse: sqlstate  E/W/S  ERRCODE_MACRO  [spec_name]
	next unless /^([^\s]{5})\s+[EWS]\s+([^\s]+)(?:\s+([^\s]+))?/;

	my ($sqlstate, $errcode_macro, $spec_name) = ($1, $2, $3);

	# Skip entries without a spec_name
	next unless defined $spec_name && $spec_name ne '';

	print $outfh "\t{$errcode_macro, \"$spec_name\"},\n";
}

print $outfh "\t{0, NULL}\n";
print $outfh "};\n";

close $errcodes;
close $outfh if ($outfile);
