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:
Bruce Momjian 2012-08-04 12:41:21 -04:00
parent 4639432597
commit 149ac7d455
3 changed files with 579 additions and 375 deletions

View File

@ -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
---------------------------------------------------------------------------

View File

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

View 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.