]> granicus.if.org Git - postgresql/blob - src/tools/pgindent/pgindent
ab8884db5e2bd36deefaf3ac3e60d30c4a6dc787
[postgresql] / src / tools / pgindent / pgindent
1 #!/bin/sh
2
3 # $PostgreSQL: pgsql/src/tools/pgindent/pgindent,v 1.98 2008/01/16 20:13:44 momjian Exp $
4
5 # Known bugs:
6 #
7 # Blank line is added after, seen as a function definition, no space
8 # after *:
9 #       y = (int) x *y;
10
11 if [ "$#" -lt 2 ]
12 then    echo "Usage:  `basename $0` typedefs file [...]" 1>&2
13         exit 1
14 fi
15
16 TYPEDEFS="$1"
17 shift
18
19 trap "rm -f /tmp/$$ /tmp/$$a" 0 1 2 3 15
20 entab </dev/null >/dev/null
21 if [ "$?" -ne 0 ]
22 then    echo "Go to the src/tools/entab directory and do a 'make' and 'make install'." >&2
23         echo "This will put the 'entab' command in your path." >&2
24         echo "Then run $0 again."
25         exit 1
26 fi
27 indent -? </dev/null >/dev/null 2>&1
28 if [ "$?" -ne 1 ]
29 then    echo "You do not appear to have 'indent' installed on your system." >&2
30         exit 1
31 fi
32 indent -gnu </dev/null >/dev/null 2>&1
33 if [ "$?" -eq 0 ]
34 then    echo "You appear to have GNU indent rather than BSD indent." >&2
35         echo "See the pgindent/README file for a description of its problems." >&2
36         EXTRA_OPTS="-cdb -bli0 -npcs -cli4 -sc"
37 else    echo "Hope you installed /src/tools/pgindent/indent.bsd.patch." >&2
38         EXTRA_OPTS="-cli1"
39 fi
40
41 for FILE
42 do
43         cat "$FILE" |
44
45 # Convert // comments to /* */
46         sed 's;^\([     ]*\)//\(.*\)$;\1/* \2 */;g' |
47
48 # Avoid bug that converts 'x =- 1' to 'x = -1'
49         sed 's;=- ;-= ;g' |
50
51 # Mark some comments for special treatment later
52         sed 's;/\*  *---;/*---X_X;g' |
53
54 # 'else' followed by a single-line comment, followed by
55 # a brace on the next line confuses BSD indent, so we push
56 # the comment down to the next line, then later pull it
57 # back up again.  Add space before _PGMV or indent will add
58 # it for us.
59         sed 's;\([}     ]\)else[        ]*\(/\*\)\(.*\*/\)[     ]*$;\1else\
60     \2 _PGMV\3;g' |
61
62 # Indent multi-line after-'else' comment so BSD indent will move it properly.
63 # We already moved down single-line comments above.  Check for '*' to make
64 # sure we are not in a single-line comment that has other text on the line.
65         sed 's;\([}     ]\)else[        ]*\(/\*[^\*]*\)[        ]*$;\1else\
66     \2;g' |
67         detab -t4 -qc |
68
69 # Work around bug where function that defines no local variables misindents
70 # switch() case lines and line after #else.  Do not do for struct/enum.
71         awk '   BEGIN   {line1 = ""; line2 = ""}
72                 {
73                         line2 = $0;
74                         if (NR >= 2)
75                                 print line1;
76                         if (NR >= 2 &&
77                             line2 ~ /^{[        ]*$/ &&
78                             line1 !~ /^struct/ &&
79                             line1 !~ /^enum/ &&
80                             line1 !~ /^typedef/ &&
81                             line1 !~ /^extern[  ][      ]*"C"/ &&
82                             line1 !~ /=/ &&
83                             line1 ~ /\)/)
84                                 print "int      pgindent_func_no_var_fix;";
85                         line1 = line2;
86                 }
87                 END {
88                         if (NR >= 1)
89                                 print line1;
90                 }' |
91
92 # Prevent indenting of code in 'extern "C"' blocks.
93         awk '   BEGIN   {line1 = ""; line2 = ""; skips = 0}
94                 {
95                         line2 = $0;
96                         if (skips > 0)
97                                 skips--;
98                         if (line1 ~ /^#ifdef[   ]*__cplusplus/ &&
99                             line2 ~ /^extern[   ]*"C"[  ]*$/)
100                         {
101                                 print line1;
102                                 print line2;
103                                 if (getline && $0 ~ /^{[        ]*$/)
104                                         print "/* Open extern \"C\" */";
105                                 else    print $0;
106                                 line2 = "";
107                                 skips = 2;
108                         }
109                         else if (line1 ~ /^#ifdef[      ]*__cplusplus/ &&
110                             line2 ~ /^}[        ]*$/)
111                         {
112                                 print line1;
113                                 print "/* Close extern \"C\" */";
114                                 line2 = "";
115                                 skips = 2;
116                         }
117                         else
118                                 if (skips == 0 && NR >= 2)
119                                         print line1;
120                         line1 = line2;
121                 }
122                 END {
123                         if (NR >= 1 && skips <= 1)
124                                 print line1;
125                 }' |
126
127 # Protect backslashes in DATA().
128         sed 's;^DATA(.*$;/*&*/;' |
129
130 # Protect wrapping in CATALOG().
131         sed 's;^CATALOG(.*$;/*&*/;' >/tmp/$$a
132
133 # We get the list of typedef's from /src/tools/find_typedef
134         indent -bad -bap -bc -bl -d0 -cdb -nce -nfc1 -di12 -i4 -l79 \
135                 -lp -nip -npro -bbb $EXTRA_OPTS \
136                 `cat "$TYPEDEFS" | sed 's/.*/-T& /'` \
137                 /tmp/$$a >/tmp/$$ 2>&1
138
139         if [ "$?" -ne 0 -o -s /tmp/$$ ]
140         then    echo
141                 echo "$FILE"
142                 cat /tmp/$$
143         fi
144         cat /tmp/$$a |
145
146 # Restore DATA/CATALOG lines.
147         sed 's;^/\*\(DATA(.*\)\*/$;\1;' |
148         sed 's;^/\*\(CATALOG(.*\)\*/$;\1;' |
149
150 # Remove tabs and retab with four spaces.
151         detab -t8 -qc |
152         entab -t4 -qc |
153         sed 's;^/\* Open extern \"C\" \*/$;{;' |
154         sed 's;^/\* Close extern \"C\" \*/$;};' |
155         sed 's;/\*---X_X;/* ---;g' |
156
157 # Workaround indent bug for 'static'.
158         sed 's;^static[         ][      ]*;static ;g' |
159
160 # Remove too much indenting after closing brace.
161         sed 's;^}       [       ]*;}    ;' |
162
163 # Indent single-line after-'else' comment by only one tab.
164         sed 's;\([}     ]\)else[        ]*\(/\*.*\*/\)[         ]*$;\1else      \2;g' |
165
166 # Pull in #endif comments.
167         sed 's;^#endif[         ][      ]*/\*;#endif   /*;' |
168
169 # Work around misindenting of function with no variables defined.
170         awk '
171         {
172                 if ($0 ~ /^[    ]*int[  ]*pgindent_func_no_var_fix;/)
173                 {
174                         if (getline && $0 != "")
175                                 print $0;
176                 }
177                 else    print $0;
178         }' |
179
180 # Add space after comments that start on tab stops.
181         sed 's;\([^     ]\)\(/\*.*\*/\)$;\1     \2;' |
182
183 # Move trailing * in function return type.
184         sed 's;^\([A-Za-z_][^   ]*\)[   ][      ]*\*$;\1 *;' |
185
186 # Remove un-needed braces around single statements.
187 # Do not use because it uglifies PG_TRY/PG_CATCH blocks and probably
188 # isn't needed for general use.
189 #       awk '
190 #       {
191 #                       line3 = $0;  
192 #                       if (skips > 0)
193 #                               skips--;
194 #                       if (line1 ~ /           *{$/ &&
195 #                           line2 ~ /           *[^;{}]*;$/ &&
196 #                           line3 ~ /           *}$/)
197 #                       {
198 #                               print line2;
199 #                               line2 = "";
200 #                               line3 = "";
201 #                               skips = 3;
202 #                       }
203 #                       else
204 #                               if (skips == 0 && NR >= 3)
205 #                                       print line1;
206 #                       line1 = line2;
207 #                       line2 = line3;
208 #               }
209 #               END {
210 #                       if (NR >= 2 && skips <= 1)
211 #                               print line1;
212 #                       if (NR >= 1 && skips <= 2)
213 #                               print line2;
214 #               }' |
215
216 # Remove blank line between opening brace and block comment.
217         awk '
218         {
219                         line3 = $0;  
220                         if (skips > 0)
221                                 skips--;
222                         if (line1 ~ /   *{$/ &&
223                             line2 ~ /^$/ &&
224                             line3 ~ /           *\/\*$/)
225                         {
226                                 print line1;
227                                 print line3;
228                                 line2 = "";
229                                 line3 = "";
230                                 skips = 3;
231                         }
232                         else
233                                 if (skips == 0 && NR >= 3)
234                                         print line1;
235                         line1 = line2;
236                         line2 = line3;
237                 }
238                 END {
239                         if (NR >= 2 && skips <= 1)
240                                 print line1;
241                         if (NR >= 1 && skips <= 2)
242                                 print line2;
243                 }' |
244
245 # Pull up single-line comment after 'else' that was pulled down above
246         awk '
247                 {
248                         if (NR != 1)
249                         {
250                                 if ($0 ~ "/\* _PGMV")
251                                 {
252                                         # remove tag
253                                         sub(" _PGMV", "", $0);
254                                         # remove leading whitespace
255                                         sub("^[         ]*", "", $0);
256                                         # add comment with single tab prefix
257                                         print prev_line"        "$0;
258                                         # throw away current line
259                                         getline;
260                                 }
261                                 else
262                                         print prev_line;
263                         }
264                         prev_line = $0;
265                 }
266                 END {
267                         if (NR >= 1)
268                                 print prev_line;
269                 }' |
270
271 # Remove trailing blank lines, helps with adding blank before trailing #endif.
272         awk '   BEGIN   {blank_lines = 0;}
273                 {
274                         line1 = $0;
275                         if (line1 ~ /^$/)
276                                 blank_lines++;
277                         else
278                         {
279                                 for (; blank_lines > 0; blank_lines--)
280                                         printf "\n";
281                                 print line1;
282                         }
283                 }' |
284
285 # Remove blank line before #else, #elif, and #endif.
286         awk '   BEGIN   {line1 = ""; line2 = ""; skips = 0}
287                 {
288                         line2 = $0;
289                         if (skips > 0)
290                                 skips--;
291                         if (line1 ~ /^$/ &&
292                             (line2 ~ /^#else/ ||
293                              line2 ~ /^#elif/ ||
294                              line2 ~ /^#endif/))
295                         {
296                                 print line2;
297                                 line2 = "";
298                                 skips = 2;
299                         }
300                         else
301                                 if (skips == 0 && NR >= 2)
302                                         print line1;
303                         line1 = line2;
304                 }
305                 END {
306                         if (NR >= 1 && skips <= 1)
307                                 print line1;
308                 }' |
309
310 # Add blank line before #endif if it is the last line in the file.
311         awk '   BEGIN   {line1 = ""; line2 = ""}
312                 {
313                         line2 = $0;
314                         if (NR >= 2)
315                                 print line1;
316                         line1 = line2;
317                 }
318                 END {
319                         if (NR >= 1 && line2 ~ /^#endif/)
320                                 printf "\n";
321                         print line1;
322                 }' |
323
324 #  Move prototype names to the same line as return type.  Useful for ctags. 
325 #  Indent should do this, but it does not.  It formats prototypes just
326 #  like real functions.
327         awk '   BEGIN   {paren_level = 0}  
328         {
329                 if ($0 ~ /^[a-zA-Z_][a-zA-Z_0-9]*[^\(]*$/)
330                 {
331                         saved_len = 0;
332                         saved_lines[++saved_len] = $0;
333                         if ((getline saved_lines[++saved_len]) == 0)
334                                 print saved_lines[1];
335                         else
336                         if (saved_lines[saved_len] !~ /^[a-zA-Z_][a-zA-Z_0-9]*\(/ ||
337                             saved_lines[saved_len] ~  /^[a-zA-Z_][a-zA-Z_0-9]*\(.*\)$/ ||
338                             saved_lines[saved_len] ~  /^[a-zA-Z_][a-zA-Z_0-9]*\(.*\);$/)
339                         {
340                                 print saved_lines[1];
341                                 print saved_lines[2];
342                         }
343                         else
344                         {
345                                 while (1)
346                                 {
347                                         if ((getline saved_lines[++saved_len]) == 0)
348                                                 break;
349                                         if (saved_lines[saved_len] ~ /^[^       ]/ ||
350                                             saved_lines[saved_len] !~ /,$/)
351                                                 break;
352                                 }
353                                 for (i=1; i <= saved_len; i++)
354                                 {
355                                         if (i == 1 && saved_lines[saved_len] ~ /\);$/)
356                                         {
357                                                 printf "%s", saved_lines[i];
358                                                 if (substr(saved_lines[i], length(saved_lines[i]),1) != "*")
359                                                         printf " ";
360                                         }
361                                         else    print saved_lines[i];
362                                 }
363                         }
364                 }
365                 else    print $0;
366         }' |
367
368 # Fix indenting of typedef caused by __cplusplus in libpq-fe.h.
369         (
370                 if echo "$FILE" | grep -q 'libpq-fe.h$'
371                 then    sed 's/^[       ]*typedef enum/typedef enum/'
372                 else    cat
373                 fi
374         ) |
375 # end
376         cat >/tmp/$$ && cat /tmp/$$ >"$FILE"
377 done
378
379 # The 'for' loop makes these backup files useless so delete them
380 rm -f *a.BAK