xref: /netbsd-src/usr.bin/indent/indent.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: indent.c,v 1.60 2021/03/26 22:02:00 rillig Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-4-Clause
5  *
6  * Copyright (c) 1985 Sun Microsystems, Inc.
7  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
8  * Copyright (c) 1980, 1993
9  *	The Regents of the University of California.  All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  */
39 
40 #if 0
41 #ifndef lint
42 static char sccsid[] = "@(#)indent.c	5.17 (Berkeley) 6/7/93";
43 #endif /* not lint */
44 #endif
45 
46 #include <sys/cdefs.h>
47 #ifndef lint
48 #if defined(__NetBSD__)
49 __RCSID("$NetBSD: indent.c,v 1.60 2021/03/26 22:02:00 rillig Exp $");
50 #elif defined(__FreeBSD__)
51 __FBSDID("$FreeBSD: head/usr.bin/indent/indent.c 340138 2018-11-04 19:24:49Z oshogbo $");
52 #endif
53 #endif
54 
55 #include <sys/param.h>
56 #if HAVE_CAPSICUM
57 #include <sys/capsicum.h>
58 #include <capsicum_helpers.h>
59 #endif
60 #include <err.h>
61 #include <errno.h>
62 #include <fcntl.h>
63 #include <unistd.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <ctype.h>
68 
69 #include "indent.h"
70 
71 struct options opt;
72 struct parser_state ps;
73 
74 char       *labbuf;
75 char       *s_lab;
76 char       *e_lab;
77 char       *l_lab;
78 
79 char       *codebuf;
80 char       *s_code;
81 char       *e_code;
82 char       *l_code;
83 
84 char       *combuf;
85 char       *s_com;
86 char       *e_com;
87 char       *l_com;
88 
89 char       *tokenbuf;
90 char	   *s_token;
91 char       *e_token;
92 char	   *l_token;
93 
94 char       *in_buffer;
95 char	   *in_buffer_limit;
96 char       *buf_ptr;
97 char       *buf_end;
98 
99 char        sc_buf[sc_size];
100 char       *save_com;
101 char       *sc_end;
102 
103 char       *bp_save;
104 char       *be_save;
105 
106 int         found_err;
107 int         n_real_blanklines;
108 int         prefix_blankline_requested;
109 int         postfix_blankline_requested;
110 int         break_comma;
111 float       case_ind;
112 int         code_lines;
113 int         had_eof;
114 int         line_no;
115 int         inhibit_formatting;
116 int         suppress_blanklines;
117 
118 int         ifdef_level;
119 struct parser_state state_stack[5];
120 struct parser_state match_state[5];
121 
122 FILE       *input;
123 FILE       *output;
124 
125 static void bakcopy(void);
126 static void indent_declaration(int, int);
127 
128 const char *in_name = "Standard Input";	/* will always point to name of input
129 					 * file */
130 const char *out_name = "Standard Output";	/* will always point to name
131 						 * of output file */
132 const char *simple_backup_suffix = ".BAK";	/* Suffix to use for backup
133 						 * files */
134 char        bakfile[MAXPATHLEN] = "";
135 
136 static void
137 check_size_code(size_t desired_size)
138 {
139     if (e_code + (desired_size) < l_code)
140         return;
141 
142     size_t nsize = l_code - s_code + 400 + desired_size;
143     size_t code_len = e_code - s_code;
144     codebuf = realloc(codebuf, nsize);
145     if (codebuf == NULL)
146 	err(1, NULL);
147     e_code = codebuf + code_len + 1;
148     l_code = codebuf + nsize - 5;
149     s_code = codebuf + 1;
150 }
151 
152 static void
153 check_size_label(size_t desired_size)
154 {
155     if (e_lab + (desired_size) < l_lab)
156         return;
157 
158     size_t nsize = l_lab - s_lab + 400 + desired_size;
159     size_t label_len = e_lab - s_lab;
160     labbuf = realloc(labbuf, nsize);
161     if (labbuf == NULL)
162 	err(1, NULL);
163     e_lab = labbuf + label_len + 1;
164     l_lab = labbuf + nsize - 5;
165     s_lab = labbuf + 1;
166 }
167 
168 #if HAVE_CAPSICUM
169 static void
170 init_capsicum(void)
171 {
172     cap_rights_t rights;
173 
174     /* Restrict input/output descriptors and enter Capsicum sandbox. */
175     cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE);
176     if (caph_rights_limit(fileno(output), &rights) < 0)
177 	err(EXIT_FAILURE, "unable to limit rights for %s", out_name);
178     cap_rights_init(&rights, CAP_FSTAT, CAP_READ);
179     if (caph_rights_limit(fileno(input), &rights) < 0)
180 	err(EXIT_FAILURE, "unable to limit rights for %s", in_name);
181     if (caph_enter() < 0)
182 	err(EXIT_FAILURE, "unable to enter capability mode");
183 }
184 #endif
185 
186 static void
187 search_brace(token_type *inout_type_code, int *inout_force_nl,
188 	     int *inout_comment_buffered, int *inout_last_else)
189 {
190     while (ps.search_brace) {
191 	switch (*inout_type_code) {
192 	case newline:
193 	    if (sc_end == NULL) {
194 		save_com = sc_buf;
195 		save_com[0] = save_com[1] = ' ';
196 		sc_end = &save_com[2];
197 	    }
198 	    *sc_end++ = '\n';
199 	    /*
200 	     * We may have inherited a force_nl == true from the previous
201 	     * token (like a semicolon). But once we know that a newline
202 	     * has been scanned in this loop, force_nl should be false.
203 	     *
204 	     * However, the force_nl == true must be preserved if newline
205 	     * is never scanned in this loop, so this assignment cannot be
206 	     * done earlier.
207 	     */
208 	    *inout_force_nl = false;
209 	    break;
210 	case form_feed:
211 	    break;
212 	case comment:
213 	    if (sc_end == NULL) {
214 		/*
215 		 * Copy everything from the start of the line, because
216 		 * process_comment() will use that to calculate original
217 		 * indentation of a boxed comment.
218 		 */
219 		memcpy(sc_buf, in_buffer, (size_t)(buf_ptr - in_buffer) - 4);
220 		save_com = sc_buf + (buf_ptr - in_buffer - 4);
221 		save_com[0] = save_com[1] = ' ';
222 		sc_end = &save_com[2];
223 	    }
224 	    *inout_comment_buffered = true;
225 	    *sc_end++ = '/';	/* copy in start of comment */
226 	    *sc_end++ = '*';
227 	    for (;;) {		/* loop until the end of the comment */
228 		*sc_end = *buf_ptr++;
229 		if (buf_ptr >= buf_end)
230 		    fill_buffer();
231 		if (*sc_end++ == '*' && *buf_ptr == '/')
232 		    break;	/* we are at end of comment */
233 		if (sc_end >= &save_com[sc_size]) {	/* check for temp buffer
234 							 * overflow */
235 		    diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever");
236 		    fflush(output);
237 		    exit(1);
238 		}
239 	    }
240 	    *sc_end++ = '/';	/* add ending slash */
241 	    if (++buf_ptr >= buf_end)	/* get past / in buffer */
242 		fill_buffer();
243 	    break;
244 	case lbrace:
245 	    /*
246 	     * Put KNF-style lbraces before the buffered up tokens and
247 	     * jump out of this loop in order to avoid copying the token
248 	     * again under the default case of the switch below.
249 	     */
250 	    if (sc_end != NULL && opt.btype_2) {
251 		save_com[0] = '{';
252 		/*
253 		 * Originally the lbrace may have been alone on its own
254 		 * line, but it will be moved into "the else's line", so
255 		 * if there was a newline resulting from the "{" before,
256 		 * it must be scanned now and ignored.
257 		 */
258 		while (isspace((unsigned char)*buf_ptr)) {
259 		    if (++buf_ptr >= buf_end)
260 			fill_buffer();
261 		    if (*buf_ptr == '\n')
262 			break;
263 		}
264 		goto sw_buffer;
265 	    }
266 	    /* FALLTHROUGH */
267 	default:		/* it is the start of a normal statement */
268 	{
269 	    int remove_newlines;
270 
271 	    remove_newlines =
272 		    /* "} else" */
273 		    (*inout_type_code == keyword_do_else && *token == 'e' &&
274 		     e_code != s_code && e_code[-1] == '}')
275 		    /* "else if" */
276 		    || (*inout_type_code == keyword_for_if_while &&
277 			*token == 'i' && *inout_last_else && opt.else_if);
278 	    if (remove_newlines)
279 		*inout_force_nl = false;
280 	    if (sc_end == NULL) {	/* ignore buffering if
281 					 * comment wasn't saved up */
282 		ps.search_brace = false;
283 		return;
284 	    }
285 	    while (sc_end > save_com && isblank((unsigned char)sc_end[-1])) {
286 		sc_end--;
287 	    }
288 	    if (opt.swallow_optional_blanklines ||
289 		(!*inout_comment_buffered && remove_newlines)) {
290 		*inout_force_nl = !remove_newlines;
291 		while (sc_end > save_com && sc_end[-1] == '\n') {
292 		    sc_end--;
293 		}
294 	    }
295 	    if (*inout_force_nl) {	/* if we should insert a nl here, put
296 					 * it into the buffer */
297 		*inout_force_nl = false;
298 		--line_no;	/* this will be re-increased when the
299 				 * newline is read from the buffer */
300 		*sc_end++ = '\n';
301 		*sc_end++ = ' ';
302 		if (opt.verbose) /* print error msg if the line was
303 				 * not already broken */
304 		    diag(0, "Line broken");
305 	    }
306 	    for (const char *t_ptr = token; *t_ptr; ++t_ptr)
307 		*sc_end++ = *t_ptr;
308 
309 	    sw_buffer:
310 	    ps.search_brace = false;	/* stop looking for start of stmt */
311 	    bp_save = buf_ptr;	/* save current input buffer */
312 	    be_save = buf_end;
313 	    buf_ptr = save_com;	/* fix so that subsequent calls to
314 				 * lexi will take tokens out of save_com */
315 	    *sc_end++ = ' ';	/* add trailing blank, just in case */
316 	    buf_end = sc_end;
317 	    sc_end = NULL;
318 	    debug_println("switched buf_ptr to save_com");
319 	    break;
320 	}
321 	}			/* end of switch */
322 	/*
323 	 * We must make this check, just in case there was an unexpected
324 	 * EOF.
325 	 */
326 	if (*inout_type_code != end_of_file) {
327 	    /*
328 	     * The only intended purpose of calling lexi() below is to
329 	     * categorize the next token in order to decide whether to
330 	     * continue buffering forthcoming tokens. Once the buffering
331 	     * is over, lexi() will be called again elsewhere on all of
332 	     * the tokens - this time for normal processing.
333 	     *
334 	     * Calling it for this purpose is a bug, because lexi() also
335 	     * changes the parser state and discards leading whitespace,
336 	     * which is needed mostly for comment-related considerations.
337 	     *
338 	     * Work around the former problem by giving lexi() a copy of
339 	     * the current parser state and discard it if the call turned
340 	     * out to be just a look ahead.
341 	     *
342 	     * Work around the latter problem by copying all whitespace
343 	     * characters into the buffer so that the later lexi() call
344 	     * will read them.
345 	     */
346 	    if (sc_end != NULL) {
347 		while (*buf_ptr == ' ' || *buf_ptr == '\t') {
348 		    *sc_end++ = *buf_ptr++;
349 		    if (sc_end >= &save_com[sc_size]) {
350 			errx(1, "input too long");
351 		    }
352 		}
353 		if (buf_ptr >= buf_end) {
354 		    fill_buffer();
355 		}
356 	    }
357 
358 	    struct parser_state transient_state;
359 	    transient_state = ps;
360 	    *inout_type_code = lexi(&transient_state);	/* read another token */
361 	    if (*inout_type_code != newline && *inout_type_code != form_feed &&
362 		*inout_type_code != comment && !transient_state.search_brace) {
363 		ps = transient_state;
364 	    }
365 	}
366     }
367 
368     *inout_last_else = 0;
369 }
370 
371 static void
372 main_init_globals(void)
373 {
374     found_err = 0;
375 
376     ps.p_stack[0] = stmt;	/* this is the parser's stack */
377     ps.last_nl = true;		/* this is true if the last thing scanned was
378 				 * a newline */
379     ps.last_token = semicolon;
380     combuf = malloc(bufsize);
381     if (combuf == NULL)
382 	err(1, NULL);
383     labbuf = malloc(bufsize);
384     if (labbuf == NULL)
385 	err(1, NULL);
386     codebuf = malloc(bufsize);
387     if (codebuf == NULL)
388 	err(1, NULL);
389     tokenbuf = malloc(bufsize);
390     if (tokenbuf == NULL)
391 	err(1, NULL);
392     alloc_typenames();
393     init_constant_tt();
394     l_com = combuf + bufsize - 5;
395     l_lab = labbuf + bufsize - 5;
396     l_code = codebuf + bufsize - 5;
397     l_token = tokenbuf + bufsize - 5;
398     combuf[0] = codebuf[0] = labbuf[0] = ' ';	/* set up code, label, and
399 						 * comment buffers */
400     combuf[1] = codebuf[1] = labbuf[1] = tokenbuf[1] = '\0';
401     opt.else_if = 1;		/* Default else-if special processing to on */
402     s_lab = e_lab = labbuf + 1;
403     s_code = e_code = codebuf + 1;
404     s_com = e_com = combuf + 1;
405     s_token = e_token = tokenbuf + 1;
406 
407     in_buffer = malloc(10);
408     if (in_buffer == NULL)
409 	err(1, NULL);
410     in_buffer_limit = in_buffer + 8;
411     buf_ptr = buf_end = in_buffer;
412     line_no = 1;
413     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
414     ps.in_or_st = false;
415     ps.bl_line = true;
416     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
417 
418     ps.pcase = false;
419     sc_end = NULL;
420     bp_save = NULL;
421     be_save = NULL;
422 
423     output = NULL;
424 
425     const char *suffix = getenv("SIMPLE_BACKUP_SUFFIX");
426     if (suffix != NULL)
427 	simple_backup_suffix = suffix;
428 }
429 
430 static void
431 main_parse_command_line(int argc, char **argv)
432 {
433     int i;
434     const char *profile_name = NULL;
435 
436 #if 0
437     max_line_length = 78;	/* -l78 */
438     lineup_to_parens = 1;	/* -lp */
439     lineup_to_parens_always = 0; /* -nlpl */
440     ps.ljust_decl = 0;		/* -ndj */
441     ps.com_ind = 33;		/* -c33 */
442     star_comment_cont = 1;	/* -sc */
443     ps.ind_size = 8;		/* -i8 */
444     verbose = 0;
445     ps.decl_indent = 16;	/* -di16 */
446     ps.local_decl_indent = -1;	/* if this is not set to some nonnegative value
447 				 * by an arg, we will set this equal to
448 				 * ps.decl_ind */
449     ps.indent_parameters = 1;	/* -ip */
450     ps.decl_com_ind = 0;	/* if this is not set to some positive value
451 				 * by an arg, we will set this equal to
452 				 * ps.com_ind */
453     btype_2 = 1;		/* -br */
454     cuddle_else = 1;		/* -ce */
455     ps.unindent_displace = 0;	/* -d0 */
456     ps.case_indent = 0;		/* -cli0 */
457     format_block_comments = 1;	/* -fcb */
458     format_col1_comments = 1;	/* -fc1 */
459     procnames_start_line = 1;	/* -psl */
460     proc_calls_space = 0;	/* -npcs */
461     comment_delimiter_on_blankline = 1;	/* -cdb */
462     ps.leave_comma = 1;		/* -nbc */
463 #endif
464 
465     for (i = 1; i < argc; ++i)
466 	if (strcmp(argv[i], "-npro") == 0)
467 	    break;
468 	else if (argv[i][0] == '-' && argv[i][1] == 'P' && argv[i][2] != '\0')
469 	    profile_name = argv[i];	/* non-empty -P (set profile) */
470     set_defaults();
471     if (i >= argc)
472 	set_profile(profile_name);
473 
474     for (i = 1; i < argc; ++i) {
475 
476 	/*
477 	 * look thru args (if any) for changes to defaults
478 	 */
479 	if (argv[i][0] != '-') {/* no flag on parameter */
480 	    if (input == NULL) {	/* we must have the input file */
481 		in_name = argv[i];	/* remember name of input file */
482 		input = fopen(in_name, "r");
483 		if (input == NULL)	/* check for open error */
484 			err(1, "%s", in_name);
485 		continue;
486 	    } else if (output == NULL) {	/* we have the output file */
487 		out_name = argv[i];	/* remember name of output file */
488 		if (strcmp(in_name, out_name) == 0) {	/* attempt to overwrite
489 							 * the file */
490 		    errx(1, "input and output files must be different");
491 		}
492 		output = fopen(out_name, "w");
493 		if (output == NULL)	/* check for create error */
494 			err(1, "%s", out_name);
495 		continue;
496 	    }
497 	    errx(1, "unknown parameter: %s", argv[i]);
498 	} else
499 	    set_option(argv[i]);
500     }				/* end of for */
501     if (input == NULL)
502 	input = stdin;
503     if (output == NULL) {
504 	if (input == stdin)
505 	    output = stdout;
506 	else {
507 	    out_name = in_name;
508 	    bakcopy();
509 	}
510     }
511 
512     if (opt.comment_column <= 1)
513 	opt.comment_column = 2;	/* don't put normal comments before column 2 */
514     if (opt.block_comment_max_line_length <= 0)
515 	opt.block_comment_max_line_length = opt.max_line_length;
516     if (opt.local_decl_indent < 0) /* if not specified by user, set this */
517 	opt.local_decl_indent = opt.decl_indent;
518     if (opt.decl_comment_column <= 0)	/* if not specified by user, set this */
519 	opt.decl_comment_column = opt.ljust_decl
520 	    ? (opt.comment_column <= 10 ? 2 : opt.comment_column - 8)
521 	    : opt.comment_column;
522     if (opt.continuation_indent == 0)
523 	opt.continuation_indent = opt.indent_size;
524 }
525 
526 static void
527 main_prepare_parsing(void)
528 {
529     fill_buffer();		/* get first batch of stuff into input buffer */
530 
531     parse(semicolon);
532 
533     char *p = buf_ptr;
534     int col = 1;
535 
536     for (;;) {
537 	if (*p == ' ')
538 	    col++;
539 	else if (*p == '\t')
540 	    col = opt.tabsize * (1 + (col - 1) / opt.tabsize) + 1;
541 	else
542 	    break;
543 	p++;
544     }
545     if (col > opt.indent_size)
546 	ps.ind_level = ps.i_l_follow = col / opt.indent_size;
547 }
548 
549 static void __attribute__((__noreturn__))
550 process_end_of_file(void)
551 {
552     if (s_lab != e_lab || s_code != e_code || s_com != e_com)
553 	dump_line();
554 
555     if (ps.tos > 1)		/* check for balanced braces */
556 	diag(1, "Stuff missing from end of file");
557 
558     if (opt.verbose) {
559 	printf("There were %d output lines and %d comments\n",
560 	       ps.out_lines, ps.out_coms);
561 	printf("(Lines with comments)/(Lines with code): %6.3f\n",
562 	       (1.0 * ps.com_lines) / code_lines);
563     }
564 
565     fflush(output);
566     exit(found_err);
567 }
568 
569 static void
570 process_comment_in_code(token_type type_code, int *inout_force_nl)
571 {
572     if (*inout_force_nl &&
573 	type_code != semicolon &&
574 	(type_code != lbrace || !opt.btype_2)) {
575 
576 	/* we should force a broken line here */
577 	if (opt.verbose)
578 	    diag(0, "Line broken");
579 	dump_line();
580 	ps.want_blank = false;	/* dont insert blank at line start */
581 	*inout_force_nl = false;
582     }
583 
584     ps.in_stmt = true;		/* turn on flag which causes an extra level of
585 				 * indentation. this is turned off by a ; or
586 				 * '}' */
587     if (s_com != e_com) {	/* the turkey has embedded a comment
588 				 * in a line. fix it */
589 	size_t len = e_com - s_com;
590 
591 	check_size_code(len + 3);
592 	*e_code++ = ' ';
593 	memcpy(e_code, s_com, len);
594 	e_code += len;
595 	*e_code++ = ' ';
596 	*e_code = '\0';		/* null terminate code sect */
597 	ps.want_blank = false;
598 	e_com = s_com;
599     }
600 }
601 
602 static void
603 process_form_feed(void)
604 {
605     ps.use_ff = true;		/* a form feed is treated much like a newline */
606     dump_line();
607     ps.want_blank = false;
608 }
609 
610 static void
611 process_newline(void)
612 {
613     if (ps.last_token != comma || ps.p_l_follow > 0
614 	|| !opt.leave_comma || ps.block_init || !break_comma || s_com != e_com) {
615 	dump_line();
616 	ps.want_blank = false;
617     }
618     ++line_no;			/* keep track of input line number */
619 }
620 
621 static void
622 process_lparen_or_lbracket(int dec_ind, int tabs_to_var, int sp_sw)
623 {
624     /* count parens to make Healy happy */
625     if (++ps.p_l_follow == nitems(ps.paren_indents)) {
626 	diag(0, "Reached internal limit of %zu unclosed parens",
627 	    nitems(ps.paren_indents));
628 	ps.p_l_follow--;
629     }
630     if (*token == '[')
631 	/* not a function pointer declaration or a function call */;
632     else if (ps.in_decl && !ps.block_init && !ps.dumped_decl_indent &&
633 	ps.procname[0] == '\0' && ps.paren_level == 0) {
634 	/* function pointer declarations */
635 	indent_declaration(dec_ind, tabs_to_var);
636 	ps.dumped_decl_indent = true;
637     } else if (ps.want_blank &&
638 	    ((ps.last_token != ident && ps.last_token != funcname) ||
639 	    opt.proc_calls_space ||
640 	    (ps.keyword == rw_sizeof ? opt.Bill_Shannon :
641 	    ps.keyword != rw_0 && ps.keyword != rw_offsetof)))
642 	*e_code++ = ' ';
643     ps.want_blank = false;
644     *e_code++ = token[0];
645 
646     ps.paren_indents[ps.p_l_follow - 1] =
647 	indentation_after_range(0, s_code, e_code);
648     debug_println("paren_indent[%d] is now %d",
649 	ps.p_l_follow - 1, ps.paren_indents[ps.p_l_follow - 1]);
650 
651     if (sp_sw && ps.p_l_follow == 1 && opt.extra_expression_indent
652 	    && ps.paren_indents[0] < 2 * opt.indent_size) {
653 	ps.paren_indents[0] = 2 * opt.indent_size;
654 	debug_println("paren_indent[0] is now %d", ps.paren_indents[0]);
655     }
656     if (ps.in_or_st && *token == '(' && ps.tos <= 2) {
657 	/*
658 	 * this is a kluge to make sure that declarations will be
659 	 * aligned right if proc decl has an explicit type on it, i.e.
660 	 * "int a(x) {..."
661 	 */
662 	parse(semicolon);	/* I said this was a kluge... */
663 	ps.in_or_st = false;	/* turn off flag for structure decl or
664 				 * initialization */
665     }
666     /* parenthesized type following sizeof or offsetof is not a cast */
667     if (ps.keyword == rw_offsetof || ps.keyword == rw_sizeof)
668 	ps.not_cast_mask |= 1 << ps.p_l_follow;
669 }
670 
671 static void
672 process_rparen_or_rbracket(int *inout_sp_sw, int *inout_force_nl,
673 			 token_type hd_type)
674 {
675     if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.not_cast_mask) {
676 	ps.last_u_d = true;
677 	ps.cast_mask &= (1 << ps.p_l_follow) - 1;
678 	ps.want_blank = opt.space_after_cast;
679     } else
680 	ps.want_blank = true;
681     ps.not_cast_mask &= (1 << ps.p_l_follow) - 1;
682 
683     if (--ps.p_l_follow < 0) {
684 	ps.p_l_follow = 0;
685 	diag(0, "Extra %c", *token);
686     }
687 
688     if (e_code == s_code)	/* if the paren starts the line */
689 	ps.paren_level = ps.p_l_follow;	/* then indent it */
690 
691     *e_code++ = token[0];
692 
693     if (*inout_sp_sw && (ps.p_l_follow == 0)) {	/* check for end of if
694 				 * (...), or some such */
695 	*inout_sp_sw = false;
696 	*inout_force_nl = true;	/* must force newline after if */
697 	ps.last_u_d = true;	/* inform lexi that a following
698 				 * operator is unary */
699 	ps.in_stmt = false;	/* dont use stmt continuation indentation */
700 
701 	parse(hd_type);		/* let parser worry about if, or whatever */
702     }
703     ps.search_brace = opt.btype_2; /* this should ensure that constructs such
704 				 * as main(){...} and int[]{...} have their
705 				 * braces put in the right place */
706 }
707 
708 static void
709 process_unary_op(int dec_ind, int tabs_to_var)
710 {
711     if (!ps.dumped_decl_indent && ps.in_decl && !ps.block_init &&
712 	ps.procname[0] == '\0' && ps.paren_level == 0) {
713 	/* pointer declarations */
714 
715 	/*
716 	 * if this is a unary op in a declaration, we should indent
717 	 * this token
718 	 */
719 	int i;
720 	for (i = 0; token[i]; ++i)
721 	    /* find length of token */;
722 	indent_declaration(dec_ind - i, tabs_to_var);
723 	ps.dumped_decl_indent = true;
724     } else if (ps.want_blank)
725 	*e_code++ = ' ';
726 
727     {
728 	size_t len = e_token - s_token;
729 
730 	check_size_code(len);
731 	memcpy(e_code, token, len);
732 	e_code += len;
733     }
734     ps.want_blank = false;
735 }
736 
737 static void
738 process_binary_op(void)
739 {
740     size_t len = e_token - s_token;
741 
742     check_size_code(len + 1);
743     if (ps.want_blank)
744 	*e_code++ = ' ';
745     memcpy(e_code, token, len);
746     e_code += len;
747 
748     ps.want_blank = true;
749 }
750 
751 static void
752 process_postfix_op(void)
753 {
754     *e_code++ = token[0];
755     *e_code++ = token[1];
756     ps.want_blank = true;
757 }
758 
759 static void
760 process_question(int *inout_squest)
761 {
762     (*inout_squest)++;		/* this will be used when a later colon
763 				 * appears so we can distinguish the
764 				 * <c>?<n>:<n> construct */
765     if (ps.want_blank)
766 	*e_code++ = ' ';
767     *e_code++ = '?';
768     ps.want_blank = true;
769 }
770 
771 static void
772 process_colon(int *inout_squest, int *inout_force_nl, int *inout_scase)
773 {
774     if (*inout_squest > 0) {	/* it is part of the <c>?<n>: <n> construct */
775 	--*inout_squest;
776 	if (ps.want_blank)
777 	    *e_code++ = ' ';
778 	*e_code++ = ':';
779 	ps.want_blank = true;
780 	return;
781     }
782     if (ps.in_or_st) {
783 	*e_code++ = ':';
784 	ps.want_blank = false;
785 	return;
786     }
787     ps.in_stmt = false;		/* seeing a label does not imply we are in a
788 				 * stmt */
789     /*
790      * turn everything so far into a label
791      */
792     {
793 	size_t len = e_code - s_code;
794 
795 	check_size_label(len + 3);
796 	memcpy(e_lab, s_code, len);
797 	e_lab += len;
798 	*e_lab++ = ':';
799 	*e_lab = '\0';
800 	e_code = s_code;
801     }
802     *inout_force_nl = ps.pcase = *inout_scase;	/* ps.pcase will be used by
803 						 * dump_line to decide how to
804 						 * indent the label. force_nl
805 						 * will force a case n: to be
806 						 * on a line by itself */
807     *inout_scase = false;
808     ps.want_blank = false;
809 }
810 
811 static void
812 process_semicolon(int *inout_scase, int *inout_squest, int const dec_ind,
813 		  int const tabs_to_var, int *inout_sp_sw,
814 		  token_type const hd_type,
815 		  int *inout_force_nl)
816 {
817     if (ps.dec_nest == 0)
818 	ps.in_or_st = false;	/* we are not in an initialization or
819 				 * structure declaration */
820     *inout_scase = false; /* these will only need resetting in an error */
821     *inout_squest = 0;
822     if (ps.last_token == rparen)
823 	ps.in_parameter_declaration = 0;
824     ps.cast_mask = 0;
825     ps.not_cast_mask = 0;
826     ps.block_init = 0;
827     ps.block_init_level = 0;
828     ps.just_saw_decl--;
829 
830     if (ps.in_decl && s_code == e_code && !ps.block_init &&
831 	!ps.dumped_decl_indent && ps.paren_level == 0) {
832 	/* indent stray semicolons in declarations */
833 	indent_declaration(dec_ind - 1, tabs_to_var);
834 	ps.dumped_decl_indent = true;
835     }
836 
837     ps.in_decl = (ps.dec_nest > 0);	/* if we were in a first level
838 						 * structure declaration, we
839 						 * arent any more */
840 
841     if ((!*inout_sp_sw || hd_type != for_exprs) && ps.p_l_follow > 0) {
842 
843 	/*
844 	 * This should be true iff there were unbalanced parens in the
845 	 * stmt.  It is a bit complicated, because the semicolon might
846 	 * be in a for stmt
847 	 */
848 	diag(1, "Unbalanced parens");
849 	ps.p_l_follow = 0;
850 	if (*inout_sp_sw) {	/* this is a check for an if, while, etc. with
851 				 * unbalanced parens */
852 	    *inout_sp_sw = false;
853 	    parse(hd_type);	/* dont lose the if, or whatever */
854 	}
855     }
856     *e_code++ = ';';
857     ps.want_blank = true;
858     ps.in_stmt = (ps.p_l_follow > 0);	/* we are no longer in the
859 				 * middle of a stmt */
860 
861     if (!*inout_sp_sw) {	/* if not if for (;;) */
862 	parse(semicolon);	/* let parser know about end of stmt */
863 	*inout_force_nl = true;/* force newline after an end of stmt */
864     }
865 }
866 
867 static void
868 process_lbrace(int *inout_force_nl, int *inout_sp_sw, token_type hd_type,
869 	       int *di_stack, int di_stack_cap, int *inout_dec_ind)
870 {
871     ps.in_stmt = false;	/* dont indent the {} */
872     if (!ps.block_init)
873 	*inout_force_nl = true;	/* force other stuff on same line as '{' onto
874 				 * new line */
875     else if (ps.block_init_level <= 0)
876 	ps.block_init_level = 1;
877     else
878 	ps.block_init_level++;
879 
880     if (s_code != e_code && !ps.block_init) {
881 	if (!opt.btype_2) {
882 	    dump_line();
883 	    ps.want_blank = false;
884 	} else if (ps.in_parameter_declaration && !ps.in_or_st) {
885 	    ps.i_l_follow = 0;
886 	    if (opt.function_brace_split) { /* dump the line prior
887 				 * to the brace ... */
888 		dump_line();
889 		ps.want_blank = false;
890 	    } else		/* add a space between the decl and brace */
891 		ps.want_blank = true;
892 	}
893     }
894     if (ps.in_parameter_declaration)
895 	prefix_blankline_requested = 0;
896 
897     if (ps.p_l_follow > 0) {	/* check for preceding unbalanced
898 				 * parens */
899 	diag(1, "Unbalanced parens");
900 	ps.p_l_follow = 0;
901 	if (*inout_sp_sw) {	/* check for unclosed if, for, etc. */
902 	    *inout_sp_sw = false;
903 	    parse(hd_type);
904 	    ps.ind_level = ps.i_l_follow;
905 	}
906     }
907     if (s_code == e_code)
908 	ps.ind_stmt = false;	/* dont put extra indentation on line
909 				 * with '{' */
910     if (ps.in_decl && ps.in_or_st) {	/* this is either a structure
911 				 * declaration or an init */
912 	di_stack[ps.dec_nest] = *inout_dec_ind;
913 	if (++ps.dec_nest == di_stack_cap) {
914 	    diag(0, "Reached internal limit of %d struct levels",
915 		 di_stack_cap);
916 	    ps.dec_nest--;
917 	}
918 	/* ?		dec_ind = 0; */
919     } else {
920 	ps.decl_on_line = false;	/* we can't be in the middle of
921 						 * a declaration, so don't do
922 						 * special indentation of
923 						 * comments */
924 	if (opt.blanklines_after_declarations_at_proctop
925 	    && ps.in_parameter_declaration)
926 	    postfix_blankline_requested = 1;
927 	ps.in_parameter_declaration = 0;
928 	ps.in_decl = false;
929     }
930     *inout_dec_ind = 0;
931     parse(lbrace);	/* let parser know about this */
932     if (ps.want_blank)	/* put a blank before '{' if '{' is not at
933 				 * start of line */
934 	*e_code++ = ' ';
935     ps.want_blank = false;
936     *e_code++ = '{';
937     ps.just_saw_decl = 0;
938 }
939 
940 static void
941 process_rbrace(int *inout_sp_sw, int *inout_dec_ind, const int *di_stack)
942 {
943     if (ps.p_stack[ps.tos] == decl && !ps.block_init)	/* semicolons can be
944 				 * omitted in declarations */
945 	parse(semicolon);
946     if (ps.p_l_follow) {	/* check for unclosed if, for, else. */
947 	diag(1, "Unbalanced parens");
948 	ps.p_l_follow = 0;
949 	*inout_sp_sw = false;
950     }
951     ps.just_saw_decl = 0;
952     ps.block_init_level--;
953     if (s_code != e_code && !ps.block_init) {	/* '}' must be first on line */
954 	if (opt.verbose)
955 	    diag(0, "Line broken");
956 	dump_line();
957     }
958     *e_code++ = '}';
959     ps.want_blank = true;
960     ps.in_stmt = ps.ind_stmt = false;
961     if (ps.dec_nest > 0) { /* we are in multi-level structure declaration */
962 	*inout_dec_ind = di_stack[--ps.dec_nest];
963 	if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
964 	    ps.just_saw_decl = 2;
965 	ps.in_decl = true;
966     }
967     prefix_blankline_requested = 0;
968     parse(rbrace);		/* let parser know about this */
969     ps.search_brace = opt.cuddle_else
970 		      && ps.p_stack[ps.tos] == if_expr_stmt
971 		      && ps.il[ps.tos] >= ps.ind_level;
972     if (ps.tos <= 1 && opt.blanklines_after_procs && ps.dec_nest <= 0)
973 	postfix_blankline_requested = 1;
974 }
975 
976 static void
977 process_keyword_do_else(int *inout_force_nl, int *inout_last_else)
978 {
979     ps.in_stmt = false;
980     if (*token == 'e') {
981 	if (e_code != s_code && (!opt.cuddle_else || e_code[-1] != '}')) {
982 	    if (opt.verbose)
983 		diag(0, "Line broken");
984 	    dump_line();	/* make sure this starts a line */
985 	    ps.want_blank = false;
986 	}
987 	*inout_force_nl = true;/* also, following stuff must go onto new line */
988 	*inout_last_else = 1;
989 	parse(keyword_else);
990     } else {
991 	if (e_code != s_code) {	/* make sure this starts a line */
992 	    if (opt.verbose)
993 		diag(0, "Line broken");
994 	    dump_line();
995 	    ps.want_blank = false;
996 	}
997 	*inout_force_nl = true;/* also, following stuff must go onto new line */
998 	*inout_last_else = 0;
999 	parse(keyword_do);
1000     }
1001 }
1002 
1003 static void
1004 process_decl(int *out_dec_ind, int *out_tabs_to_var)
1005 {
1006     parse(decl);		/* let parser worry about indentation */
1007     if (ps.last_token == rparen && ps.tos <= 1) {
1008 	if (s_code != e_code) {
1009 	    dump_line();
1010 	    ps.want_blank = 0;
1011 	}
1012     }
1013     if (ps.in_parameter_declaration && opt.indent_parameters && ps.dec_nest == 0) {
1014 	ps.ind_level = ps.i_l_follow = 1;
1015 	ps.ind_stmt = 0;
1016     }
1017     ps.in_or_st = true;		/* this might be a structure or initialization
1018 				 * declaration */
1019     ps.in_decl = ps.decl_on_line = ps.last_token != type_def;
1020     if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
1021 	ps.just_saw_decl = 2;
1022     prefix_blankline_requested = 0;
1023     int i;
1024     for (i = 0; token[i++];);	/* get length of token */
1025 
1026     if (ps.ind_level == 0 || ps.dec_nest > 0) {
1027 	/* global variable or struct member in local variable */
1028 	*out_dec_ind = opt.decl_indent > 0 ? opt.decl_indent : i;
1029 	*out_tabs_to_var = (opt.use_tabs ? opt.decl_indent > 0 : 0);
1030     } else {
1031 	/* local variable */
1032 	*out_dec_ind = opt.local_decl_indent > 0 ? opt.local_decl_indent : i;
1033 	*out_tabs_to_var = (opt.use_tabs ? opt.local_decl_indent > 0 : 0);
1034     }
1035 }
1036 
1037 static void
1038 process_ident(token_type type_code, int dec_ind, int tabs_to_var,
1039 	      int *inout_sp_sw, int *inout_force_nl, token_type hd_type)
1040 {
1041     if (ps.in_decl) {
1042 	if (type_code == funcname) {
1043 	    ps.in_decl = false;
1044 	    if (opt.procnames_start_line && s_code != e_code) {
1045 		*e_code = '\0';
1046 		dump_line();
1047 	    } else if (ps.want_blank) {
1048 		*e_code++ = ' ';
1049 	    }
1050 	    ps.want_blank = false;
1051 	} else if (!ps.block_init && !ps.dumped_decl_indent &&
1052 		   ps.paren_level == 0) { /* if we are in a declaration, we
1053 					    * must indent identifier */
1054 	    indent_declaration(dec_ind, tabs_to_var);
1055 	    ps.dumped_decl_indent = true;
1056 	    ps.want_blank = false;
1057 	}
1058     } else if (*inout_sp_sw && ps.p_l_follow == 0) {
1059 	*inout_sp_sw = false;
1060 	*inout_force_nl = true;
1061 	ps.last_u_d = true;
1062 	ps.in_stmt = false;
1063 	parse(hd_type);
1064     }
1065 }
1066 
1067 static void
1068 copy_id(void)
1069 {
1070     size_t len = e_token - s_token;
1071 
1072     check_size_code(len + 1);
1073     if (ps.want_blank)
1074 	*e_code++ = ' ';
1075     memcpy(e_code, s_token, len);
1076     e_code += len;
1077 }
1078 
1079 static void
1080 process_string_prefix(void)
1081 {
1082     size_t len = e_token - s_token;
1083 
1084     check_size_code(len + 1);
1085     if (ps.want_blank)
1086 	*e_code++ = ' ';
1087     memcpy(e_code, token, len);
1088     e_code += len;
1089 
1090     ps.want_blank = false;
1091 }
1092 
1093 static void
1094 process_period(void)
1095 {
1096     *e_code++ = '.';		/* move the period into line */
1097     ps.want_blank = false;	/* dont put a blank after a period */
1098 }
1099 
1100 static void
1101 process_comma(int dec_ind, int tabs_to_var, int *inout_force_nl)
1102 {
1103     ps.want_blank = (s_code != e_code);	/* only put blank after comma
1104 				 * if comma does not start the line */
1105     if (ps.in_decl && ps.procname[0] == '\0' && !ps.block_init &&
1106 	!ps.dumped_decl_indent && ps.paren_level == 0) {
1107 	/* indent leading commas and not the actual identifiers */
1108 	indent_declaration(dec_ind - 1, tabs_to_var);
1109 	ps.dumped_decl_indent = true;
1110     }
1111     *e_code++ = ',';
1112     if (ps.p_l_follow == 0) {
1113 	if (ps.block_init_level <= 0)
1114 	    ps.block_init = 0;
1115 	if (break_comma && (!opt.leave_comma ||
1116 			    indentation_after_range(
1117 				    compute_code_indent(), s_code, e_code)
1118 			    >= opt.max_line_length - opt.tabsize))
1119 	    *inout_force_nl = true;
1120     }
1121 }
1122 
1123 static void
1124 process_preprocessing(void)
1125 {
1126     if (s_com != e_com || s_lab != e_lab || s_code != e_code)
1127 	dump_line();
1128     check_size_label(1);
1129     *e_lab++ = '#';	/* move whole line to 'label' buffer */
1130 
1131     {
1132 	int         in_comment = 0;
1133 	int         com_start = 0;
1134 	char        quote = '\0';
1135 	int         com_end = 0;
1136 
1137 	while (*buf_ptr == ' ' || *buf_ptr == '\t') {
1138 	    buf_ptr++;
1139 	    if (buf_ptr >= buf_end)
1140 		fill_buffer();
1141 	}
1142 	while (*buf_ptr != '\n' || (in_comment && !had_eof)) {
1143 	    check_size_label(2);
1144 	    *e_lab = *buf_ptr++;
1145 	    if (buf_ptr >= buf_end)
1146 		fill_buffer();
1147 	    switch (*e_lab++) {
1148 	    case '\\':
1149 		if (!in_comment) {
1150 		    *e_lab++ = *buf_ptr++;
1151 		    if (buf_ptr >= buf_end)
1152 			fill_buffer();
1153 		}
1154 		break;
1155 	    case '/':
1156 		if (*buf_ptr == '*' && !in_comment && quote == '\0') {
1157 		    in_comment = 1;
1158 		    *e_lab++ = *buf_ptr++;
1159 		    com_start = (int)(e_lab - s_lab) - 2;
1160 		}
1161 		break;
1162 	    case '"':
1163 		if (quote == '"')
1164 		    quote = '\0';
1165 		else if (quote == '\0')
1166 		    quote = '"';
1167 		break;
1168 	    case '\'':
1169 		if (quote == '\'')
1170 		    quote = '\0';
1171 		else if (quote == '\0')
1172 		    quote = '\'';
1173 		break;
1174 	    case '*':
1175 		if (*buf_ptr == '/' && in_comment) {
1176 		    in_comment = 0;
1177 		    *e_lab++ = *buf_ptr++;
1178 		    com_end = (int)(e_lab - s_lab);
1179 		}
1180 		break;
1181 	    }
1182 	}
1183 
1184 	while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1185 	    e_lab--;
1186 	if (e_lab - s_lab == com_end && bp_save == NULL) {
1187 	    /* comment on preprocessor line */
1188 	    if (sc_end == NULL) {	/* if this is the first comment,
1189 						 * we must set up the buffer */
1190 		save_com = sc_buf;
1191 		sc_end = &save_com[0];
1192 	    } else {
1193 		*sc_end++ = '\n';	/* add newline between
1194 						 * comments */
1195 		*sc_end++ = ' ';
1196 		--line_no;
1197 	    }
1198 	    if (sc_end - save_com + com_end - com_start > sc_size)
1199 		errx(1, "input too long");
1200 	    memmove(sc_end, s_lab + com_start, com_end - com_start);
1201 	    sc_end += com_end - com_start;
1202 	    e_lab = s_lab + com_start;
1203 	    while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1204 		e_lab--;
1205 	    bp_save = buf_ptr;	/* save current input buffer */
1206 	    be_save = buf_end;
1207 	    buf_ptr = save_com;	/* fix so that subsequent calls to lexi will
1208 				 * take tokens out of save_com */
1209 	    *sc_end++ = ' ';	/* add trailing blank, just in case */
1210 	    buf_end = sc_end;
1211 	    sc_end = NULL;
1212 	    debug_println("switched buf_ptr to save_com");
1213 	}
1214 	check_size_label(1);
1215 	*e_lab = '\0';	/* null terminate line */
1216 	ps.pcase = false;
1217     }
1218 
1219     if (strncmp(s_lab, "#if", 3) == 0) { /* also ifdef, ifndef */
1220 	if ((size_t)ifdef_level < nitems(state_stack)) {
1221 	    match_state[ifdef_level].tos = -1;
1222 	    state_stack[ifdef_level++] = ps;
1223 	} else
1224 	    diag(1, "#if stack overflow");
1225     } else if (strncmp(s_lab, "#el", 3) == 0) { /* else, elif */
1226 	if (ifdef_level <= 0)
1227 	    diag(1, s_lab[3] == 'i' ? "Unmatched #elif" : "Unmatched #else");
1228 	else {
1229 	    match_state[ifdef_level - 1] = ps;
1230 	    ps = state_stack[ifdef_level - 1];
1231 	}
1232     } else if (strncmp(s_lab, "#endif", 6) == 0) {
1233 	if (ifdef_level <= 0)
1234 	    diag(1, "Unmatched #endif");
1235 	else
1236 	    ifdef_level--;
1237     } else {
1238 	static const struct directives {
1239 	    int size;
1240 	    const char *string;
1241 	} recognized[] = {
1242 		{7, "include"},
1243 		{6, "define"},
1244 		{5, "undef"},
1245 		{4, "line"},
1246 		{5, "error"},
1247 		{6, "pragma"}
1248 	};
1249 	int d = nitems(recognized);
1250 	while (--d >= 0)
1251 	    if (strncmp(s_lab + 1, recognized[d].string, recognized[d].size) == 0)
1252 		break;
1253 	if (d < 0) {
1254 	    diag(1, "Unrecognized cpp directive");
1255 	    return;
1256 	}
1257     }
1258     if (opt.blanklines_around_conditional_compilation) {
1259 	postfix_blankline_requested++;
1260 	n_real_blanklines = 0;
1261     } else {
1262 	postfix_blankline_requested = 0;
1263 	prefix_blankline_requested = 0;
1264     }
1265 
1266     /*
1267      * subsequent processing of the newline character will cause the line to
1268      * be printed
1269      */
1270 }
1271 
1272 static void __attribute__((__noreturn__))
1273 main_loop(void)
1274 {
1275     token_type type_code;
1276     int force_nl;		/* when true, code must be broken */
1277     int last_else = false;	/* true iff last keyword was an else */
1278     int         dec_ind;	/* current indentation for declarations */
1279     int         di_stack[20];	/* a stack of structure indentation levels */
1280     int		tabs_to_var;	/* true if using tabs to indent to var name */
1281     int         sp_sw;		/* when true, we are in the expression of
1282 				 * if(...), while(...), etc. */
1283     token_type  hd_type = end_of_file; /* used to store type of stmt
1284 				 * for if (...), for (...), etc */
1285     int         squest;		/* when this is positive, we have seen a ?
1286 				 * without the matching : in a <c>?<s>:<s>
1287 				 * construct */
1288     int         scase;		/* set to true when we see a case, so we will
1289 				 * know what to do with the following colon */
1290 
1291     sp_sw = force_nl = false;
1292     dec_ind = 0;
1293     di_stack[ps.dec_nest = 0] = 0;
1294     scase = false;
1295     squest = 0;
1296     tabs_to_var = 0;
1297 
1298     for (;;) {			/* this is the main loop.  it will go until we
1299 				 * reach eof */
1300 	int comment_buffered = false;
1301 
1302 	type_code = lexi(&ps);	/* lexi reads one token.  The actual
1303 				 * characters read are stored in "token". lexi
1304 				 * returns a code indicating the type of token */
1305 
1306 	/*
1307 	 * The following code moves newlines and comments following an if (),
1308 	 * while (), else, etc. up to the start of the following stmt to
1309 	 * a buffer. This allows proper handling of both kinds of brace
1310 	 * placement (-br, -bl) and cuddling "else" (-ce).
1311 	 */
1312 	search_brace(&type_code, &force_nl, &comment_buffered, &last_else);
1313 
1314 	if (type_code == end_of_file) {
1315 	    process_end_of_file();
1316 	    /* NOTREACHED */
1317 	}
1318 
1319 	if (
1320 		type_code != comment &&
1321 		type_code != newline &&
1322 		type_code != preprocessing &&
1323 		type_code != form_feed) {
1324 	    process_comment_in_code(type_code, &force_nl);
1325 
1326 	} else if (type_code != comment) /* preserve force_nl thru a comment */
1327 	    force_nl = false;	/* cancel forced newline after newline, form
1328 				 * feed, etc */
1329 
1330 
1331 
1332 	/*-----------------------------------------------------*\
1333 	|	   do switch on type of token scanned		|
1334 	\*-----------------------------------------------------*/
1335 	check_size_code(3);	/* maximum number of increments of e_code
1336 				 * before the next check_size_code or
1337 				 * dump_line() is 2. After that there's the
1338 				 * final increment for the null character. */
1339 	switch (type_code) {	/* now, decide what to do with the token */
1340 
1341 	case form_feed:		/* found a form feed in line */
1342 	    process_form_feed();
1343 	    break;
1344 
1345 	case newline:
1346 	    process_newline();
1347 	    break;
1348 
1349 	case lparen:		/* got a '(' or '[' */
1350 	    process_lparen_or_lbracket(dec_ind, tabs_to_var, sp_sw);
1351 	    break;
1352 
1353 	case rparen:		/* got a ')' or ']' */
1354 	    process_rparen_or_rbracket(&sp_sw, &force_nl, hd_type);
1355 	    break;
1356 
1357 	case unary_op:		/* this could be any unary operation */
1358 	    process_unary_op(dec_ind, tabs_to_var);
1359 	    break;
1360 
1361 	case binary_op:		/* any binary operation */
1362 	    process_binary_op();
1363 	    break;
1364 
1365 	case postfix_op:	/* got a trailing ++ or -- */
1366 	    process_postfix_op();
1367 	    break;
1368 
1369 	case question:		/* got a ? */
1370 	    process_question(&squest);
1371 	    break;
1372 
1373 	case case_label:	/* got word 'case' or 'default' */
1374 	    scase = true;	/* so we can process the later colon properly */
1375 	    goto copy_id;
1376 
1377 	case colon:		/* got a ':' */
1378 	    process_colon(&squest, &force_nl, &scase);
1379 	    break;
1380 
1381 	case semicolon:		/* got a ';' */
1382 	    process_semicolon(&scase, &squest, dec_ind, tabs_to_var, &sp_sw,
1383 		hd_type, &force_nl);
1384 	    break;
1385 
1386 	case lbrace:		/* got a '{' */
1387 	    process_lbrace(&force_nl, &sp_sw, hd_type, di_stack,
1388 		(int)nitems(di_stack), &dec_ind);
1389 	    break;
1390 
1391 	case rbrace:		/* got a '}' */
1392 	    process_rbrace(&sp_sw, &dec_ind, di_stack);
1393 	    break;
1394 
1395 	case switch_expr:	/* got keyword "switch" */
1396 	    sp_sw = true;
1397 	    hd_type = switch_expr; /* keep this for when we have seen the
1398 				 * expression */
1399 	    goto copy_id;	/* go move the token into buffer */
1400 
1401 	case keyword_for_if_while:
1402 	    sp_sw = true;	/* the interesting stuff is done after the
1403 				 * expression is scanned */
1404 	    hd_type = (*token == 'i' ? if_expr :
1405 		       (*token == 'w' ? while_expr : for_exprs));
1406 
1407 	    /* remember the type of header for later use by parser */
1408 	    goto copy_id;	/* copy the token into line */
1409 
1410 	case keyword_do_else:
1411 	    process_keyword_do_else(&force_nl, &last_else);
1412 	    goto copy_id;	/* move the token into line */
1413 
1414 	case type_def:
1415 	case storage_class:
1416 	    prefix_blankline_requested = 0;
1417 	    goto copy_id;
1418 
1419 	case keyword_struct_union_enum:
1420 	    if (ps.p_l_follow > 0)
1421 		goto copy_id;
1422 	    /* FALLTHROUGH */
1423 	case decl:		/* we have a declaration type (int, etc.) */
1424 	    process_decl(&dec_ind, &tabs_to_var);
1425 	    goto copy_id;
1426 
1427 	case funcname:
1428 	case ident:		/* got an identifier or constant */
1429 	    process_ident(type_code, dec_ind, tabs_to_var, &sp_sw, &force_nl,
1430 		hd_type);
1431     copy_id:
1432 	    copy_id();
1433 	    if (type_code != funcname)
1434 		ps.want_blank = true;
1435 	    break;
1436 
1437 	case string_prefix:
1438 	    process_string_prefix();
1439 	    break;
1440 
1441 	case period:
1442 	    process_period();
1443 	    break;
1444 
1445 	case comma:
1446 	    process_comma(dec_ind, tabs_to_var, &force_nl);
1447 	    break;
1448 
1449 	case preprocessing:	/* '#' */
1450 	    process_preprocessing();
1451 	    break;
1452 	case comment:		/* the initial '/' '*' or '//' of a comment */
1453 	    process_comment();
1454 	    break;
1455 
1456 	default:
1457 	    break;
1458 	}			/* end of big switch stmt */
1459 
1460 	*e_code = '\0';		/* make sure code section is null terminated */
1461 	if (type_code != comment &&
1462 	    type_code != newline &&
1463 	    type_code != preprocessing)
1464 	    ps.last_token = type_code;
1465     }
1466 }
1467 
1468 int
1469 main(int argc, char **argv)
1470 {
1471     main_init_globals();
1472     main_parse_command_line(argc, argv);
1473 #if HAVE_CAPSICUM
1474     init_capsicum();
1475 #endif
1476     main_prepare_parsing();
1477     main_loop();
1478 }
1479 
1480 /*
1481  * copy input file to backup file if in_name is /blah/blah/blah/file, then
1482  * backup file will be ".Bfile" then make the backup file the input and
1483  * original input file the output
1484  */
1485 static void
1486 bakcopy(void)
1487 {
1488     ssize_t n;
1489     int bakchn;
1490     char buff[8 * 1024];
1491     const char *p;
1492 
1493     /* construct file name .Bfile */
1494     for (p = in_name; *p; p++);	/* skip to end of string */
1495     while (p > in_name && *p != '/')	/* find last '/' */
1496 	p--;
1497     if (*p == '/')
1498 	p++;
1499     sprintf(bakfile, "%s%s", p, simple_backup_suffix);
1500 
1501     /* copy in_name to backup file */
1502     bakchn = creat(bakfile, 0600);
1503     if (bakchn < 0)
1504 	err(1, "%s", bakfile);
1505     while ((n = read(fileno(input), buff, sizeof(buff))) > 0)
1506 	if (write(bakchn, buff, (size_t)n) != n)
1507 	    err(1, "%s", bakfile);
1508     if (n < 0)
1509 	err(1, "%s", in_name);
1510     close(bakchn);
1511     fclose(input);
1512 
1513     /* re-open backup file as the input file */
1514     input = fopen(bakfile, "r");
1515     if (input == NULL)
1516 	err(1, "%s", bakfile);
1517     /* now the original input file will be the output */
1518     output = fopen(in_name, "w");
1519     if (output == NULL) {
1520 	unlink(bakfile);
1521 	err(1, "%s", in_name);
1522     }
1523 }
1524 
1525 static void
1526 indent_declaration(int cur_dec_ind, int tabs_to_var)
1527 {
1528     int pos = (int)(e_code - s_code);
1529     char *startpos = e_code;
1530 
1531     /*
1532      * get the tab math right for indentations that are not multiples of tabsize
1533      */
1534     if ((ps.ind_level * opt.indent_size) % opt.tabsize != 0) {
1535 	pos += (ps.ind_level * opt.indent_size) % opt.tabsize;
1536 	cur_dec_ind += (ps.ind_level * opt.indent_size) % opt.tabsize;
1537     }
1538     if (tabs_to_var) {
1539 	int tpos;
1540 
1541 	check_size_code(cur_dec_ind / opt.tabsize);
1542 	while ((tpos = opt.tabsize * (1 + pos / opt.tabsize)) <= cur_dec_ind) {
1543 	    *e_code++ = '\t';
1544 	    pos = tpos;
1545 	}
1546     }
1547     check_size_code(cur_dec_ind - pos + 1);
1548     while (pos < cur_dec_ind) {
1549 	*e_code++ = ' ';
1550 	pos++;
1551     }
1552     if (e_code == startpos && ps.want_blank) {
1553 	*e_code++ = ' ';
1554 	ps.want_blank = false;
1555     }
1556 }
1557 
1558 #ifdef debug
1559 void
1560 debug_printf(const char *fmt, ...)
1561 {
1562     FILE *f = output == stdout ? stderr : stdout;
1563     va_list ap;
1564 
1565     va_start(ap, fmt);
1566     vfprintf(f, fmt, ap);
1567     va_end(ap);
1568 }
1569 
1570 void
1571 debug_println(const char *fmt, ...)
1572 {
1573     FILE *f = output == stdout ? stderr : stdout;
1574     va_list ap;
1575 
1576     va_start(ap, fmt);
1577     vfprintf(f, fmt, ap);
1578     va_end(ap);
1579     fprintf(f, "\n");
1580 }
1581 
1582 void
1583 debug_vis_range(const char *prefix, const char *s, const char *e,
1584 		const char *suffix)
1585 {
1586     debug_printf("%s", prefix);
1587     for (const char *p = s; p < e; p++) {
1588 	if (isprint((unsigned char)*p) && *p != '\\' && *p != '"')
1589 	    debug_printf("%c", *p);
1590 	else if (*p == '\n')
1591 	    debug_printf("\\n");
1592 	else if (*p == '\t')
1593 	    debug_printf("\\t");
1594 	else
1595 	    debug_printf("\\x%02x", *p);
1596     }
1597     debug_printf("%s", suffix);
1598 }
1599 #endif
1600