#!/usr/bin/perl
#----------------------------------------------------------------------
#
# Generate wait events support files from waiteventnames.txt:
# - waiteventnames.h
# - waiteventnames.c
# - waiteventnames.sgml
#
# Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# src/backend/utils/activity/generate-waiteventnames.pl
#
#----------------------------------------------------------------------

use strict;
use warnings;
use Getopt::Long;

my $output_path = '.';

my $continue    = "\n";
my %hashwe;
my $waitclass;
my @wait_classes = ("PG_WAIT_ACTIVITY", "PG_WAIT_CLIENT", "PG_WAIT_IPC", "PG_WAIT_TIMEOUT", "PG_WAIT_IO");

GetOptions(
	'outdir:s'       => \$output_path);

open my $waiteventnames, '<', $ARGV[0] or die;

# Include PID in suffix in case parallel make runs this multiple times.
my $htmp = "$output_path/waiteventnames.h.tmp$$";
my $ctmp = "$output_path/waiteventnames.c.tmp$$";
my $stmp = "$output_path/waiteventnames.s.tmp$$";
open my $h, '>', $htmp or die "Could not open $htmp: $!";
open my $c, '>', $ctmp or die "Could not open $ctmp: $!";
open my $s, '>', $stmp or die "Could not open $stmp: $!";

my $header_comment =
  '/*-------------------------------------------------------------------------
 *
 * %s
 *    Generated wait events infrastructure code
 *
 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * NOTES
 *  ******************************
 *  *** DO NOT EDIT THIS FILE! ***
 *  ******************************
 *
 *  It has been GENERATED by src/backend/utils/activity/generate-waiteventnames.pl
 *
 *-------------------------------------------------------------------------
 */
';

printf $h $header_comment, 'waiteventnames.h';
printf $h "#ifndef WAITEVENTNAMES_H\n";
printf $h "#define WAITEVENTNAMES_H\n\n";
printf $h "#include \"utils/wait_event.h\"\n\n";

printf $c $header_comment, 'waiteventnames.c';

# Read the input file and populate the hash table
while (<$waiteventnames>)
{
	chomp;

	# Skip comments
	next if /^#/;
	next if /^\s*$/;

	die "unable to parse waiteventnames.txt"
	  unless /^(\w+)\t+(\w+)\t+("\w+")\t+("\w.*\.")$/;

	(my $waitclassname, my $waiteventenumname, my $waiteventdescription, my $waitevendocsentence) = ($1, $2, $3, $4);

	my @waiteventlist = [$waiteventenumname, $waiteventdescription, $waitevendocsentence];
	my $trimmedwaiteventname = $waiteventenumname;
	$trimmedwaiteventname =~ s/^WAIT_EVENT_//;
	die "wait event names must start with 'WAIT_EVENT_'" if $trimmedwaiteventname eq $waiteventenumname;
	$continue    = ",\n";
	push(@{ $hashwe{$waitclassname} }, @waiteventlist);
}

# Generate the output files
foreach $waitclass (sort keys %hashwe) {
	my $last = $waitclass;
	$last =~ s/^WaitEvent//;
	my $lastuc = uc $last;
	my $lastlc = lc $last;
	my $firstpass = 1;
	my $pg_wait_class;

	printf $h "typedef enum\n{\n";

	printf $c "static const char *\npgstat_get_wait_$lastlc($waitclass w)\n{\n";
	printf $c "\tconst char *event_name = \"unknown wait event\";\n\n";
	printf $c "\tswitch (w)\n\t{\n";

	printf $s "  <table id=\"wait-event-%s-table\">\n", $lastlc;
	printf $s "   <title>Wait Events of Type <literal>%s</literal></title>\n", ucfirst($lastlc);
	printf $s "   <tgroup cols=\"2\">\n";
	printf $s "    <thead>\n";
	printf $s "     <row>\n";
	printf $s "      <entry><literal>Activity</literal> Wait Event</entry>\n";
	printf $s "      <entry>Description</entry>\n";
    printf $s "     </row>\n";
	printf $s "    </thead>\n\n";
	printf $s "    <tbody>\n";

	foreach my $wev (@{$hashwe{$waitclass}}) {
		if ($firstpass) {
			$pg_wait_class = "PG_WAIT_".$lastuc;
			die "waitclass $pg_wait_class does not exist" unless grep( /^$pg_wait_class$/, @wait_classes );
			printf $h "\t%s = %s", $wev->[0], $pg_wait_class;
			$continue = ",\n";
		} else {
			printf $h "%s\t%s", $continue, $wev->[0];
			$continue = ",\n";
		}
		$firstpass = 0;

		printf $c "\t\t case %s:\n", $wev->[0];
		printf $c "\t\t\t event_name = %s;\n\t\t\t break;\n", $wev->[1];

		printf $s "     <row>\n";
		printf $s "      <entry><literal>%s</literal></entry>\n", substr $wev->[1], 1, -1;
		printf $s "      <entry>%s</entry>\n", substr $wev->[2], 1, -1;
		printf $s "     </row>\n";
	}

	printf $h "\n} $waitclass;\n\n";

	printf $c "\t\t\t /* no default case, so that compiler will warn */\n";
	printf $c "\t}\n\n";
	printf $c "\treturn event_name;\n";
	printf $c "\n}\n";

	printf $s "    </tbody>\n";
	printf $s "   </tgroup>\n";
	printf $s "  </table>\n";
}

printf $h "#endif                          /* WAITEVENTNAMES_H */";
close $h;
close $c;
close $s;

rename($htmp, "$output_path/waiteventnames.h") || die "rename: $htmp to $output_path/waiteventnames.h: $!";
rename($ctmp, "$output_path/waiteventnames.c") || die "rename: $ctmp: $!";
rename($stmp, "$output_path/waiteventnames.sgml") || die "rename: $ctmp: $!";

close $waiteventnames;
