+/*-------------------------------------------------------------------------
+ *
+ * tab-complete.c
+ * Preprocessed tab-completion code.
+ *
+ * Portions Copyright (c) 1996-2024, 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/bin/psql/gen_tabcomplete.pl
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#define SWITCH_CONVERSION_APPLIED
+
+#line 1 "tab-complete.in.c"
+EOM
+
+# Scan input file until we find the data-replacement label line.
+# Dump what we scan directly into the output file.
+while (<$infh>)
+{
+ chomp;
+ last if m|^\s*/\* Insert tab-completion pattern data here\. \*/\s*$|;
+ print $outfh "$_\n";
+}
+
+# $table_data collects what we will substitute for the "pattern data" line.
+my $table_data = '';
+# $output_code collects code that we can't emit till after $table_data.
+my $output_code = '';
+# last case label assigned
+my $last_case_label = 0;
+
+# We emit #line directives to keep the output file's line numbering in sync
+# with the line numbering of the original, to simplify compiler error message
+# reading and debugging.
+my $next_line_no = $. + 1;
+$output_code .= "#line ${next_line_no} \"tab-complete.in.c\"\n";
+
+# Scan until we find the BEGIN GEN_TABCOMPLETE line.
+# Add the scanned code to $output_code verbatim.
+while (<$infh>)
+{
+ chomp;
+ last if m|^\s*/\* BEGIN GEN_TABCOMPLETE \*/\s*$|;
+ $output_code .= $_ . "\n";
+}
+
+# Emit the switch-starting lines.
+$output_code .= "\tswitch (pattern_id)\n";
+$output_code .= "\t{\n";
+
+# Keep line numbering in sync.
+$next_line_no = $. + 1;
+$output_code .= "#line ${next_line_no} \"tab-complete.in.c\"\n";
+
+# Scan input file, collecting outer-level else-if conditions
+# to pass to process_else_if.
+# Lines that aren't else-if conditions go to $output_code verbatim.
+# True if we're handling a multiline else-if condition
+my $in_else_if = 0;
+# The accumulated line
+my $else_if_line;
+my $else_if_lineno;
+
+while (<$infh>)
+{
+ chomp;
+ last if m|^\s*/\* END GEN_TABCOMPLETE \*/\s*$|;
+ if ($in_else_if)
+ {
+ my $rest = $_;
+ # collapse leading whitespace
+ $rest =~ s/^\s+//;
+ $else_if_line .= ' ' . $rest;
+ # Double right paren is currently sufficient to detect completion
+ if ($else_if_line =~ m/\)\)$/)
+ {
+ process_else_if($else_if_line, $else_if_lineno, $.);
+ $in_else_if = 0;
+ }
+ }
+ elsif (m/^\telse if \(/)
+ {
+ $else_if_line = $_;
+ $else_if_lineno = $.;
+ # Double right paren is currently sufficient to detect completion
+ if ($else_if_line =~ m/\)\)$/)
+ {
+ process_else_if($else_if_line, $else_if_lineno, $.);
+ }
+ else
+ {
+ $in_else_if = 1;
+ }
+ }
+ else
+ {
+ $output_code .= $_ . "\n";
+ }
+}
+
+die "unfinished else-if" if $in_else_if;
+
+# Emit the switch-ending lines.
+$output_code .= "\tbreak;\n";
+$output_code .= "\tdefault:\n";
+$output_code .= "\t\tAssert(false);\n";
+$output_code .= "\t\tbreak;\n";
+$output_code .= "\t}\n";
+
+# Keep line numbering in sync.
+$next_line_no = $. + 1;
+$output_code .= "#line ${next_line_no} \"tab-complete.in.c\"\n";
+
+# Scan the rest, adding it to $output_code verbatim.
+while (<$infh>)
+{
+ chomp;
+ $output_code .= $_ . "\n";
+}
+
+# Dump out the table data.
+print $outfh $table_data;
+
+# Dump out the modified code, and we're done!
+print $outfh $output_code;
+
+close($infh);
+close($outfh);
+
+# Disassemble an else-if condition.
+# Add the generated table-contents macro(s) to $table_data,
+# and add the replacement case label(s) to $output_code.
+sub process_else_if
+{
+ my ($else_if_line, $else_if_lineno, $end_lineno) = @_;
+
+ # Strip the initial "else if (", which we know is there
+ $else_if_line =~ s/^\telse if \(//;
+
+ # Handle OR'd conditions
+ my $isfirst = 1;
+ while ($else_if_line =~
+ s/^(Head|Tail|)Matches(CS|)\((("[^"]*"|MatchAnyExcept\("[^"]*"\)|[A-Za-z,\s])+)\)\s*\|\|\s*//
+ )
+ {
+ my $typ = $1;
+ my $cs = $2;
+ my $args = $3;
+ process_match($typ, $cs, $args, $else_if_lineno, $isfirst);
+ $isfirst = 0;
+ }
+
+ # Check for AND'd condition
+ if ($else_if_line =~
+ s/^(Head|Tail|)Matches(CS|)\((("[^"]*"|MatchAnyExcept\("[^"]*"\)|[A-Za-z,\s])+)\)\s*&&\s*//
+ )
+ {
+ my $typ = $1;
+ my $cs = $2;
+ my $args = $3;
+ warn
+ "could not process OR/ANDed if condition at line $else_if_lineno\n"
+ if !$isfirst;
+ process_match($typ, $cs, $args, $else_if_lineno, $isfirst);
+ $isfirst = 0;
+ # approximate line positioning of AND'd condition
+ $output_code .= "#line ${end_lineno} \"tab-complete.in.c\"\n";
+ $output_code .= "\tif ($else_if_line\n";
+ }
+ elsif ($else_if_line =~
+ s/^(Head|Tail|)Matches(CS|)\((("[^"]*"|MatchAnyExcept\("[^"]*"\)|[A-Za-z,\s])+)\)\)$//
+ )
+ {
+ my $typ = $1;
+ my $cs = $2;
+ my $args = $3;
+ process_match($typ, $cs, $args, $else_if_lineno, $isfirst);
+ $isfirst = 0;
+ }
+ else
+ {
+ warn
+ "could not process if condition at line $else_if_lineno: the rest looks like $else_if_line\n";
+ $output_code .= "\telse if ($else_if_line\n";
+ }
+
+ # Keep line numbering in sync.
+ if ($end_lineno != $else_if_lineno)
+ {
+ my $next_lineno = $end_lineno + 1;
+ $output_code .= "#line ${next_lineno} \"tab-complete.in.c\"\n";
+ }
+}
+
+sub process_match
+{
+ my ($typ, $cs, $args, $lineno, $isfirst) = @_;
+
+ # Assign a new case label only for the first pattern in an OR group.
+ if ($isfirst)
+ {
+ $last_case_label++;
+
+ # We intentionally keep the "break;" and the "case" on one line, so
+ # that they have the same line number as the original "else if"'s
+ # first line. This avoids misleading displays in, e.g., lcov.
+ $output_code .= "\t";
+ $output_code .= "break; " if $last_case_label > 1;
+ $output_code .= "case $last_case_label:\n";
+ }
+
+ $table_data .=
+ "\tTCPAT(${last_case_label}, ${typ}Match${cs}, ${args}),\n";
+}
+
+
+sub usage
+{
+ die <
+Usage: gen_tabcomplete.pl [--outfile/-o
] input_file
+ --outfile Output file (default is stdout)
+
+gen_tabcomplete.pl transforms tab-complete.in.c to tab-complete.c.
+EOM
+}
'prompt.c',
'startup.c',
'stringutils.c',
- 'tab-complete.c',
'variables.c',
)
generated_sources += psqlscanslash
psql_sources += psqlscanslash
+tabcomplete = custom_target('tabcomplete',
+ input: 'tab-complete.in.c',
+ output: 'tab-complete.c',
+ command: [
+ perl, files('gen_tabcomplete.pl'), files('tab-complete.in.c'),
+ '--outfile', '@OUTPUT@', '@INPUT@',
+ ],
+)
+generated_sources += tabcomplete
+psql_sources += tabcomplete
+
sql_help = custom_target('psql_help',
output: ['sql_help.c', 'sql_help.h'],
depfile: 'sql_help.dep',
*
* Copyright (c) 2000-2024, PostgreSQL Global Development Group
*
- * src/bin/psql/tab-complete.c
+ * src/bin/psql/tab-complete.in.c
*
* Note: this will compile and work as-is if SWITCH_CONVERSION_APPLIED
* is not defined. However, the expected usage is that it's first run