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