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