mirror of https://github.com/postgres/postgres
instructions to perltidy Perl files that lack Perl file extensions. pgindent Perl coding by Andrew Dunstan, restructured by me.pull/3/head
parent
4639432597
commit
149ac7d455
@ -1,393 +1,549 @@ |
||||
#!/bin/sh |
||||
|
||||
# src/tools/pgindent/pgindent |
||||
|
||||
# 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); |
||||
|
||||
if [ "$#" -lt 2 ] |
||||
then echo "Usage: $(basename $0) typedefs file [...]" 1>&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
TYPEDEFS="$1" |
||||
shift |
||||
|
||||
[ -z "$INDENT" ] && INDENT=pg_bsd_indent |
||||
INDENT_VERSION="1.1" |
||||
|
||||
trap "rm -f /tmp/$$ /tmp/$$a" 0 1 2 3 15 |
||||
|
||||
# check the environment |
||||
|
||||
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 |
||||
|
||||
for FILE |
||||
do |
||||
cat "$FILE" | |
||||
|
||||
# Convert // comments to /* */ |
||||
sed 's;^\([ ]*\)//\(.*\)$;\1/* \2 */;g' | |
||||
|
||||
# Mark some comments for special treatment later |
||||
sed 's;/\* *---;/*---X_X;g' | |
||||
|
||||
# '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' | |
||||
|
||||
# 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 | |
||||
|
||||
# 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; |
||||
}' | |
||||
#!/usr/bin/perl |
||||
|
||||
# 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; |
||||
}' | |
||||
use strict; |
||||
use warnings; |
||||
|
||||
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; |
||||
|
||||
# Protect backslashes in DATA(). |
||||
sed 's;^DATA(.*$;/*&*/;' | |
||||
# Update for pg_bsd_indent version |
||||
Readonly my $INDENT_VERSION => "1.1"; |
||||
Readonly my $devnull => File::Spec->devnull; |
||||
|
||||
# Protect wrapping in CATALOG(). |
||||
sed 's;^CATALOG(.*$;/*&*/;' >/tmp/$$a |
||||
# Common indent settings |
||||
my $indent_opts = |
||||
"-bad -bap -bc -bl -d0 -cdb -nce -nfc1 -di12 -i4 -l79 -lp -nip -npro -bbb"; |
||||
|
||||
egrep -v '^(FD_SET|date|interval|timestamp|ANY)$' "$TYPEDEFS" | sed -e '/^$/d' > /tmp/$$b |
||||
# indent-dependant settings |
||||
my $extra_opts = ""; |
||||
|
||||
# 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 |
||||
my ($typedefs_file, $code_base, $excludes, $indent, $build); |
||||
|
||||
if [ "$?" -ne 0 -o -s /tmp/$$ ] |
||||
then echo |
||||
echo "$FILE" |
||||
cat /tmp/$$ |
||||
fi |
||||
cat /tmp/$$a | |
||||
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"; |
||||
|
||||
# Restore DATA/CATALOG lines. |
||||
sed 's;^/\*\(DATA(.*\)\*/$;\1;' | |
||||
sed 's;^/\*\(CATALOG(.*\)\*/$;\1;' | |
||||
run_build($code_base) if ($build); |
||||
|
||||
# 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' | |
||||
# 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}; |
||||
|
||||
# Workaround indent bug for 'static'. |
||||
sed 's;^static[ ][ ]*;static ;g' | |
||||
# build mode sets PGINDENT and PGENTAB |
||||
$indent ||= $ENV{PGINDENT} || $ENV{INDENT} || "pg_bsd_indent"; |
||||
my $entab = $ENV{PGENTAB} || "entab"; |
||||
|
||||
# Remove too much indenting after closing brace. |
||||
sed 's;^} [ ]*;} ;' | |
||||
# no non-option arguments given. so do everything in the current directory |
||||
$code_base ||= '.' unless @ARGV; |
||||
|
||||
# Indent single-line after-'else' comment by only one tab. |
||||
sed 's;\([} ]\)else[ ]*\(/\*.*\*/\)[ ]*$;\1else \2;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"; |
||||
|
||||
# Pull in #endif comments. |
||||
sed 's;^#endif[ ][ ]*/\*;#endif /*;' | |
||||
# globals |
||||
my @files; |
||||
my $filtered_typedefs_fh; |
||||
|
||||
# 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; |
||||
}' | |
||||
|
||||
# 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 ' |
||||
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; |
||||
} |
||||
|
||||
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; |
||||
}' | |
||||
|
||||
# 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; |
||||
}' | |
||||
print STDERR |
||||
"You do not appear to have 'indent' installed on your system.\n"; |
||||
exit 1; |
||||
} |
||||
|
||||
# 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; |
||||
}' | |
||||
if (`$indent -V` !~ m/ $INDENT_VERSION$/) |
||||
{ |
||||
print STDERR |
||||
"You do not appear to have $indent version $INDENT_VERSION installed on your system.\n"; |
||||
exit 1; |
||||
} |
||||
|
||||
# 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} |
||||
system("$indent -gnu < $devnull > $devnull 2>&1"); |
||||
if ($? == 0) |
||||
{ |
||||
if ($0 ~ /^[a-zA-Z_][a-zA-Z_0-9]*[^\(]*$/) |
||||
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; |
||||
}' | |
||||
|
||||
# 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 |
||||
close($eh); |
||||
} |
||||
} |
||||
|
||||
|
||||
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; |
||||
|
||||
@ -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