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