#!/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 =
  '/*-------------------------------------------------------------------------
 *
 * waiteventnames.%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
 *
 *-------------------------------------------------------------------------
 */';

my $h_header_comment = sprintf $header_comment, 'h';
my $c_header_comment = sprintf $header_comment, 'c';


print $h <<"EOF";
$h_header_comment
#ifndef WAITEVENTNAMES_H
#define WAITEVENTNAMES_H

#include "utils/wait_event.h"

EOF

print $c <<"EOF";
$c_header_comment
EOF

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

	print $h <<"EOF";
typedef enum
{
EOF

	print $c <<"EOF";
static const char *
pgstat_get_wait_$lastlc($waitclass w)
{
	const char *event_name = "unknown wait event";

	switch (w)
	{
EOF

	my $ucfirst_lastlc = ucfirst($lastlc);
	print $s <<"EOF";
  <table id="wait-event-$ucfirst_lastlc-table">
   <title>Wait Events of Type <literal>$ucfirst_lastlc</literal></title>
   <tgroup cols="2">
    <thead>
     <row>
      <entry><literal>Activity</literal> Wait Event</entry>
      <entry>Description</entry>
     </row>
    </thead>

    <tbody>
EOF

	foreach my $wev (@{$hashwe{$waitclass}}) {

		my $wev0 = $wev->[0];
		my $wev1 = $wev->[1];
		my $wev1_substr = substr $wev->[1], 1, -1;
		my $wev2_substr = substr $wev->[2], 1, -1;

		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;

		print $c <<"EOF";
		 case $wev0:
			 event_name = $wev1;
			 break;
EOF

		print $s <<"EOF";
     <row>
      <entry><literal>$wev1_substr</literal></entry>
      <entry>$wev2_substr</entry>
     </row>
EOF
	}

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

	print $c <<"EOF";
			 /* no default case, so that compiler will warn */
	}

	return event_name;

}
EOF

print $s <<"EOF";
    </tbody>
   </tgroup>
  </table>
EOF
}

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;
