indent(1): Sync with FreeBSD and raise WARNS to 6.
[dragonfly.git] / usr.bin / indent / indent.c
1 /*
2  * Copyright (c) 1985 Sun Microsystems, Inc.
3  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
4  * Copyright (c) 1980, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by the University of
18  *      California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * @(#) Copyright (c) 1985 Sun Microsystems, Inc.
36  * @(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.
37  * @(#) Copyright (c) 1980, 1993 The Regents of the University of California.  All rights reserved.
38  * @(#)indent.c 5.17 (Berkeley) 6/7/93
39  * $FreeBSD: src/usr.bin/indent/indent.c,v 1.25 2006/09/13 05:06:12 charnier Exp $
40  * $DragonFly: src/usr.bin/indent/indent.c,v 1.4 2007/05/13 18:33:58 swildner Exp $
41  */
42
43 #include <sys/param.h>
44 #include <err.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include "indent_globs.h"
52 #include "indent_codes.h"
53 #include "indent.h"
54
55 static void bakcopy(void);
56
57 const char *in_name = "Standard Input"; /* will always point to name of input
58                                          * file */
59 const char *out_name = "Standard Output";       /* will always point to name
60                                                  * of output file */
61 char        bakfile[MAXPATHLEN] = "";
62
63 int
64 main(int argc, char **argv)
65 {
66
67     int         dec_ind;        /* current indentation for declarations */
68     int         di_stack[20];   /* a stack of structure indentation levels */
69     int         flushed_nl;     /* used when buffering up comments to remember
70                                  * that a newline was passed over */
71     int         force_nl;       /* when true, code must be broken */
72     int         hd_type = 0;    /* used to store type of stmt for if (...),
73                                  * for (...), etc */
74     int i;                      /* local loop counter */
75     int         scase;          /* set to true when we see a case, so we will
76                                  * know what to do with the following colon */
77     int         sp_sw;          /* when true, we are in the expression of
78                                  * if(...), while(...), etc. */
79     int         squest;         /* when this is positive, we have seen a ?
80                                  * without the matching : in a <c>?<s>:<s>
81                                  * construct */
82     const char *t_ptr;          /* used for copying tokens */
83     int         tabs_to_var;    /* true if using tabs to indent to var name */
84     int         type_code;      /* the type of token, returned by lexi */
85
86     int         last_else = 0;  /* true iff last keyword was an else */
87
88
89     /*-----------------------------------------------*\
90     |                 INITIALIZATION                  |
91     \*-----------------------------------------------*/
92
93     found_err = 0;
94
95     ps.p_stack[0] = stmt;       /* this is the parser's stack */
96     ps.last_nl = true;          /* this is true if the last thing scanned was
97                                  * a newline */
98     ps.last_token = semicolon;
99     combuf = (char *) malloc(bufsize);
100     if (combuf == NULL)
101         err(1, NULL);
102     labbuf = (char *) malloc(bufsize);
103     if (labbuf == NULL)
104         err(1, NULL);
105     codebuf = (char *) malloc(bufsize);
106     if (codebuf == NULL)
107         err(1, NULL);
108     tokenbuf = (char *) malloc(bufsize);
109     if (tokenbuf == NULL)
110         err(1, NULL);
111     l_com = combuf + bufsize - 5;
112     l_lab = labbuf + bufsize - 5;
113     l_code = codebuf + bufsize - 5;
114     l_token = tokenbuf + bufsize - 5;
115     combuf[0] = codebuf[0] = labbuf[0] = ' ';   /* set up code, label, and
116                                                  * comment buffers */
117     combuf[1] = codebuf[1] = labbuf[1] = '\0';
118     ps.else_if = 1;             /* Default else-if special processing to on */
119     s_lab = e_lab = labbuf + 1;
120     s_code = e_code = codebuf + 1;
121     s_com = e_com = combuf + 1;
122     s_token = e_token = tokenbuf + 1;
123
124     in_buffer = (char *) malloc(10);
125     if (in_buffer == NULL)
126         err(1, NULL);
127     in_buffer_limit = in_buffer + 8;
128     buf_ptr = buf_end = in_buffer;
129     line_no = 1;
130     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
131     sp_sw = force_nl = false;
132     ps.in_or_st = false;
133     ps.bl_line = true;
134     dec_ind = 0;
135     di_stack[ps.dec_nest = 0] = 0;
136     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
137
138     scase = ps.pcase = false;
139     squest = 0;
140     sc_end = 0;
141     bp_save = 0;
142     be_save = 0;
143
144     output = 0;
145     tabs_to_var = 0;
146
147     /*--------------------------------------------------*\
148     |                   COMMAND LINE SCAN                |
149     \*--------------------------------------------------*/
150
151 #ifdef undef
152     max_col = 78;               /* -l78 */
153     lineup_to_parens = 1;       /* -lp */
154     ps.ljust_decl = 0;          /* -ndj */
155     ps.com_ind = 33;            /* -c33 */
156     star_comment_cont = 1;      /* -sc */
157     ps.ind_size = 8;            /* -i8 */
158     verbose = 0;
159     ps.decl_indent = 16;        /* -di16 */
160     ps.local_decl_indent = -1;  /* if this is not set to some nonnegative value
161                                  * by an arg, we will set this equal to
162                                  * ps.decl_ind */
163     ps.indent_parameters = 1;   /* -ip */
164     ps.decl_com_ind = 0;        /* if this is not set to some positive value
165                                  * by an arg, we will set this equal to
166                                  * ps.com_ind */
167     btype_2 = 1;                /* -br */
168     cuddle_else = 1;            /* -ce */
169     ps.unindent_displace = 0;   /* -d0 */
170     ps.case_indent = 0;         /* -cli0 */
171     format_block_comments = 1;  /* -fcb */
172     format_col1_comments = 1;   /* -fc1 */
173     procnames_start_line = 1;   /* -psl */
174     proc_calls_space = 0;       /* -npcs */
175     comment_delimiter_on_blankline = 1; /* -cdb */
176     ps.leave_comma = 1;         /* -nbc */
177 #endif
178
179     for (i = 1; i < argc; ++i)
180         if (strcmp(argv[i], "-npro") == 0)
181             break;
182     set_defaults();
183     if (i >= argc)
184         set_profile();
185
186     for (i = 1; i < argc; ++i) {
187
188         /*
189          * look thru args (if any) for changes to defaults
190          */
191         if (argv[i][0] != '-') {/* no flag on parameter */
192             if (input == 0) {   /* we must have the input file */
193                 in_name = argv[i];      /* remember name of input file */
194                 input = fopen(in_name, "r");
195                 if (input == 0)         /* check for open error */
196                         err(1, "%s", in_name);
197                 continue;
198             }
199             else if (output == 0) {     /* we have the output file */
200                 out_name = argv[i];     /* remember name of output file */
201                 if (strcmp(in_name, out_name) == 0) {   /* attempt to overwrite
202                                                          * the file */
203                     errx(1, "input and output files must be different");
204                 }
205                 output = fopen(out_name, "w");
206                 if (output == 0)        /* check for create error */
207                         err(1, "%s", out_name);
208                 continue;
209             }
210             errx(1, "unknown parameter: %s", argv[i]);
211         }
212         else
213             set_option(argv[i]);
214     }                           /* end of for */
215     if (input == 0)
216         input = stdin;
217     if (output == 0) {
218         if (troff || input == stdin)
219             output = stdout;
220         else {
221             out_name = in_name;
222             bakcopy();
223         }
224     }
225     if (ps.com_ind <= 1)
226         ps.com_ind = 2;         /* dont put normal comments before column 2 */
227     if (troff) {
228         if (bodyf.font[0] == 0)
229             parsefont(&bodyf, "R");
230         if (scomf.font[0] == 0)
231             parsefont(&scomf, "I");
232         if (blkcomf.font[0] == 0)
233             blkcomf = scomf, blkcomf.size += 2;
234         if (boxcomf.font[0] == 0)
235             boxcomf = blkcomf;
236         if (stringf.font[0] == 0)
237             parsefont(&stringf, "L");
238         if (keywordf.font[0] == 0)
239             parsefont(&keywordf, "B");
240         writefdef(&bodyf, 'B');
241         writefdef(&scomf, 'C');
242         writefdef(&blkcomf, 'L');
243         writefdef(&boxcomf, 'X');
244         writefdef(&stringf, 'S');
245         writefdef(&keywordf, 'K');
246     }
247     if (block_comment_max_col <= 0)
248         block_comment_max_col = max_col;
249     if (ps.local_decl_indent < 0)       /* if not specified by user, set this */
250         ps.local_decl_indent = ps.decl_indent;
251     if (ps.decl_com_ind <= 0)   /* if not specified by user, set this */
252         ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
253     if (continuation_indent == 0)
254         continuation_indent = ps.ind_size;
255     fill_buffer();              /* get first batch of stuff into input buffer */
256
257     parse(semicolon);
258     {
259         char *p = buf_ptr;
260         int col = 1;
261
262         while (1) {
263             if (*p == ' ')
264                 col++;
265             else if (*p == '\t')
266                 col = ((col - 1) & ~7) + 9;
267             else
268                 break;
269             p++;
270         }
271         if (col > ps.ind_size)
272             ps.ind_level = ps.i_l_follow = col / ps.ind_size;
273     }
274     if (troff) {
275         const char *p = in_name,
276                    *beg = in_name;
277
278         while (*p)
279             if (*p++ == '/')
280                 beg = p;
281         fprintf(output, ".Fn \"%s\"\n", beg);
282     }
283     /*
284      * START OF MAIN LOOP
285      */
286
287     while (1) {                 /* this is the main loop.  it will go until we
288                                  * reach eof */
289         int         is_procname;
290
291         type_code = lexi();     /* lexi reads one token.  The actual
292                                  * characters read are stored in "token". lexi
293                                  * returns a code indicating the type of token */
294         is_procname = ps.procname[0];
295
296         /*
297          * The following code moves everything following an if (), while (),
298          * else, etc. up to the start of the following stmt to a buffer. This
299          * allows proper handling of both kinds of brace placement.
300          */
301
302         flushed_nl = false;
303         while (ps.search_brace) {       /* if we scanned an if(), while(),
304                                          * etc., we might need to copy stuff
305                                          * into a buffer we must loop, copying
306                                          * stuff into save_com, until we find
307                                          * the start of the stmt which follows
308                                          * the if, or whatever */
309             switch (type_code) {
310             case newline:
311                 ++line_no;
312                 flushed_nl = true;
313             case form_feed:
314                 break;          /* form feeds and newlines found here will be
315                                  * ignored */
316
317             case lbrace:        /* this is a brace that starts the compound
318                                  * stmt */
319                 if (sc_end == 0) {      /* ignore buffering if a comment wasnt
320                                          * stored up */
321                     ps.search_brace = false;
322                     goto check_type;
323                 }
324                 if (btype_2) {
325                     save_com[0] = '{';  /* we either want to put the brace
326                                          * right after the if */
327                     goto sw_buffer;     /* go to common code to get out of
328                                          * this loop */
329                 }
330             case comment:       /* we have a comment, so we must copy it into
331                                  * the buffer */
332                 if (!flushed_nl || sc_end != 0) {
333                     if (sc_end == 0) {  /* if this is the first comment, we
334                                          * must set up the buffer */
335                         save_com[0] = save_com[1] = ' ';
336                         sc_end = &(save_com[2]);
337                     }
338                     else {
339                         *sc_end++ = '\n';       /* add newline between
340                                                  * comments */
341                         *sc_end++ = ' ';
342                         --line_no;
343                     }
344                     *sc_end++ = '/';    /* copy in start of comment */
345                     *sc_end++ = '*';
346
347                     for (;;) {  /* loop until we get to the end of the comment */
348                         *sc_end = *buf_ptr++;
349                         if (buf_ptr >= buf_end)
350                             fill_buffer();
351
352                         if (*sc_end++ == '*' && *buf_ptr == '/')
353                             break;      /* we are at end of comment */
354
355                         if (sc_end >= &(save_com[sc_size])) {   /* check for temp buffer
356                                                                  * overflow */
357                             diag2(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever");
358                             fflush(output);
359                             exit(1);
360                         }
361                     }
362                     *sc_end++ = '/';    /* add ending slash */
363                     if (++buf_ptr >= buf_end)   /* get past / in buffer */
364                         fill_buffer();
365                     break;
366                 }
367             default:            /* it is the start of a normal statement */
368                 if (flushed_nl) /* if we flushed a newline, make sure it is
369                                  * put back */
370                     force_nl = true;
371                 if ((type_code == sp_paren && *token == 'i'
372                         && last_else && ps.else_if)
373                         || (type_code == sp_nparen && *token == 'e'
374                         && e_code != s_code && e_code[-1] == '}'))
375                     force_nl = false;
376
377                 if (sc_end == 0) {      /* ignore buffering if comment wasnt
378                                          * saved up */
379                     ps.search_brace = false;
380                     goto check_type;
381                 }
382                 if (force_nl) { /* if we should insert a nl here, put it into
383                                  * the buffer */
384                     force_nl = false;
385                     --line_no;  /* this will be re-increased when the nl is
386                                  * read from the buffer */
387                     *sc_end++ = '\n';
388                     *sc_end++ = ' ';
389                     if (verbose && !flushed_nl) /* print error msg if the line
390                                                  * was not already broken */
391                         diag2(0, "Line broken");
392                     flushed_nl = false;
393                 }
394                 for (t_ptr = token; *t_ptr; ++t_ptr)
395                     *sc_end++ = *t_ptr; /* copy token into temp buffer */
396                 ps.procname[0] = 0;
397
398         sw_buffer:
399                 ps.search_brace = false;        /* stop looking for start of
400                                                  * stmt */
401                 bp_save = buf_ptr;      /* save current input buffer */
402                 be_save = buf_end;
403                 buf_ptr = save_com;     /* fix so that subsequent calls to
404                                          * lexi will take tokens out of
405                                          * save_com */
406                 *sc_end++ = ' ';/* add trailing blank, just in case */
407                 buf_end = sc_end;
408                 sc_end = 0;
409                 break;
410             }                   /* end of switch */
411             if (type_code != 0) /* we must make this check, just in case there
412                                  * was an unexpected EOF */
413                 type_code = lexi();     /* read another token */
414             /* if (ps.search_brace) ps.procname[0] = 0; */
415             if ((is_procname = ps.procname[0]) && flushed_nl
416                     && !procnames_start_line && ps.in_decl
417                     && type_code == ident)
418                 flushed_nl = 0;
419         }                       /* end of while (search_brace) */
420         last_else = 0;
421 check_type:
422         if (type_code == 0) {   /* we got eof */
423             if (s_lab != e_lab || s_code != e_code
424                     || s_com != e_com)  /* must dump end of line */
425                 dump_line();
426             if (ps.tos > 1)     /* check for balanced braces */
427                 diag2(1, "Stuff missing from end of file");
428
429             if (verbose) {
430                 printf("There were %d output lines and %d comments\n",
431                        ps.out_lines, ps.out_coms);
432                 printf("(Lines with comments)/(Lines with code): %6.3f\n",
433                        (1.0 * ps.com_lines) / code_lines);
434             }
435             fflush(output);
436             exit(found_err);
437         }
438         if (
439                 (type_code != comment) &&
440                 (type_code != newline) &&
441                 (type_code != preesc) &&
442                 (type_code != form_feed)) {
443             if (force_nl &&
444                     (type_code != semicolon) &&
445                     (type_code != lbrace || !btype_2)) {
446                 /* we should force a broken line here */
447                 if (verbose && !flushed_nl)
448                     diag2(0, "Line broken");
449                 flushed_nl = false;
450                 dump_line();
451                 ps.want_blank = false;  /* dont insert blank at line start */
452                 force_nl = false;
453             }
454             ps.in_stmt = true;  /* turn on flag which causes an extra level of
455                                  * indentation. this is turned off by a ; or
456                                  * '}' */
457             if (s_com != e_com) {       /* the turkey has embedded a comment
458                                          * in a line. fix it */
459                 *e_code++ = ' ';
460                 for (t_ptr = s_com; *t_ptr; ++t_ptr) {
461                     CHECK_SIZE_CODE;
462                     *e_code++ = *t_ptr;
463                 }
464                 *e_code++ = ' ';
465                 *e_code = '\0'; /* null terminate code sect */
466                 ps.want_blank = false;
467                 e_com = s_com;
468             }
469         }
470         else if (type_code != comment)  /* preserve force_nl thru a comment */
471             force_nl = false;   /* cancel forced newline after newline, form
472                                  * feed, etc */
473
474
475
476         /*-----------------------------------------------------*\
477         |          do switch on type of token scanned           |
478         \*-----------------------------------------------------*/
479         CHECK_SIZE_CODE;
480         switch (type_code) {    /* now, decide what to do with the token */
481
482         case form_feed: /* found a form feed in line */
483             ps.use_ff = true;   /* a form feed is treated much like a newline */
484             dump_line();
485             ps.want_blank = false;
486             break;
487
488         case newline:
489             if (ps.last_token != comma || ps.p_l_follow > 0
490                     || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com) {
491                 dump_line();
492                 ps.want_blank = false;
493             }
494             ++line_no;          /* keep track of input line number */
495             break;
496
497         case lparen:            /* got a '(' or '[' */
498             ++ps.p_l_follow;    /* count parens to make Healy happy */
499             if (ps.want_blank && *token != '[' &&
500                     (ps.last_token != ident || proc_calls_space
501               || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon))))
502                 *e_code++ = ' ';
503             if (ps.in_decl && !ps.block_init)
504                 if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl) {
505                     ps.dumped_decl_indent = 1;
506                     sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
507                     e_code += strlen(e_code);
508                 }
509                 else {
510                     while ((e_code - s_code) < dec_ind) {
511                         CHECK_SIZE_CODE;
512                         *e_code++ = ' ';
513                     }
514                     *e_code++ = token[0];
515                 }
516             else
517                 *e_code++ = token[0];
518             ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code;
519             if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent
520                     && ps.paren_indents[0] < 2 * ps.ind_size)
521                 ps.paren_indents[0] = 2 * ps.ind_size;
522             ps.want_blank = false;
523             if (ps.in_or_st && *token == '(' && ps.tos <= 2) {
524                 /*
525                  * this is a kluge to make sure that declarations will be
526                  * aligned right if proc decl has an explicit type on it, i.e.
527                  * "int a(x) {..."
528                  */
529                 parse(semicolon);       /* I said this was a kluge... */
530                 ps.in_or_st = false;    /* turn off flag for structure decl or
531                                          * initialization */
532             }
533             if (ps.sizeof_keyword)
534                 ps.sizeof_mask |= 1 << ps.p_l_follow;
535             break;
536
537         case rparen:            /* got a ')' or ']' */
538             rparen_count--;
539             if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask) {
540                 ps.last_u_d = true;
541                 ps.cast_mask &= (1 << ps.p_l_follow) - 1;
542                 ps.want_blank = false;
543             } else
544                 ps.want_blank = true;
545             ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
546             if (--ps.p_l_follow < 0) {
547                 ps.p_l_follow = 0;
548                 diag3(0, "Extra %c", *token);
549             }
550             if (e_code == s_code)       /* if the paren starts the line */
551                 ps.paren_level = ps.p_l_follow; /* then indent it */
552
553             *e_code++ = token[0];
554
555             if (sp_sw && (ps.p_l_follow == 0)) {        /* check for end of if
556                                                          * (...), or some such */
557                 sp_sw = false;
558                 force_nl = true;/* must force newline after if */
559                 ps.last_u_d = true;     /* inform lexi that a following
560                                          * operator is unary */
561                 ps.in_stmt = false;     /* dont use stmt continuation
562                                          * indentation */
563
564                 parse(hd_type); /* let parser worry about if, or whatever */
565             }
566             ps.search_brace = btype_2;  /* this should insure that constructs
567                                          * such as main(){...} and int[]{...}
568                                          * have their braces put in the right
569                                          * place */
570             break;
571
572         case unary_op:          /* this could be any unary operation */
573             if (ps.want_blank)
574                 *e_code++ = ' ';
575
576             if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname) {
577                 sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
578                 ps.dumped_decl_indent = 1;
579                 e_code += strlen(e_code);
580             }
581             else {
582                 const char *res = token;
583
584                 if (ps.in_decl && !ps.block_init) {     /* if this is a unary op
585                                                          * in a declaration, we
586                                                          * should indent this
587                                                          * token */
588                     for (i = 0; token[i]; ++i); /* find length of token */
589                     while ((e_code - s_code) < (dec_ind - i)) {
590                         CHECK_SIZE_CODE;
591                         *e_code++ = ' ';        /* pad it */
592                     }
593                 }
594                 if (troff && token[0] == '-' && token[1] == '>')
595                     res = "\\(->";
596                 for (t_ptr = res; *t_ptr; ++t_ptr) {
597                     CHECK_SIZE_CODE;
598                     *e_code++ = *t_ptr;
599                 }
600             }
601             ps.want_blank = false;
602             break;
603
604         case binary_op: /* any binary operation */
605             if (ps.want_blank)
606                 *e_code++ = ' ';
607             {
608                 const char *res = token;
609
610                 if (troff)
611                     switch (token[0]) {
612                     case '<':
613                         if (token[1] == '=')
614                             res = "\\(<=";
615                         break;
616                     case '>':
617                         if (token[1] == '=')
618                             res = "\\(>=";
619                         break;
620                     case '!':
621                         if (token[1] == '=')
622                             res = "\\(!=";
623                         break;
624                     case '|':
625                         if (token[1] == '|')
626                             res = "\\(br\\(br";
627                         else if (token[1] == 0)
628                             res = "\\(br";
629                         break;
630                     }
631                 for (t_ptr = res; *t_ptr; ++t_ptr) {
632                     CHECK_SIZE_CODE;
633                     *e_code++ = *t_ptr; /* move the operator */
634                 }
635             }
636             ps.want_blank = true;
637             break;
638
639         case postop:            /* got a trailing ++ or -- */
640             *e_code++ = token[0];
641             *e_code++ = token[1];
642             ps.want_blank = true;
643             break;
644
645         case question:          /* got a ? */
646             squest++;           /* this will be used when a later colon
647                                  * appears so we can distinguish the
648                                  * <c>?<n>:<n> construct */
649             if (ps.want_blank)
650                 *e_code++ = ' ';
651             *e_code++ = '?';
652             ps.want_blank = true;
653             break;
654
655         case casestmt:          /* got word 'case' or 'default' */
656             scase = true;       /* so we can process the later colon properly */
657             goto copy_id;
658
659         case colon:             /* got a ':' */
660             if (squest > 0) {   /* it is part of the <c>?<n>: <n> construct */
661                 --squest;
662                 if (ps.want_blank)
663                     *e_code++ = ' ';
664                 *e_code++ = ':';
665                 ps.want_blank = true;
666                 break;
667             }
668             if (ps.in_decl) {
669                 *e_code++ = ':';
670                 ps.want_blank = false;
671                 break;
672             }
673             ps.in_stmt = false; /* seeing a label does not imply we are in a
674                                  * stmt */
675             for (t_ptr = s_code; *t_ptr; ++t_ptr)
676                 *e_lab++ = *t_ptr;      /* turn everything so far into a label */
677             e_code = s_code;
678             *e_lab++ = ':';
679             *e_lab++ = ' ';
680             *e_lab = '\0';
681
682             force_nl = ps.pcase = scase;        /* ps.pcase will be used by
683                                                  * dump_line to decide how to
684                                                  * indent the label. force_nl
685                                                  * will force a case n: to be
686                                                  * on a line by itself */
687             scase = false;
688             ps.want_blank = false;
689             break;
690
691         case semicolon: /* got a ';' */
692             ps.in_or_st = false;/* we are not in an initialization or
693                                  * structure declaration */
694             scase = false;      /* these will only need resetting in an error */
695             squest = 0;
696             if (ps.last_token == rparen && rparen_count == 0)
697                 ps.in_parameter_declaration = 0;
698             ps.cast_mask = 0;
699             ps.sizeof_mask = 0;
700             ps.block_init = 0;
701             ps.block_init_level = 0;
702             ps.just_saw_decl--;
703
704             if (ps.in_decl && s_code == e_code && !ps.block_init)
705                 while ((e_code - s_code) < (dec_ind - 1)) {
706                     CHECK_SIZE_CODE;
707                     *e_code++ = ' ';
708                 }
709
710             ps.in_decl = (ps.dec_nest > 0);     /* if we were in a first level
711                                                  * structure declaration, we
712                                                  * arent any more */
713
714             if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
715
716                 /*
717                  * This should be true iff there were unbalanced parens in the
718                  * stmt.  It is a bit complicated, because the semicolon might
719                  * be in a for stmt
720                  */
721                 diag2(1, "Unbalanced parens");
722                 ps.p_l_follow = 0;
723                 if (sp_sw) {    /* this is a check for an if, while, etc. with
724                                  * unbalanced parens */
725                     sp_sw = false;
726                     parse(hd_type);     /* dont lose the if, or whatever */
727                 }
728             }
729             *e_code++ = ';';
730             ps.want_blank = true;
731             ps.in_stmt = (ps.p_l_follow > 0);   /* we are no longer in the
732                                                  * middle of a stmt */
733
734             if (!sp_sw) {       /* if not if for (;;) */
735                 parse(semicolon);       /* let parser know about end of stmt */
736                 force_nl = true;/* force newline after an end of stmt */
737             }
738             break;
739
740         case lbrace:            /* got a '{' */
741             ps.in_stmt = false; /* dont indent the {} */
742             if (!ps.block_init)
743                 force_nl = true;/* force other stuff on same line as '{' onto
744                                  * new line */
745             else if (ps.block_init_level <= 0)
746                 ps.block_init_level = 1;
747             else
748                 ps.block_init_level++;
749
750             if (s_code != e_code && !ps.block_init) {
751                 if (!btype_2) {
752                     dump_line();
753                     ps.want_blank = false;
754                 }
755                 else if (ps.in_parameter_declaration && !ps.in_or_st) {
756                     ps.i_l_follow = 0;
757                     if (function_brace_split) { /* dump the line prior to the
758                                                  * brace ... */
759                     dump_line();
760                     ps.want_blank = false;
761                     } else      /* add a space between the decl and brace */
762                         ps.want_blank = true;
763                 }
764             }
765             if (ps.in_parameter_declaration)
766                 prefix_blankline_requested = 0;
767
768             if (ps.p_l_follow > 0) {    /* check for preceding unbalanced
769                                          * parens */
770                 diag2(1, "Unbalanced parens");
771                 ps.p_l_follow = 0;
772                 if (sp_sw) {    /* check for unclosed if, for, etc. */
773                     sp_sw = false;
774                     parse(hd_type);
775                     ps.ind_level = ps.i_l_follow;
776                 }
777             }
778             if (s_code == e_code)
779                 ps.ind_stmt = false;    /* dont put extra indentation on line
780                                          * with '{' */
781             if (ps.in_decl && ps.in_or_st) {    /* this is either a structure
782                                                  * declaration or an init */
783                 di_stack[ps.dec_nest++] = dec_ind;
784                 /* ?            dec_ind = 0; */
785             }
786             else {
787                 ps.decl_on_line = false;        /* we cant be in the middle of
788                                                  * a declaration, so dont do
789                                                  * special indentation of
790                                                  * comments */
791                 if (blanklines_after_declarations_at_proctop
792                         && ps.in_parameter_declaration)
793                     postfix_blankline_requested = 1;
794                 ps.in_parameter_declaration = 0;
795             }
796             dec_ind = 0;
797             parse(lbrace);      /* let parser know about this */
798             if (ps.want_blank)  /* put a blank before '{' if '{' is not at
799                                  * start of line */
800                 *e_code++ = ' ';
801             ps.want_blank = false;
802             *e_code++ = '{';
803             ps.just_saw_decl = 0;
804             break;
805
806         case rbrace:            /* got a '}' */
807             if (ps.p_stack[ps.tos] == decl && !ps.block_init)   /* semicolons can be
808                                                                  * omitted in
809                                                                  * declarations */
810                 parse(semicolon);
811             if (ps.p_l_follow) {/* check for unclosed if, for, else. */
812                 diag2(1, "Unbalanced parens");
813                 ps.p_l_follow = 0;
814                 sp_sw = false;
815             }
816             ps.just_saw_decl = 0;
817             ps.block_init_level--;
818             if (s_code != e_code && !ps.block_init) {   /* '}' must be first on
819                                                          * line */
820                 if (verbose)
821                     diag2(0, "Line broken");
822                 dump_line();
823             }
824             *e_code++ = '}';
825             ps.want_blank = true;
826             ps.in_stmt = ps.ind_stmt = false;
827             if (ps.dec_nest > 0) {      /* we are in multi-level structure
828                                          * declaration */
829                 dec_ind = di_stack[--ps.dec_nest];
830                 if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
831                     ps.just_saw_decl = 2;
832                 ps.in_decl = true;
833             }
834             prefix_blankline_requested = 0;
835             parse(rbrace);      /* let parser know about this */
836             ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead
837                 && ps.il[ps.tos] >= ps.ind_level;
838             if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
839                 postfix_blankline_requested = 1;
840             break;
841
842         case swstmt:            /* got keyword "switch" */
843             sp_sw = true;
844             hd_type = swstmt;   /* keep this for when we have seen the
845                                  * expression */
846             goto copy_id;       /* go move the token into buffer */
847
848         case sp_paren:          /* token is if, while, for */
849             sp_sw = true;       /* the interesting stuff is done after the
850                                  * expression is scanned */
851             hd_type = (*token == 'i' ? ifstmt :
852                        (*token == 'w' ? whilestmt : forstmt));
853
854             /*
855              * remember the type of header for later use by parser
856              */
857             goto copy_id;       /* copy the token into line */
858
859         case sp_nparen: /* got else, do */
860             ps.in_stmt = false;
861             if (*token == 'e') {
862                 if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
863                     if (verbose)
864                         diag2(0, "Line broken");
865                     dump_line();/* make sure this starts a line */
866                     ps.want_blank = false;
867                 }
868                 force_nl = true;/* also, following stuff must go onto new line */
869                 last_else = 1;
870                 parse(elselit);
871             }
872             else {
873                 if (e_code != s_code) { /* make sure this starts a line */
874                     if (verbose)
875                         diag2(0, "Line broken");
876                     dump_line();
877                     ps.want_blank = false;
878                 }
879                 force_nl = true;/* also, following stuff must go onto new line */
880                 last_else = 0;
881                 parse(dolit);
882             }
883             goto copy_id;       /* move the token into line */
884
885         case decl:              /* we have a declaration type (int, register,
886                                  * etc.) */
887             parse(decl);        /* let parser worry about indentation */
888             if (ps.last_token == rparen && ps.tos <= 1) {
889                 ps.in_parameter_declaration = 1;
890                 if (s_code != e_code) {
891                     dump_line();
892                     ps.want_blank = 0;
893                 }
894             }
895             if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) {
896                 ps.ind_level = ps.i_l_follow = 1;
897                 ps.ind_stmt = 0;
898             }
899             ps.in_or_st = true; /* this might be a structure or initialization
900                                  * declaration */
901             ps.in_decl = ps.decl_on_line = true;
902             if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
903                 ps.just_saw_decl = 2;
904             prefix_blankline_requested = 0;
905             for (i = 0; token[i++];);   /* get length of token */
906
907             if (ps.ind_level == 0 || ps.dec_nest > 0) {
908                 /* global variable or struct member in local variable */
909             dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
910                 tabs_to_var = (use_tabs ? ps.decl_indent > 0 : 0);
911             } else {
912                 /* local variable */
913                 dec_ind = ps.local_decl_indent > 0 ? ps.local_decl_indent : i;
914                 tabs_to_var = (use_tabs ? ps.local_decl_indent > 0 : 0);
915             }
916             goto copy_id;
917
918         case ident:             /* got an identifier or constant */
919             if (ps.in_decl) {   /* if we are in a declaration, we must indent
920                                  * identifier */
921                 if (is_procname == 0 || !procnames_start_line) {
922                     if (!ps.block_init) {
923                         if (troff && !ps.dumped_decl_indent) {
924                             if (ps.want_blank)
925                                 *e_code++ = ' ';
926                             ps.want_blank = false;
927                             sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
928                             ps.dumped_decl_indent = 1;
929                             e_code += strlen(e_code);
930                         } else {
931                             int cur_dec_ind;
932                             int pos, startpos;
933
934                             /*
935                              * in order to get the tab math right for
936                              * indentations that are not multiples of 8 we
937                              * need to modify both startpos and dec_ind
938                              * (cur_dec_ind) here by eight minus the
939                              * remainder of the current starting column
940                              * divided by eight. This seems to be a
941                              * properly working fix
942                              */
943                             startpos = e_code - s_code;
944                             cur_dec_ind = dec_ind;
945                             pos = startpos;
946                             if ((ps.ind_level * ps.ind_size) % 8 != 0) {
947                                 pos += (ps.ind_level * ps.ind_size) % 8;
948                                 cur_dec_ind += (ps.ind_level * ps.ind_size) % 8;
949                             }
950
951                             if (tabs_to_var) {
952                                 while ((pos & ~7) + 8 <= cur_dec_ind) {
953                                     CHECK_SIZE_CODE;
954                                     *e_code++ = '\t';
955                                     pos = (pos & ~7) + 8;
956                                 }
957                             }
958                             while (pos < cur_dec_ind) {
959                                 CHECK_SIZE_CODE;
960                                 *e_code++ = ' ';
961                                 pos++;
962                             }
963                             if (ps.want_blank && e_code - s_code == startpos)
964                                 *e_code++ = ' ';
965                             ps.want_blank = false;
966                         }
967                     }
968                 } else {
969                     if (ps.want_blank)
970                         *e_code++ = ' ';
971                     ps.want_blank = false;
972                     if (dec_ind && s_code != e_code)
973                         dump_line();
974                     dec_ind = 0;
975                 }
976             }
977             else if (sp_sw && ps.p_l_follow == 0) {
978                 sp_sw = false;
979                 force_nl = true;
980                 ps.last_u_d = true;
981                 ps.in_stmt = false;
982                 parse(hd_type);
983             }
984     copy_id:
985             if (ps.want_blank)
986                 *e_code++ = ' ';
987             if (troff && ps.its_a_keyword) {
988                 e_code = chfont(&bodyf, &keywordf, e_code);
989                 for (t_ptr = token; *t_ptr; ++t_ptr) {
990                     CHECK_SIZE_CODE;
991                     *e_code++ = keywordf.allcaps && islower(*t_ptr)
992                         ? toupper(*t_ptr) : *t_ptr;
993                 }
994                 e_code = chfont(&keywordf, &bodyf, e_code);
995             }
996             else
997                 for (t_ptr = token; *t_ptr; ++t_ptr) {
998                     CHECK_SIZE_CODE;
999                     *e_code++ = *t_ptr;
1000                 }
1001             ps.want_blank = true;
1002             break;
1003
1004         case period:            /* treat a period kind of like a binary
1005                                  * operation */
1006             *e_code++ = '.';    /* move the period into line */
1007             ps.want_blank = false;      /* dont put a blank after a period */
1008             break;
1009
1010         case comma:
1011             ps.want_blank = (s_code != e_code); /* only put blank after comma
1012                                                  * if comma does not start the
1013                                                  * line */
1014             if (ps.in_decl && is_procname == 0 && !ps.block_init)
1015                 while ((e_code - s_code) < (dec_ind - 1)) {
1016                     CHECK_SIZE_CODE;
1017                     *e_code++ = ' ';
1018                 }
1019
1020             *e_code++ = ',';
1021             if (ps.p_l_follow == 0) {
1022                 if (ps.block_init_level <= 0)
1023                     ps.block_init = 0;
1024                 if (break_comma && (!ps.leave_comma || compute_code_target() + (e_code - s_code) > max_col - 8))
1025                     force_nl = true;
1026             }
1027             break;
1028
1029         case preesc:            /* got the character '#' */
1030             if ((s_com != e_com) ||
1031                     (s_lab != e_lab) ||
1032                     (s_code != e_code))
1033                 dump_line();
1034             *e_lab++ = '#';     /* move whole line to 'label' buffer */
1035             {
1036                 int         in_comment = 0;
1037                 int         com_start = 0;
1038                 char        quote = 0;
1039                 int         com_end = 0;
1040
1041                 while (*buf_ptr == ' ' || *buf_ptr == '\t') {
1042                     buf_ptr++;
1043                     if (buf_ptr >= buf_end)
1044                         fill_buffer();
1045                 }
1046                 while (*buf_ptr != '\n' || (in_comment && !had_eof)) {
1047                     CHECK_SIZE_LAB;
1048                     *e_lab = *buf_ptr++;
1049                     if (buf_ptr >= buf_end)
1050                         fill_buffer();
1051                     switch (*e_lab++) {
1052                     case BACKSLASH:
1053                         if (troff)
1054                             *e_lab++ = BACKSLASH;
1055                         if (!in_comment) {
1056                             *e_lab++ = *buf_ptr++;
1057                             if (buf_ptr >= buf_end)
1058                                 fill_buffer();
1059                         }
1060                         break;
1061                     case '/':
1062                         if (*buf_ptr == '*' && !in_comment && !quote) {
1063                             in_comment = 1;
1064                             *e_lab++ = *buf_ptr++;
1065                             com_start = e_lab - s_lab - 2;
1066                         }
1067                         break;
1068                     case '"':
1069                         if (quote == '"')
1070                             quote = 0;
1071                         break;
1072                     case '\'':
1073                         if (quote == '\'')
1074                             quote = 0;
1075                         break;
1076                     case '*':
1077                         if (*buf_ptr == '/' && in_comment) {
1078                             in_comment = 0;
1079                             *e_lab++ = *buf_ptr++;
1080                             com_end = e_lab - s_lab;
1081                         }
1082                         break;
1083                     }
1084                 }
1085
1086                 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1087                     e_lab--;
1088                 if (e_lab - s_lab == com_end && bp_save == 0) { /* comment on
1089                                                                  * preprocessor line */
1090                     if (sc_end == 0)    /* if this is the first comment, we
1091                                          * must set up the buffer */
1092                         sc_end = &(save_com[0]);
1093                     else {
1094                         *sc_end++ = '\n';       /* add newline between
1095                                                  * comments */
1096                         *sc_end++ = ' ';
1097                         --line_no;
1098                     }
1099                     bcopy(s_lab + com_start, sc_end, com_end - com_start);
1100                     sc_end += com_end - com_start;
1101                     if (sc_end >= &save_com[sc_size])
1102                         abort();
1103                     e_lab = s_lab + com_start;
1104                     while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1105                         e_lab--;
1106                     bp_save = buf_ptr;  /* save current input buffer */
1107                     be_save = buf_end;
1108                     buf_ptr = save_com; /* fix so that subsequent calls to
1109                                          * lexi will take tokens out of
1110                                          * save_com */
1111                     *sc_end++ = ' ';    /* add trailing blank, just in case */
1112                     buf_end = sc_end;
1113                     sc_end = 0;
1114                 }
1115                 *e_lab = '\0';  /* null terminate line */
1116                 ps.pcase = false;
1117             }
1118
1119             if (strncmp(s_lab, "#if", 3) == 0) {
1120                 if (blanklines_around_conditional_compilation) {
1121                     int c;
1122                     prefix_blankline_requested++;
1123                     while ((c = getc(input)) == '\n');
1124                     ungetc(c, input);
1125                 }
1126                 if ((size_t)ifdef_level < sizeof(state_stack)/sizeof(state_stack[0])) {
1127                     match_state[ifdef_level].tos = -1;
1128                     state_stack[ifdef_level++] = ps;
1129                 }
1130                 else
1131                     diag2(1, "#if stack overflow");
1132             }
1133             else if (strncmp(s_lab, "#else", 5) == 0)
1134                 if (ifdef_level <= 0)
1135                     diag2(1, "Unmatched #else");
1136                 else {
1137                     match_state[ifdef_level - 1] = ps;
1138                     ps = state_stack[ifdef_level - 1];
1139                 }
1140             else if (strncmp(s_lab, "#endif", 6) == 0) {
1141                 if (ifdef_level <= 0)
1142                     diag2(1, "Unmatched #endif");
1143                 else {
1144                     ifdef_level--;
1145
1146 #ifdef undef
1147                     /*
1148                      * This match needs to be more intelligent before the
1149                      * message is useful
1150                      */
1151                     if (match_state[ifdef_level].tos >= 0
1152                           && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
1153                         diag2(0, "Syntactically inconsistent #ifdef alternatives");
1154 #endif
1155                 }
1156                 if (blanklines_around_conditional_compilation) {
1157                     postfix_blankline_requested++;
1158                     n_real_blanklines = 0;
1159                 }
1160             }
1161             break;              /* subsequent processing of the newline
1162                                  * character will cause the line to be printed */
1163
1164         case comment:           /* we have gotten a / followed by * this is a biggie */
1165             if (flushed_nl) {   /* we should force a broken line here */
1166                 flushed_nl = false;
1167                 dump_line();
1168                 ps.want_blank = false;  /* dont insert blank at line start */
1169                 force_nl = false;
1170             }
1171             pr_comment();
1172             break;
1173         }                       /* end of big switch stmt */
1174
1175         *e_code = '\0';         /* make sure code section is null terminated */
1176         if (type_code != comment && type_code != newline && type_code != preesc)
1177             ps.last_token = type_code;
1178     }                           /* end of main while (1) loop */
1179 }
1180
1181 /*
1182  * copy input file to backup file if in_name is /blah/blah/blah/file, then
1183  * backup file will be ".Bfile" then make the backup file the input and
1184  * original input file the output
1185  */
1186 static void
1187 bakcopy(void)
1188 {
1189     int         n,
1190                 bakchn;
1191     char        buff[8 * 1024];
1192     const char *p;
1193
1194     /* construct file name .Bfile */
1195     for (p = in_name; *p; p++); /* skip to end of string */
1196     while (p > in_name && *p != '/')    /* find last '/' */
1197         p--;
1198     if (*p == '/')
1199         p++;
1200     sprintf(bakfile, "%s.BAK", p);
1201
1202     /* copy in_name to backup file */
1203     bakchn = creat(bakfile, 0600);
1204     if (bakchn < 0)
1205         err(1, "%s", bakfile);
1206     while ((n = read(fileno(input), buff, sizeof buff)) != 0)
1207         if (write(bakchn, buff, n) != n)
1208             err(1, "%s", bakfile);
1209     if (n < 0)
1210         err(1, "%s", in_name);
1211     close(bakchn);
1212     fclose(input);
1213
1214     /* re-open backup file as the input file */
1215     input = fopen(bakfile, "r");
1216     if (input == 0)
1217         err(1, "%s", bakfile);
1218     /* now the original input file will be the output */
1219     output = fopen(in_name, "w");
1220     if (output == 0) {
1221         unlink(bakfile);
1222         err(1, "%s", in_name);
1223     }
1224 }