mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-17 19:30:00 +08:00
Replace pgindent shell script with Perl script. Update perltidy
instructions to perltidy Perl files that lack Perl file extensions. pgindent Perl coding by Andrew Dunstan, restructured by me.
This commit is contained in:
parent
4639432597
commit
149ac7d455
@ -1,5 +1,3 @@
|
||||
src/tools/pgindent/README
|
||||
|
||||
pgindent
|
||||
========
|
||||
|
||||
@ -26,9 +24,7 @@ This can format all PostgreSQL *.c and *.h files, but excludes *.y, and
|
||||
|
||||
6) Run pgindent:
|
||||
|
||||
find . -name '*.[ch]' -type f -print | \
|
||||
egrep -v -f src/tools/pgindent/exclude_file_patterns | \
|
||||
xargs -n100 src/tools/pgindent/pgindent src/tools/pgindent/typedefs.list
|
||||
pgindent
|
||||
|
||||
7) Remove any files that generate errors and restore their original
|
||||
versions.
|
||||
@ -46,7 +42,14 @@ This can format all PostgreSQL *.c and *.h files, but excludes *.y, and
|
||||
|
||||
9) Indent the Perl code:
|
||||
|
||||
find . -name \*.pl -o -name \*.pm |
|
||||
(
|
||||
find . -name \*.pl -o -name \*.pm
|
||||
|
||||
find . -type f -exec file {} \; |
|
||||
egrep -i ':.*perl[0-9]*\>' |
|
||||
cut -d: -f1
|
||||
) |
|
||||
sort -u |
|
||||
xargs perltidy --profile=src/tools/pgindent/perltidyrc
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
@ -1,393 +1,549 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/perl
|
||||
|
||||
# src/tools/pgindent/pgindent
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# Known bugs:
|
||||
#
|
||||
# Blank line is added after parentheses; seen as a function definition, no space
|
||||
# after *:
|
||||
# y = (int) x *y;
|
||||
#
|
||||
# Structure/union pointers in function prototypes and definitions have an extra
|
||||
# space after the asterisk:
|
||||
#
|
||||
# void x(struct xxc * a);
|
||||
use Cwd qw(abs_path getcwd);
|
||||
use File::Find;
|
||||
use File::Spec qw(devnull);
|
||||
use File::Temp;
|
||||
use IO::Handle;
|
||||
use Getopt::Long;
|
||||
use Readonly;
|
||||
|
||||
if [ "$#" -lt 2 ]
|
||||
then echo "Usage: $(basename $0) typedefs file [...]" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
# Update for pg_bsd_indent version
|
||||
Readonly my $INDENT_VERSION => "1.1";
|
||||
Readonly my $devnull => File::Spec->devnull;
|
||||
|
||||
TYPEDEFS="$1"
|
||||
shift
|
||||
# Common indent settings
|
||||
my $indent_opts =
|
||||
"-bad -bap -bc -bl -d0 -cdb -nce -nfc1 -di12 -i4 -l79 -lp -nip -npro -bbb";
|
||||
|
||||
[ -z "$INDENT" ] && INDENT=pg_bsd_indent
|
||||
INDENT_VERSION="1.1"
|
||||
# indent-dependant settings
|
||||
my $extra_opts = "";
|
||||
|
||||
trap "rm -f /tmp/$$ /tmp/$$a" 0 1 2 3 15
|
||||
my ($typedefs_file, $code_base, $excludes, $indent, $build);
|
||||
|
||||
# check the environment
|
||||
my %options = (
|
||||
"typedefs=s" => \$typedefs_file,
|
||||
"code-base=s" => \$code_base,
|
||||
"excludes=s" => \$excludes,
|
||||
"indent=s" => \$indent,
|
||||
"build" => \$build,);
|
||||
GetOptions(%options) || die "bad command line";
|
||||
|
||||
entab </dev/null >/dev/null
|
||||
if [ "$?" -ne 0 ]
|
||||
then echo "Go to the src/tools/entab directory and do a 'make' and 'make install'." >&2
|
||||
echo "This will put the 'entab' command in your path." >&2
|
||||
echo "Then run $0 again."
|
||||
exit 1
|
||||
fi
|
||||
$INDENT -? </dev/null >/dev/null 2>&1
|
||||
if [ "$?" -ne 1 ]
|
||||
then echo "You do not appear to have '$INDENT' installed on your system." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "`$INDENT -V`" != "$INDENT $INDENT_VERSION" ]
|
||||
then echo "You do not appear to have $INDENT version $INDENT_VERSION installed on your system." >&2
|
||||
exit 1
|
||||
fi
|
||||
$INDENT -gnu </dev/null >/dev/null 2>&1
|
||||
if [ "$?" -eq 0 ]
|
||||
then echo "You appear to have GNU indent rather than BSD indent." >&2
|
||||
echo "See the pgindent/README file for a description of its problems." >&2
|
||||
EXTRA_OPTS="-cdb -bli0 -npcs -cli4 -sc"
|
||||
else
|
||||
EXTRA_OPTS="-cli1"
|
||||
fi
|
||||
run_build($code_base) if ($build);
|
||||
|
||||
for FILE
|
||||
do
|
||||
cat "$FILE" |
|
||||
# command line option wins, then first non-option arg,
|
||||
# then environment (which is how --build sets it) ,
|
||||
# then locations. based on current dir, then default location
|
||||
$typedefs_file ||= shift if @ARGV && $ARGV[0] !~ /\\.[ch]$/;
|
||||
$typedefs_file ||= $ENV{PGTYPEDEFS};
|
||||
|
||||
# Convert // comments to /* */
|
||||
sed 's;^\([ ]*\)//\(.*\)$;\1/* \2 */;g' |
|
||||
# build mode sets PGINDENT and PGENTAB
|
||||
$indent ||= $ENV{PGINDENT} || $ENV{INDENT} || "pg_bsd_indent";
|
||||
my $entab = $ENV{PGENTAB} || "entab";
|
||||
|
||||
# Mark some comments for special treatment later
|
||||
sed 's;/\* *---;/*---X_X;g' |
|
||||
# no non-option arguments given. so do everything in the current directory
|
||||
$code_base ||= '.' unless @ARGV;
|
||||
|
||||
# 'else' followed by a single-line comment, followed by
|
||||
# a brace on the next line confuses BSD indent, so we push
|
||||
# the comment down to the next line, then later pull it
|
||||
# back up again. Add space before _PGMV or indent will add
|
||||
# it for us.
|
||||
sed 's;\([} ]\)else[ ]*\(/\*\)\(.*\*/\)[ ]*$;\1else\
|
||||
\2 _PGMV\3;g' |
|
||||
# if it's the base of a postgres tree, we will exclude the files
|
||||
# postgres wants excluded
|
||||
$excludes ||= "$code_base/src/tools/pgindent/exclude_file_patterns"
|
||||
if $code_base && -f "$code_base/src/tools/pgindent/exclude_file_patterns";
|
||||
|
||||
# Indent multi-line after-'else' comment so BSD indent will move it properly.
|
||||
# We already moved down single-line comments above. Check for '*' to make
|
||||
# sure we are not in a single-line comment that has other text on the line.
|
||||
sed 's;\([} ]\)else[ ]*\(/\*[^\*]*\)[ ]*$;\1else\
|
||||
\2;g' |
|
||||
detab -t4 -qc |
|
||||
# globals
|
||||
my @files;
|
||||
my $filtered_typedefs_fh;
|
||||
|
||||
# Work around bug where function that defines no local variables misindents
|
||||
# switch() case lines and line after #else. Do not do for struct/enum.
|
||||
awk ' BEGIN {line1 = ""; line2 = ""}
|
||||
{
|
||||
line2 = $0;
|
||||
if (NR >= 2)
|
||||
print line1;
|
||||
if (NR >= 2 &&
|
||||
line2 ~ /^{[ ]*$/ &&
|
||||
line1 !~ /^struct/ &&
|
||||
line1 !~ /^enum/ &&
|
||||
line1 !~ /^typedef/ &&
|
||||
line1 !~ /^extern[ ][ ]*"C"/ &&
|
||||
line1 !~ /=/ &&
|
||||
line1 ~ /\)/)
|
||||
print "int pgindent_func_no_var_fix;";
|
||||
line1 = line2;
|
||||
}
|
||||
END {
|
||||
if (NR >= 1)
|
||||
print line1;
|
||||
}' |
|
||||
|
||||
# Prevent indenting of code in 'extern "C"' blocks.
|
||||
awk ' BEGIN {line1 = ""; line2 = ""; skips = 0}
|
||||
{
|
||||
line2 = $0;
|
||||
if (skips > 0)
|
||||
skips--;
|
||||
if (line1 ~ /^#ifdef[ ]*__cplusplus/ &&
|
||||
line2 ~ /^extern[ ]*"C"[ ]*$/)
|
||||
{
|
||||
print line1;
|
||||
print line2;
|
||||
if (getline && $0 ~ /^{[ ]*$/)
|
||||
print "/* Open extern \"C\" */";
|
||||
else print $0;
|
||||
line2 = "";
|
||||
skips = 2;
|
||||
}
|
||||
else if (line1 ~ /^#ifdef[ ]*__cplusplus/ &&
|
||||
line2 ~ /^}[ ]*$/)
|
||||
{
|
||||
print line1;
|
||||
print "/* Close extern \"C\" */";
|
||||
line2 = "";
|
||||
skips = 2;
|
||||
}
|
||||
else
|
||||
if (skips == 0 && NR >= 2)
|
||||
print line1;
|
||||
line1 = line2;
|
||||
}
|
||||
END {
|
||||
if (NR >= 1 && skips <= 1)
|
||||
print line1;
|
||||
}' |
|
||||
|
||||
# Protect backslashes in DATA().
|
||||
sed 's;^DATA(.*$;/*&*/;' |
|
||||
|
||||
# Protect wrapping in CATALOG().
|
||||
sed 's;^CATALOG(.*$;/*&*/;' >/tmp/$$a
|
||||
|
||||
egrep -v '^(FD_SET|date|interval|timestamp|ANY)$' "$TYPEDEFS" | sed -e '/^$/d' > /tmp/$$b
|
||||
|
||||
# We get the list of typedef's from /src/tools/find_typedef
|
||||
$INDENT -bad -bap -bc -bl -d0 -cdb -nce -nfc1 -di12 -i4 -l79 \
|
||||
-lp -nip -npro -bbb $EXTRA_OPTS -U/tmp/$$b \
|
||||
/tmp/$$a >/tmp/$$ 2>&1
|
||||
|
||||
if [ "$?" -ne 0 -o -s /tmp/$$ ]
|
||||
then echo
|
||||
echo "$FILE"
|
||||
cat /tmp/$$
|
||||
fi
|
||||
cat /tmp/$$a |
|
||||
|
||||
# Restore DATA/CATALOG lines.
|
||||
sed 's;^/\*\(DATA(.*\)\*/$;\1;' |
|
||||
sed 's;^/\*\(CATALOG(.*\)\*/$;\1;' |
|
||||
|
||||
# Remove tabs and retab with four spaces.
|
||||
detab -t8 -qc |
|
||||
entab -t4 -qc |
|
||||
sed 's;^/\* Open extern \"C\" \*/$;{;' |
|
||||
sed 's;^/\* Close extern \"C\" \*/$;};' |
|
||||
sed 's;/\*---X_X;/* ---;g' |
|
||||
|
||||
# Workaround indent bug for 'static'.
|
||||
sed 's;^static[ ][ ]*;static ;g' |
|
||||
|
||||
# Remove too much indenting after closing brace.
|
||||
sed 's;^} [ ]*;} ;' |
|
||||
|
||||
# Indent single-line after-'else' comment by only one tab.
|
||||
sed 's;\([} ]\)else[ ]*\(/\*.*\*/\)[ ]*$;\1else \2;g' |
|
||||
|
||||
# Pull in #endif comments.
|
||||
sed 's;^#endif[ ][ ]*/\*;#endif /*;' |
|
||||
|
||||
# Work around misindenting of function with no variables defined.
|
||||
awk '
|
||||
sub check_indent
|
||||
{
|
||||
system("entab < $devnull");
|
||||
if ($?)
|
||||
{
|
||||
if ($0 ~ /^[ ]*int[ ]*pgindent_func_no_var_fix;/)
|
||||
{
|
||||
if (getline && $0 != "")
|
||||
print $0;
|
||||
}
|
||||
else print $0;
|
||||
}' |
|
||||
print STDERR
|
||||
"Go to the src/tools/entab directory and do 'make' and 'make install'.\n",
|
||||
"This will put the 'entab' command in your path.\n",
|
||||
"Then run $0 again.\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Add space after comments that start on tab stops.
|
||||
sed 's;\([^ ]\)\(/\*.*\*/\)$;\1 \2;' |
|
||||
|
||||
# Move trailing * in function return type.
|
||||
sed 's;^\([A-Za-z_][^ ]*\)[ ][ ]*\*$;\1 *;' |
|
||||
|
||||
# Remove un-needed braces around single statements.
|
||||
# Do not use because it uglifies PG_TRY/PG_CATCH blocks and probably
|
||||
# isn't needed for general use.
|
||||
# awk '
|
||||
# {
|
||||
# line3 = $0;
|
||||
# if (skips > 0)
|
||||
# skips--;
|
||||
# if (line1 ~ / *{$/ &&
|
||||
# line2 ~ / *[^;{}]*;$/ &&
|
||||
# line3 ~ / *}$/)
|
||||
# {
|
||||
# print line2;
|
||||
# line2 = "";
|
||||
# line3 = "";
|
||||
# skips = 3;
|
||||
# }
|
||||
# else
|
||||
# if (skips == 0 && NR >= 3)
|
||||
# print line1;
|
||||
# line1 = line2;
|
||||
# line2 = line3;
|
||||
# }
|
||||
# END {
|
||||
# if (NR >= 2 && skips <= 1)
|
||||
# print line1;
|
||||
# if (NR >= 1 && skips <= 2)
|
||||
# print line2;
|
||||
# }' |
|
||||
|
||||
# Remove blank line between opening brace and block comment.
|
||||
awk '
|
||||
system("$indent -? < $devnull > $devnull 2>&1");
|
||||
if ($? >> 8 != 1)
|
||||
{
|
||||
line3 = $0;
|
||||
if (skips > 0)
|
||||
skips--;
|
||||
if (line1 ~ / *{$/ &&
|
||||
line2 ~ /^$/ &&
|
||||
line3 ~ / *\/[*]$/)
|
||||
{
|
||||
print line1;
|
||||
print line3;
|
||||
line2 = "";
|
||||
line3 = "";
|
||||
skips = 3;
|
||||
}
|
||||
else
|
||||
if (skips == 0 && NR >= 3)
|
||||
print line1;
|
||||
line1 = line2;
|
||||
line2 = line3;
|
||||
}
|
||||
END {
|
||||
if (NR >= 2 && skips <= 1)
|
||||
print line1;
|
||||
if (NR >= 1 && skips <= 2)
|
||||
print line2;
|
||||
}' |
|
||||
print STDERR
|
||||
"You do not appear to have 'indent' installed on your system.\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Pull up single-line comment after 'else' that was pulled down above
|
||||
awk '
|
||||
{
|
||||
if (NR != 1)
|
||||
{
|
||||
if ($0 ~ "/[*] _PGMV")
|
||||
{
|
||||
# remove tag
|
||||
sub(" _PGMV", "", $0);
|
||||
# remove leading whitespace
|
||||
sub("^[ ]*", "", $0);
|
||||
# add comment with single tab prefix
|
||||
print prev_line" "$0;
|
||||
# throw away current line
|
||||
getline;
|
||||
}
|
||||
else
|
||||
print prev_line;
|
||||
}
|
||||
prev_line = $0;
|
||||
}
|
||||
END {
|
||||
if (NR >= 1)
|
||||
print prev_line;
|
||||
}' |
|
||||
|
||||
# Remove trailing blank lines, helps with adding blank before trailing #endif.
|
||||
awk ' BEGIN {blank_lines = 0;}
|
||||
{
|
||||
line1 = $0;
|
||||
if (line1 ~ /^$/)
|
||||
blank_lines++;
|
||||
else
|
||||
{
|
||||
for (; blank_lines > 0; blank_lines--)
|
||||
printf "\n";
|
||||
print line1;
|
||||
}
|
||||
}' |
|
||||
|
||||
# Remove blank line before #else, #elif, and #endif.
|
||||
awk ' BEGIN {line1 = ""; line2 = ""; skips = 0}
|
||||
{
|
||||
line2 = $0;
|
||||
if (skips > 0)
|
||||
skips--;
|
||||
if (line1 ~ /^$/ &&
|
||||
(line2 ~ /^#else/ ||
|
||||
line2 ~ /^#elif/ ||
|
||||
line2 ~ /^#endif/))
|
||||
{
|
||||
print line2;
|
||||
line2 = "";
|
||||
skips = 2;
|
||||
}
|
||||
else
|
||||
if (skips == 0 && NR >= 2)
|
||||
print line1;
|
||||
line1 = line2;
|
||||
}
|
||||
END {
|
||||
if (NR >= 1 && skips <= 1)
|
||||
print line1;
|
||||
}' |
|
||||
|
||||
# Add blank line before #endif if it is the last line in the file.
|
||||
awk ' BEGIN {line1 = ""; line2 = ""}
|
||||
{
|
||||
line2 = $0;
|
||||
if (NR >= 2)
|
||||
print line1;
|
||||
line1 = line2;
|
||||
}
|
||||
END {
|
||||
if (NR >= 1 && line2 ~ /^#endif/)
|
||||
printf "\n";
|
||||
print line1;
|
||||
}' |
|
||||
|
||||
# Move prototype names to the same line as return type. Useful for ctags.
|
||||
# Indent should do this, but it does not. It formats prototypes just
|
||||
# like real functions.
|
||||
awk ' BEGIN {paren_level = 0}
|
||||
if (`$indent -V` !~ m/ $INDENT_VERSION$/)
|
||||
{
|
||||
if ($0 ~ /^[a-zA-Z_][a-zA-Z_0-9]*[^\(]*$/)
|
||||
print STDERR
|
||||
"You do not appear to have $indent version $INDENT_VERSION installed on your system.\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
system("$indent -gnu < $devnull > $devnull 2>&1");
|
||||
if ($? == 0)
|
||||
{
|
||||
print STDERR
|
||||
"You appear to have GNU indent rather than BSD indent.\n",
|
||||
"See the pgindent/README file for a description of its problems.\n";
|
||||
$extra_opts = "-cdb -bli0 -npcs -cli4 -sc";
|
||||
}
|
||||
else
|
||||
{
|
||||
$extra_opts = "-cli1";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub load_typedefs
|
||||
{
|
||||
|
||||
# try fairly hard to find the typedefs file if it's not set
|
||||
|
||||
foreach my $try ('.', 'src/tools/pgindent', '/usr/local/etc')
|
||||
{
|
||||
$typedefs_file ||= "$try/typedefs.list"
|
||||
if (-f "$try/typedefs.list");
|
||||
}
|
||||
|
||||
# try to find typedefs by moving up directory levels
|
||||
my $tdtry = "..";
|
||||
foreach (1 .. 5)
|
||||
{
|
||||
$typedefs_file ||= "$tdtry/src/tools/pgindent/typedefs.list"
|
||||
if (-f "$tdtry/src/tools/pgindent/typedefs.list");
|
||||
$tdtry = "$tdtry/..";
|
||||
}
|
||||
die "no typedefs file" unless $typedefs_file && -f $typedefs_file;
|
||||
|
||||
open(my $typedefs_fh, '<', $typedefs_file)
|
||||
|| die "opening $typedefs_file: $!";
|
||||
my @typedefs = <$typedefs_fh>;
|
||||
close($typedefs_fh);
|
||||
|
||||
# remove certain entries
|
||||
@typedefs =
|
||||
grep { !m/^(FD_SET|date|interval|timestamp|ANY)\n?$/ } @typedefs;
|
||||
|
||||
# write filtered typedefs
|
||||
my $filter_typedefs_fh = new File::Temp(TEMPLATE => "pgtypedefXXXXX");
|
||||
print $filter_typedefs_fh @typedefs;
|
||||
$filter_typedefs_fh->close();
|
||||
|
||||
# temp file remains because we return a file handle reference
|
||||
return $filter_typedefs_fh;
|
||||
}
|
||||
|
||||
|
||||
sub process_exclude
|
||||
{
|
||||
if ($excludes && @files)
|
||||
{
|
||||
open(my $eh, '<', $excludes) || die "opening $excludes";
|
||||
while (my $line = <$eh>)
|
||||
{
|
||||
saved_len = 0;
|
||||
saved_lines[++saved_len] = $0;
|
||||
if ((getline saved_lines[++saved_len]) == 0)
|
||||
print saved_lines[1];
|
||||
else
|
||||
if (saved_lines[saved_len] !~ /^[a-zA-Z_][a-zA-Z_0-9]*\(/ ||
|
||||
saved_lines[saved_len] ~ /^[a-zA-Z_][a-zA-Z_0-9]*\(.*\)$/ ||
|
||||
saved_lines[saved_len] ~ /^[a-zA-Z_][a-zA-Z_0-9]*\(.*\);$/)
|
||||
{
|
||||
print saved_lines[1];
|
||||
print saved_lines[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if ((getline saved_lines[++saved_len]) == 0)
|
||||
break;
|
||||
if (saved_lines[saved_len] ~ /^[^ ]/ ||
|
||||
saved_lines[saved_len] !~ /,$/)
|
||||
break;
|
||||
}
|
||||
for (i=1; i <= saved_len; i++)
|
||||
{
|
||||
if (i == 1 && saved_lines[saved_len] ~ /\);$/)
|
||||
{
|
||||
printf "%s", saved_lines[i];
|
||||
if (substr(saved_lines[i], length(saved_lines[i]),1) != "*")
|
||||
printf " ";
|
||||
}
|
||||
else print saved_lines[i];
|
||||
}
|
||||
}
|
||||
chomp $line;
|
||||
my $rgx;
|
||||
eval " \$rgx = qr!$line!;";
|
||||
@files = grep { $_ !~ /$rgx/ } @files if $rgx;
|
||||
}
|
||||
else print $0;
|
||||
}' |
|
||||
close($eh);
|
||||
}
|
||||
}
|
||||
|
||||
# Fix indenting of typedef caused by __cplusplus in libpq-fe.h.
|
||||
(
|
||||
if echo "$FILE" | grep -q 'libpq-fe.h$'
|
||||
then sed 's/^[ ]*typedef enum/typedef enum/'
|
||||
else cat
|
||||
fi
|
||||
) |
|
||||
# end
|
||||
cat >/tmp/$$ && cat /tmp/$$ >"$FILE"
|
||||
done
|
||||
|
||||
# The 'for' loop makes these backup files useless so delete them
|
||||
rm -f *a.BAK
|
||||
sub read_source
|
||||
{
|
||||
my $source_filename = shift;
|
||||
my $source;
|
||||
|
||||
open(my $src_fd, '<', $source_filename)
|
||||
|| die "opening $source_filename: $!";
|
||||
local ($/) = undef;
|
||||
$source = <$src_fd>;
|
||||
close($src_fd);
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
|
||||
sub write_source
|
||||
{
|
||||
my $source = shift;
|
||||
my $source_filename = shift;
|
||||
|
||||
open(my $src_fh, '>', $source_filename)
|
||||
|| die "opening $source_filename: $!";
|
||||
print $src_fh $source;
|
||||
close($src_fh);
|
||||
}
|
||||
|
||||
|
||||
sub pre_indent
|
||||
{
|
||||
my $source = shift;
|
||||
|
||||
# remove trailing whitespace
|
||||
$source =~ s/\h+$//gm;
|
||||
|
||||
## Comments
|
||||
|
||||
# Convert // comments to /* */
|
||||
$source =~ s!^(\h*)//(.*)$!$1/* $2 */!gm;
|
||||
|
||||
# 'else' followed by a single-line comment, followed by
|
||||
# a brace on the next line confuses BSD indent, so we push
|
||||
# the comment down to the next line, then later pull it
|
||||
# back up again. Add space before _PGMV or indent will add
|
||||
# it for us.
|
||||
# AMD: A symptom of not getting this right is that you see errors like:
|
||||
# FILE: ../../../src/backend/rewrite/rewriteHandler.c
|
||||
# Error@2259:
|
||||
# Stuff missing from end of file
|
||||
$source =~ s!(\}|\h)else\h*(/\*)(.*\*/)\h*$!$1else\n $2 _PGMV$3!gm;
|
||||
|
||||
# Indent multi-line after-'else' comment so BSD indent will move it
|
||||
# properly. We already moved down single-line comments above.
|
||||
# Check for '*' to make sure we are not in a single-line comment that
|
||||
# has other text on the line.
|
||||
$source =~ s!(\}|\h)else\h*(/\*[^*]*)\h*$!$1else\n $2!gm;
|
||||
|
||||
# Mark some comments for special treatment later
|
||||
$source =~ s!/\* +---!/*---X_X!g;
|
||||
|
||||
## Other
|
||||
|
||||
# Work around bug where function that defines no local variables
|
||||
# misindents switch() case lines and line after #else. Do not do
|
||||
# for struct/enum.
|
||||
my @srclines = split(/\n/, $source);
|
||||
foreach my $lno (1 .. $#srclines)
|
||||
{
|
||||
my $l2 = $srclines[$lno];
|
||||
|
||||
# Line is only a single open brace in column 0
|
||||
next unless $l2 =~ /^\{\h*$/;
|
||||
|
||||
# previous line has a closing paren
|
||||
next unless $srclines[ $lno - 1 ] =~ /\)/;
|
||||
|
||||
# previous line was struct, etc.
|
||||
next
|
||||
if $srclines[ $lno - 1 ] =~
|
||||
m!=|^(struct|enum|\h*typedef|extern\h+"C")!;
|
||||
|
||||
$srclines[$lno] = "$l2\nint pgindent_func_no_var_fix;";
|
||||
}
|
||||
$source = join("\n", @srclines) . "\n"; # make sure there's a final \n
|
||||
|
||||
# Prevent indenting of code in 'extern "C"' blocks.
|
||||
# we replace the braces with comments which we'll reverse later
|
||||
my $extern_c_start = '/* Open extern "C" */';
|
||||
my $extern_c_stop = '/* Close extern "C" */';
|
||||
$source =~
|
||||
s!(^#ifdef\h+__cplusplus.*\nextern\h+"C"\h*\n)\{\h*$!$1$extern_c_start!gm;
|
||||
$source =~ s!(^#ifdef\h+__cplusplus.*\n)\}\h*$!$1$extern_c_stop!gm;
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
|
||||
sub post_indent
|
||||
{
|
||||
my $source = shift;
|
||||
my $source_filename = shift;
|
||||
|
||||
# put back braces for extern "C"
|
||||
$source =~ s!^/\* Open extern "C" \*/$!{!gm;
|
||||
$source =~ s!^/\* Close extern "C" \*/$!}!gm;
|
||||
|
||||
## Comments
|
||||
|
||||
# remove special comment marker
|
||||
$source =~ s!/\*---X_X!/* ---!g;
|
||||
|
||||
# Pull up single-line comment after 'else' that was pulled down above
|
||||
$source =~ s!else\n\h+/\* _PGMV!else\t/*!g;
|
||||
|
||||
# Indent single-line after-'else' comment by only one tab.
|
||||
$source =~ s!(\}|\h)else\h+(/\*.*\*/)\h*$!$1else\t$2!gm;
|
||||
|
||||
# Add tab before comments with no whitespace before them (on a tab stop)
|
||||
$source =~ s!(\S)(/\*.*\*/)$!$1\t$2!gm;
|
||||
|
||||
# Remove blank line between opening brace and block comment.
|
||||
$source =~ s!(\t*\{\n)\n(\h+/\*)$!$1$2!gm;
|
||||
|
||||
# cpp conditionals
|
||||
|
||||
# Reduce whitespace between #endif and comments to one tab
|
||||
$source =~ s!^\#endif\h+/\*!#endif /*!gm;
|
||||
|
||||
# Remove blank line(s) before #else, #elif, and #endif
|
||||
$source =~ s!\n\n+(\#else|\#elif|\#endif)!\n$1!g;
|
||||
|
||||
# Add blank line before #endif if it is the last line in the file
|
||||
$source =~ s!\n(#endif.*)\n\z!\n\n$1\n!;
|
||||
|
||||
## Functions
|
||||
|
||||
# Work around misindenting of function with no variables defined.
|
||||
$source =~ s!^\h*int\h+pgindent_func_no_var_fix;\h*\n{1,2}!!gm;
|
||||
|
||||
# Use a single space before '*' in function return types
|
||||
$source =~ s!^([A-Za-z_]\S*)\h+\*$!$1 *!gm;
|
||||
|
||||
# Move prototype names to the same line as return type. Useful
|
||||
# for ctags. Indent should do this, but it does not. It formats
|
||||
# prototypes just like real functions.
|
||||
|
||||
my $ident = qr/[a-zA-Z_][a-zA-Z_0-9]*/;
|
||||
my $comment = qr!/\*.*\*/!;
|
||||
|
||||
$source =~ s!
|
||||
(\n$ident[^(\n]*)\n # e.g. static void
|
||||
(
|
||||
$ident\(\n? # func_name(
|
||||
(.*,(\h*$comment)?\n)* # args b4 final ln
|
||||
.*\);(\h*$comment)?$ # final line
|
||||
)
|
||||
!$1 . (substr($1,-1,1) eq '*' ? '' : ' ') . $2!gmxe;
|
||||
|
||||
## Other
|
||||
|
||||
# Remove too much indenting after closing brace.
|
||||
$source =~ s!^\}\t\h+!}\t!gm;
|
||||
|
||||
# Workaround indent bug that places excessive space before 'static'.
|
||||
$source =~ s!^static\h+!static !gm;
|
||||
|
||||
# Remove leading whitespace from typedefs
|
||||
$source =~ s!^\h+typedef enum!typedef enum!gm
|
||||
if $source_filename =~ 'libpq-(fe|events).h$';
|
||||
|
||||
# Remove trailing blank lines
|
||||
$source =~ s!\n+\z!\n!;
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
|
||||
sub run_indent
|
||||
{
|
||||
my $source = shift;
|
||||
my $error_message = shift;
|
||||
|
||||
my $cmd =
|
||||
"$indent $indent_opts $extra_opts -U" . $filtered_typedefs_fh->filename;
|
||||
|
||||
my $tmp_fh = new File::Temp(TEMPLATE => "pgsrcXXXXX");
|
||||
my $filename = $tmp_fh->filename;
|
||||
print $tmp_fh $source;
|
||||
$tmp_fh->close();
|
||||
|
||||
$$error_message = `$cmd $filename 2>&1`;
|
||||
|
||||
return "" if ($? || length($$error_message) > 0);
|
||||
|
||||
unlink "$filename.BAK";
|
||||
|
||||
open(my $src_out, '<', $filename);
|
||||
local ($/) = undef;
|
||||
$source = <$src_out>;
|
||||
close($src_out);
|
||||
|
||||
return $source;
|
||||
|
||||
}
|
||||
|
||||
# XXX Ideally we'd implement entab/detab in pure perl.
|
||||
|
||||
sub detab
|
||||
{
|
||||
my $source = shift;
|
||||
|
||||
my $tmp_fh = new File::Temp(TEMPLATE => "pgdetXXXXX");
|
||||
print $tmp_fh $source;
|
||||
$tmp_fh->close();
|
||||
|
||||
open(my $entab, '-|', "$entab -d -t4 -qc " . $tmp_fh->filename);
|
||||
local ($/) = undef;
|
||||
$source = <$entab>;
|
||||
close($entab);
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
|
||||
sub entab
|
||||
{
|
||||
my $source = shift;
|
||||
|
||||
my $tmp_fh = new File::Temp(TEMPLATE => "pgentXXXXX");
|
||||
print $tmp_fh $source;
|
||||
$tmp_fh->close();
|
||||
|
||||
open(my $entab, '-|',
|
||||
"$entab -d -t8 -qc " . $tmp_fh->filename . " | $entab -t4 -qc");
|
||||
local ($/) = undef;
|
||||
$source = <$entab>;
|
||||
close($entab);
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
|
||||
# for development diagnostics
|
||||
sub diff
|
||||
{
|
||||
my $pre = shift;
|
||||
my $post = shift;
|
||||
my $flags = shift || "";
|
||||
|
||||
print STDERR "running diff\n";
|
||||
|
||||
my $pre_fh = new File::Temp(TEMPLATE => "pgdiffbXXXXX");
|
||||
my $post_fh = new File::Temp(TEMPLATE => "pgdiffaXXXXX");
|
||||
|
||||
print $pre_fh $pre;
|
||||
print $post_fh $post;
|
||||
|
||||
$pre_fh->close();
|
||||
$post_fh->close();
|
||||
|
||||
system( "diff $flags "
|
||||
. $pre_fh->filename . " "
|
||||
. $post_fh->filename
|
||||
. " >&2");
|
||||
}
|
||||
|
||||
|
||||
sub run_build
|
||||
{
|
||||
eval "use LWP::Simple;";
|
||||
|
||||
my $code_base = shift || '.';
|
||||
my $save_dir = getcwd();
|
||||
|
||||
# look for the code root
|
||||
foreach (1 .. 5)
|
||||
{
|
||||
last if -d "$code_base/src/tools/pgindent";
|
||||
$code_base = "$code_base/..";
|
||||
}
|
||||
|
||||
die "no src/tools/pgindent directory in $code_base"
|
||||
unless -d "$code_base/src/tools/pgindent";
|
||||
|
||||
chdir "$code_base/src/tools/pgindent";
|
||||
|
||||
my $rv = getstore("http://buildfarm.postgresql.org/cgi-bin/typedefs.pl",
|
||||
"tmp_typedefs.list");
|
||||
|
||||
die "fetching typedefs.list" unless is_success($rv);
|
||||
|
||||
$ENV{PGTYPEDEFS} = abs_path('tmp_typedefs.list');
|
||||
|
||||
$rv =
|
||||
getstore("ftp://ftp.postgresql.org/pub/dev/indent.netbsd.patched.tgz",
|
||||
"indent.netbsd.patched.tgz");
|
||||
|
||||
die "fetching indent.netbsd.patched.tgz" unless is_success($rv);
|
||||
|
||||
# XXX add error checking here
|
||||
|
||||
mkdir "bsdindent";
|
||||
chdir "bsdindent";
|
||||
system("tar -z -xf ../indent.netbsd.patched.tgz");
|
||||
system("make > $devnull 2>&1");
|
||||
|
||||
$ENV{PGINDENT} = abs_path('indent');
|
||||
|
||||
chdir "../../entab";
|
||||
|
||||
system("make > $devnull 2>&1");
|
||||
|
||||
$ENV{PGENTAB} = abs_path('entab');
|
||||
|
||||
chdir $save_dir;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub build_clean
|
||||
{
|
||||
my $code_base = shift || '.';
|
||||
|
||||
# look for the code root
|
||||
foreach (1 .. 5)
|
||||
{
|
||||
last if -d "$code_base/src/tools/pgindent";
|
||||
$code_base = "$code_base/..";
|
||||
}
|
||||
|
||||
die "no src/tools/pgindent directory in $code_base"
|
||||
unless -d "$code_base/src/tools/pgindent";
|
||||
|
||||
chdir "$code_base";
|
||||
|
||||
system("rm -rf src/tools/pgindent/bsdindent");
|
||||
system("git clean -q -f src/tools/entab src/tools/pgindent");
|
||||
}
|
||||
|
||||
|
||||
# main
|
||||
|
||||
# get the list of files under code base, if it's set
|
||||
File::Find::find(
|
||||
{ wanted => sub {
|
||||
my ($dev, $ino, $mode, $nlink, $uid, $gid);
|
||||
(($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_))
|
||||
&& -f _
|
||||
&& /^.*\.[ch]\z/s
|
||||
&& push(@files, $File::Find::name);
|
||||
}
|
||||
},
|
||||
$code_base) if $code_base;
|
||||
|
||||
process_exclude();
|
||||
|
||||
$filtered_typedefs_fh = load_typedefs();
|
||||
|
||||
check_indent();
|
||||
|
||||
# make sure we process any non-option arguments.
|
||||
push(@files, @ARGV);
|
||||
|
||||
foreach my $source_filename (@files)
|
||||
{
|
||||
my $source = read_source($source_filename);
|
||||
my $error_message = '';
|
||||
|
||||
$source = pre_indent($source);
|
||||
|
||||
# Protect backslashes in DATA() and wrapping in CATALOG()
|
||||
|
||||
$source = detab($source);
|
||||
$source =~ s!^((DATA|CATALOG)\(.*)$!/*$1*/!gm;
|
||||
|
||||
$source = run_indent($source, \$error_message);
|
||||
if ($source eq "")
|
||||
{
|
||||
print STDERR "Failure in $source_filename: " . $error_message . "\n";
|
||||
next;
|
||||
}
|
||||
|
||||
# Restore DATA/CATALOG lines; must be done here so tab alignment is preserved
|
||||
$source =~ s!^/\*((DATA|CATALOG)\(.*)\*/$!$1!gm;
|
||||
$source = entab($source);
|
||||
|
||||
$source = post_indent($source, $source_filename);
|
||||
|
||||
write_source($source, $source_filename);
|
||||
}
|
||||
|
||||
build_clean($code_base) if $build;
|
||||
|
45
src/tools/pgindent/pgindent.man
Normal file
45
src/tools/pgindent/pgindent.man
Normal file
@ -0,0 +1,45 @@
|
||||
pgindent will indent .c and .h files according to the coding standards of
|
||||
the PostgreSQL project. It needs several things to run, and tries to locate
|
||||
or build them if possible. They can also be specified via command line switches
|
||||
or the environment.
|
||||
|
||||
In its simplest form, if all the required objects are installed, simply run
|
||||
it without any parameters at the top of the source tree you want to process.
|
||||
|
||||
pgindent
|
||||
|
||||
If you don't have all the requirements installed, pgindent will fetch and build
|
||||
them for you, if you're in a PostgreSQL source tree:
|
||||
|
||||
|
||||
pgindent --build
|
||||
|
||||
If your indent program is not installed in your path, you can specify it
|
||||
by setting the environment variable INDENT, or PGINDENT, or by giving the
|
||||
command line option --indent:
|
||||
|
||||
pgindent --indent=/opt/extras/bsdindent
|
||||
|
||||
Similarly, the entab program can be specified using the PGENTAB environment
|
||||
variable, or using the --entab command line option.
|
||||
|
||||
pgindent also needs a file containing a list of typedefs. This can be
|
||||
specified using the PGTYPEDEFS environment variable, or via the command line
|
||||
--typedefs option. If neither is used, it will look for it within the
|
||||
current source tree, or in /usr/local/etc/typedefs.list.
|
||||
|
||||
If you want to indent a source tree other than the current working directory,
|
||||
you can specify it via the --code-base command line option.
|
||||
|
||||
We don't want to indent certain files in the PostgreSQL source. pgindent
|
||||
will honor a file containing a list of patterns of files to avoid. This
|
||||
file can be specified using the --excludes command line option. If indenting
|
||||
a PostgreSQL source tree, this option isn't necessary, as it will find the file
|
||||
src/tools/pgindent/exclude_file_patterns.
|
||||
|
||||
Any non-option arguments are taken as the names of files to be indented. In this
|
||||
case only these files will be changed, and nothing else will be touched. If the
|
||||
first non-option argument is not a .c or .h file, it is treated as the name
|
||||
of a typedefs file for legacy reasons, but this use is deprecated - use the
|
||||
--typedefs option instead.
|
||||
|
Loading…
Reference in New Issue
Block a user