#!/usr/bin/perl

use strict;
use warnings;
use IPC::Open2;
use IPC::Cmd qw[can_run];

can_run('gperf') or die 'No gperf binary found, make sure to have gperf installed!';

print("/******** GENERATED FILE ********/\n");

my $rewritten_input = '';
my $iter = 0;
my $keys = '';
my %key_vals;

# collect keywords and rewrite input file with in lookup keys

while (my $line = <STDIN>) {
	if (!($line =~ s/CSH_LOOKUP\("(.*?)"\)/{}/)) {
		$rewritten_input .= $line;
		next;
	}
	my $key = $1;
	if (exists($key_vals{$key})) {
		$line =~ s/{}/$key_vals{$key}/;
	}
	else {
		$line =~ s/{}/$iter/;
		$keys .= "$key,$iter\n";
		$key_vals{$key} = $iter;
		$iter++;
	}
	$rewritten_input .= $line;
}

# pass collected output to gperf

my ($rd, $wr);
my $pid = open2($rd, $wr, qw(gperf -t -E -l -c -t -I -H __csh_hash -N __csh_lookup_raw));

# gperf header and keys

print { $wr } "struct __csh_hash_lookup { char *name; int num; };\n%%\n";
print { $wr } $keys;

# read gperf output

close($wr);
my $hash_func_code;
{
	local $/ = undef;
	$hash_func_code = <$rd>;
}
close($rd);
waitpid($pid, 0);
exit(1) if $?;

# convert lookup function to static

$hash_func_code =~ s/(^|\s)struct\s+__csh_hash_lookup\s*\*/\nstatic$&/s;

# print combined output

print "#pragma GCC diagnostic push\n";
print "#pragma GCC diagnostic ignored \"-Wmissing-field-initializers\"\n";
print $hash_func_code;
print "#pragma GCC diagnostic pop\n";
# add convenience function
print <<END;
#include "str.h"
static int __csh_lookup(const str *s) {
	if (!s->s)
		return -1;
	struct __csh_hash_lookup *h = __csh_lookup_raw(s->s, s->len);
	if (!h)
		return -1;
	return h->num;
}
END
# adjust diagnostic line numbers and originating file
print $ARGV[0] ? "#line 1 \"$ARGV[0]\"\n" : "#line 1\n";
print $rewritten_input;
