#! /usr/bin/perl -w ################################################################# # create_help.pl -- converts SGML docs to internal psql help # # Copyright (c) 2000-2010, PostgreSQL Global Development Group # # $PostgreSQL: pgsql/src/bin/psql/create_help.pl,v 1.21 2010/01/02 16:57:59 momjian Exp $ ################################################################# # # This script automatically generates the help on SQL in psql from # the SGML docs. So far the format of the docs was consistent # enough that this worked, but this here is by no means an SGML # parser. # # Call: perl create_help.pl docdir sql_help # The name of the header file doesn't matter to this script, but it # sure does matter to the rest of the source. # use strict; my $docdir = $ARGV[0] or die "$0: missing required argument: docdir\n"; my $hfile = $ARGV[1] . '.h' or die "$0: missing required argument: output file\n"; my $cfile = $ARGV[1] . '.c'; my $hfilebasename; if ($hfile =~ m!.*/([^/]+)$!) { $hfilebasename = $1; } else { $hfilebasename = $hfile; } my $define = $hfilebasename; $define =~ tr/a-z/A-Z/; $define =~ s/\W/_/g; opendir(DIR, $docdir) or die "$0: could not open documentation source dir '$docdir': $!\n"; open(HFILE, ">$hfile") or die "$0: could not open output file '$hfile': $!\n"; open(CFILE, ">$cfile") or die "$0: could not open output file '$cfile': $!\n"; print HFILE "/* * *** Do not change this file by hand. It is automatically * *** generated from the DocBook documentation. * * generated by * $^X $0 @ARGV * */ #ifndef $define #define $define #define N_(x) (x) /* gettext noop */ #include \"postgres_fe.h\" #include \"pqexpbuffer.h\" struct _helpStruct { const char *cmd; /* the command name */ const char *help; /* the help associated with it */ void (*syntaxfunc)(PQExpBuffer); /* function that prints the syntax associated with it */ int nl_count; /* number of newlines in syntax (for pager) */ }; "; print CFILE "/* * *** Do not change this file by hand. It is automatically * *** generated from the DocBook documentation. * * generated by * $^X $0 @ARGV * */ #include \"$hfile\" "; my $maxlen = 0; my %entries; foreach my $file (sort readdir DIR) { my (@cmdnames, $cmddesc, $cmdsynopsis); $file =~ /\.sgml$/ or next; open(FILE, "$docdir/$file") or next; my $filecontent = join('', ); close FILE; # Ignore files that are not for SQL language statements $filecontent =~ m!\s*SQL - Language Statements\s*!i or next; # Collect multiple refnames LOOP: { $filecontent =~ m!\G.*?\s*([a-z ]+?)\s*!cgis and push @cmdnames, $1 and redo LOOP; } $filecontent =~ m!\s*(.+?)\s*!is and $cmddesc = $1; $filecontent =~ m!\s*(.+?)\s*!is and $cmdsynopsis = $1; if (@cmdnames && $cmddesc && $cmdsynopsis) { s/\"/\\"/g foreach @cmdnames; $cmddesc =~ s/<[^>]+>//g; $cmddesc =~ s/\s+/ /g; $cmddesc =~ s/\"/\\"/g; my @params = (); my $nl_count = () = $cmdsynopsis =~ /\n/g; $cmdsynopsis =~ m!! and die "$0:$file: null end tag not supported in synopsis\n"; $cmdsynopsis =~ s/%/%%/g; while ($cmdsynopsis =~ m!<(\w+)[^>]*>(.+?)]*>!) { my $match = $2; $match =~ s/<[^>]+>//g; $match =~ s/%%/%/g; push @params, $match; $cmdsynopsis =~ s!<(\w+)[^>]*>.+?]*>!%s!; } $cmdsynopsis =~ s/\r?\n/\\n/g; $cmdsynopsis =~ s/\"/\\"/g; foreach my $cmdname (@cmdnames) { $entries{$cmdname} = { cmddesc => $cmddesc, cmdsynopsis => $cmdsynopsis, params => \@params, nl_count => $nl_count }; $maxlen = ($maxlen >= length $cmdname) ? $maxlen : length $cmdname; } } else { die "$0: parsing file '$file' failed (N='@cmdnames' D='$cmddesc')\n"; } } foreach (sort keys %entries) { my $prefix = "\t"x5 . ' '; my $id = $_; $id =~ s/ /_/g; my $synopsis = "\"$entries{$_}{cmdsynopsis}\""; $synopsis =~ s/\\n/\\n"\n$prefix"/g; my @args = ("buf", $synopsis, map("_(\"$_\")", @{$entries{$_}{params}})); print HFILE "extern void sql_help_$id(PQExpBuffer buf);\n"; print CFILE "void sql_help_$id(PQExpBuffer buf) { \tappendPQExpBuffer(".join(",\n$prefix", @args)."); } "; } print HFILE " static const struct _helpStruct QL_HELP[] = { "; foreach (sort keys %entries) { my $id = $_; $id =~ s/ /_/g; print HFILE " { \"$_\", N_(\"$entries{$_}{cmddesc}\"), sql_help_$id, $entries{$_}{nl_count} }, "; } print HFILE " { NULL, NULL, NULL } /* End of list marker */ }; #define QL_HELP_COUNT ".scalar(keys %entries)." /* number of help items */ #define QL_MAX_CMD_LEN $maxlen /* largest strlen(cmd) */ #endif /* $define */ "; close CFILE; close HFILE; closedir DIR;