| #!/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 |
| |
| if [ -z "$INDENT" ] |
| then |
| INDENT=indent |
| fi |
| |
| trap "rm -f /tmp/$$ /tmp/$$a" 0 1 2 3 15 |
| 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 |
| $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' | |
| |
| # Avoid bug that converts 'x =- 1' to 'x = -1' |
| sed 's;=- ;-= ;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; |
| }' | |
| |
| # 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 |
| |
| # 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 \ |
| `egrep -v '^(FD_SET|date|interval|timestamp|ANY)$' "$TYPEDEFS" | sed -e '/^$/d' -e 's/.*/-T& /'` \ |
| /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 ' |
| { |
| 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 ' |
| { |
| 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; |
| }' | |
| |
| # 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 ($0 ~ /^[a-zA-Z_][a-zA-Z_0-9]*[^\(]*$/) |
| { |
| 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]; |
| } |
| } |
| } |
| 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 |