Home | History | Annotate | Line # | Download | only in indent
indent.c revision 1.24
      1 /*	$NetBSD: indent.c,v 1.24 2019/02/03 03:19:29 mrg 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
     76 static char sccsid[] = "@(#)indent.c	5.17 (Berkeley) 6/7/93";
     77 #else
     78 __RCSID("$NetBSD: indent.c,v 1.24 2019/02/03 03:19:29 mrg 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 
     97 const char *in_name = "Standard Input";		/* will always point to name of
     98 						 * input file */
     99 const char *out_name = "Standard Output";	/* will always point to name of
    100 						 * output file */
    101 char    bakfile[MAXPATHLEN] = "";
    102 
    103 int
    104 main(int argc, char **argv)
    105 {
    106 
    107 	extern int found_err;	/* flag set in diag() on error */
    108 	int     dec_ind;	/* current indentation for declarations */
    109 	int     di_stack[20];	/* a stack of structure indentation levels */
    110 	int     flushed_nl;	/* used when buffering up comments to remember
    111 				 * that a newline was passed over */
    112 	int     force_nl;	/* when true, code must be broken */
    113 	int     hd_type;	/* used to store type of stmt for if (...),
    114 				 * for (...), etc */
    115 	int     i;		/* local loop counter */
    116 	int     scase;		/* set to true when we see a case, so we will
    117 				 * know what to do with the following colon */
    118 	int     sp_sw;		/* when true, we are in the expressin of
    119 				 * if(...), while(...), etc. */
    120 	int     squest;		/* when this is positive, we have seen a ?
    121 				 * without the matching : in a <c>?<s>:<s>
    122 				 * construct */
    123 	const char *t_ptr;	/* used for copying tokens */
    124 	int	tabs_to_var = 0; /* true if using tabs to indent to var name */
    125 	int     type_code;	/* the type of token, returned by lexi */
    126 
    127 	int     last_else = 0;	/* true iff last keyword was an else */
    128 
    129 
    130 	/*-----------------------------------------------*\
    131         |		      INITIALIZATION		      |
    132         \*-----------------------------------------------*/
    133 
    134 	if (!setlocale(LC_ALL, ""))
    135 		warnx("can't set locale.");
    136 
    137 	hd_type = 0;
    138 	ps.p_stack[0] = stmt;	/* this is the parser's stack */
    139 	ps.last_nl = true;	/* this is true if the last thing scanned was
    140 				 * a newline */
    141 	ps.last_token = semicolon;
    142 	combuf = (char *) malloc(bufsize);
    143 	labbuf = (char *) malloc(bufsize);
    144 	codebuf = (char *) malloc(bufsize);
    145 	tokenbuf = (char *) malloc(bufsize);
    146 	l_com = combuf + bufsize - 5;
    147 	l_lab = labbuf + bufsize - 5;
    148 	l_code = codebuf + bufsize - 5;
    149 	l_token = tokenbuf + bufsize - 5;
    150 	combuf[0] = codebuf[0] = labbuf[0] = ' ';	/* set up code, label,
    151 							 * and comment buffers */
    152 	combuf[1] = codebuf[1] = labbuf[1] = '\0';
    153 	ps.else_if = 1;		/* Default else-if special processing to on */
    154 	s_lab = e_lab = labbuf + 1;
    155 	s_code = e_code = codebuf + 1;
    156 	s_com = e_com = combuf + 1;
    157 	s_token = e_token = tokenbuf + 1;
    158 
    159 	in_buffer = (char *) malloc(10);
    160 	in_buffer_limit = in_buffer + 8;
    161 	buf_ptr = buf_end = in_buffer;
    162 	line_no = 1;
    163 	had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
    164 	sp_sw = force_nl = false;
    165 	ps.in_or_st = false;
    166 	ps.bl_line = true;
    167 	dec_ind = 0;
    168 	di_stack[ps.dec_nest = 0] = 0;
    169 	ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
    170 
    171 
    172 	scase = ps.pcase = false;
    173 	squest = 0;
    174 	sc_end = 0;
    175 	bp_save = 0;
    176 	be_save = 0;
    177 
    178 	output = 0;
    179 
    180 
    181 
    182 	/*--------------------------------------------------*\
    183         |   		COMMAND LINE SCAN		 |
    184         \*--------------------------------------------------*/
    185 
    186 #ifdef undef
    187 	max_col = 78;		/* -l78 */
    188 	lineup_to_parens = 1;	/* -lp */
    189 	ps.ljust_decl = 0;	/* -ndj */
    190 	ps.com_ind = 33;	/* -c33 */
    191 	star_comment_cont = 1;	/* -sc */
    192 	ps.ind_size = 8;	/* -i8 */
    193 	verbose = 0;
    194 	ps.decl_indent = 16;	/* -di16 */
    195 	ps.indent_parameters = 1;	/* -ip */
    196 	ps.decl_com_ind = 0;	/* if this is not set to some positive value
    197 				 * by an arg, we will set this equal to
    198 				 * ps.com_ind */
    199 	btype_2 = 1;		/* -br */
    200 	cuddle_else = 1;	/* -ce */
    201 	ps.unindent_displace = 0;	/* -d0 */
    202 	ps.case_indent = 0;	/* -cli0 */
    203 	format_col1_comments = 1;	/* -fc1 */
    204 	procnames_start_line = 1;	/* -psl */
    205 	proc_calls_space = 0;	/* -npcs */
    206 	comment_delimiter_on_blankline = 1;	/* -cdb */
    207 	ps.leave_comma = 1;	/* -nbc */
    208 #endif
    209 
    210 	for (i = 1; i < argc; ++i)
    211 		if (strcmp(argv[i], "-npro") == 0)
    212 			break;
    213 	set_defaults();
    214 	if (i >= argc)
    215 		set_profile();
    216 
    217 	for (i = 1; i < argc; ++i) {
    218 
    219 		/*
    220 		 * look thru args (if any) for changes to defaults
    221 		 */
    222 		if (argv[i][0] != '-') {	/* no flag on parameter */
    223 			if (input == 0) {	/* we must have the input file */
    224 				in_name = argv[i];	/* remember name of
    225 							 * input file */
    226 				input = fopen(in_name, "r");
    227 				if (input == 0)	/* check for open error */
    228 					err(1, "%s", in_name);
    229 				continue;
    230 			} else
    231 				if (output == 0) {	/* we have the output
    232 							 * file */
    233 					out_name = argv[i];	/* remember name of
    234 								 * output file */
    235 					if (strcmp(in_name, out_name) == 0) {	/* attempt to overwrite
    236 										 * the file */
    237 						errx(1, "input and output files must be different");
    238 					}
    239 					output = fopen(out_name, "w");
    240 					if (output == 0)	/* check for create
    241 								 * error */
    242 						err(1, "%s", out_name);
    243 					continue;
    244 				}
    245 			errx(1, "unknown parameter: %s", argv[i]);
    246 		} else
    247 			set_option(argv[i]);
    248 	}			/* end of for */
    249 	if (input == 0) {
    250 		input = stdin;
    251 	}
    252 	if (output == 0) {
    253 		if (troff || input == stdin)
    254 			output = stdout;
    255 		else {
    256 			out_name = in_name;
    257 			bakcopy();
    258 		}
    259 	}
    260 	if (ps.com_ind <= 1)
    261 		ps.com_ind = 2;	/* don't put normal comments before column 2 */
    262 	if (troff) {
    263 		if (bodyf.font[0] == 0)
    264 			parsefont(&bodyf, "R");
    265 		if (scomf.font[0] == 0)
    266 			parsefont(&scomf, "I");
    267 		if (blkcomf.font[0] == 0)
    268 			blkcomf = scomf, blkcomf.size += 2;
    269 		if (boxcomf.font[0] == 0)
    270 			boxcomf = blkcomf;
    271 		if (stringf.font[0] == 0)
    272 			parsefont(&stringf, "L");
    273 		if (keywordf.font[0] == 0)
    274 			parsefont(&keywordf, "B");
    275 		writefdef(&bodyf, 'B');
    276 		writefdef(&scomf, 'C');
    277 		writefdef(&blkcomf, 'L');
    278 		writefdef(&boxcomf, 'X');
    279 		writefdef(&stringf, 'S');
    280 		writefdef(&keywordf, 'K');
    281 	}
    282 	if (block_comment_max_col <= 0)
    283 		block_comment_max_col = max_col;
    284 	if (ps.decl_com_ind <= 0)	/* if not specified by user, set this */
    285 		ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
    286 	if (continuation_indent == 0)
    287 		continuation_indent = ps.ind_size;
    288 	fill_buffer();		/* get first batch of stuff into input buffer */
    289 
    290 	parse(semicolon);
    291 	{
    292 		char   *p = buf_ptr;
    293 		int     col = 1;
    294 
    295 		while (1) {
    296 			if (*p == ' ')
    297 				col++;
    298 			else
    299 				if (*p == '\t')
    300 					col = ((col - 1) & ~7) + 9;
    301 				else
    302 					break;
    303 			p++;
    304 		}
    305 		if (col > ps.ind_size)
    306 			ps.ind_level = ps.i_l_follow = col / ps.ind_size;
    307 	}
    308 	if (troff) {
    309 		const char   *p = in_name, *beg = in_name;
    310 
    311 		while (*p)
    312 			if (*p++ == '/')
    313 				beg = p;
    314 		fprintf(output, ".Fn \"%s\"\n", beg);
    315 	}
    316 	/*
    317          * START OF MAIN LOOP
    318          */
    319 
    320 	while (1) {		/* this is the main loop.  it will go until we
    321 				 * reach eof */
    322 		int     is_procname;
    323 
    324 		type_code = lexi();	/* lexi reads one token.  The actual
    325 					 * characters read are stored in
    326 					 * "token". lexi returns a code
    327 					 * indicating the type of token */
    328 		is_procname = ps.procname[0];
    329 
    330 		/*
    331 		 * The following code moves everything following an if (), while (),
    332 		 * else, etc. up to the start of the following stmt to a buffer. This
    333 		 * allows proper handling of both kinds of brace placement.
    334 		 */
    335 
    336 		flushed_nl = false;
    337 		while (ps.search_brace) {	/* if we scanned an if(),
    338 						 * while(), etc., we might
    339 						 * need to copy stuff into a
    340 						 * buffer we must loop,
    341 						 * copying stuff into
    342 						 * save_com, until we find the
    343 						 * start of the stmt which
    344 						 * follows the if, or whatever */
    345 			switch (type_code) {
    346 			case newline:
    347 				++line_no;
    348 				flushed_nl = true;
    349 				/* FALLTHROUGH */
    350 			case form_feed:
    351 				break;	/* form feeds and newlines found here
    352 					 * will be ignored */
    353 
    354 			case lbrace:	/* this is a brace that starts the
    355 					 * compound stmt */
    356 				if (sc_end == 0) {	/* ignore buffering if a
    357 							 * comment wasn't stored
    358 							 * up */
    359 					ps.search_brace = false;
    360 					goto check_type;
    361 				}
    362 				if (btype_2) {
    363 					save_com[0] = '{';	/* we either want to put
    364 								 * the brace right after
    365 								 * the if */
    366 					goto sw_buffer;	/* go to common code to
    367 							 * get out of this loop */
    368 				}
    369 				/* FALLTHROUGH */
    370 			case comment:	/* we have a comment, so we must copy
    371 					 * it into the buffer */
    372 				if (!flushed_nl || sc_end != 0) {
    373 					if (sc_end == 0) {	/* if this is the first
    374 								 * comment, we must set
    375 								 * up the buffer */
    376 						save_com[0] = save_com[1] = ' ';
    377 						sc_end = &(save_com[2]);
    378 					} else {
    379 						*sc_end++ = '\n';	/* add newline between
    380 									 * comments */
    381 						*sc_end++ = ' ';
    382 						--line_no;
    383 					}
    384 					*sc_end++ = '/';	/* copy in start of
    385 								 * comment */
    386 					*sc_end++ = '*';
    387 
    388 					for (;;) {	/* loop until we get to
    389 							 * the end of the
    390 							 * comment */
    391 						*sc_end = *buf_ptr++;
    392 						if (buf_ptr >= buf_end)
    393 							fill_buffer();
    394 
    395 						if (*sc_end++ == '*' && *buf_ptr == '/')
    396 							break;	/* we are at end of
    397 								 * comment */
    398 
    399 						if (sc_end >= &(save_com[sc_size])) {	/* check for temp buffer
    400 											 * overflow */
    401 							diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
    402 							fflush(output);
    403 							exit(1);
    404 						}
    405 					}
    406 					*sc_end++ = '/';	/* add ending slash */
    407 					if (++buf_ptr >= buf_end)	/* get past / in buffer */
    408 						fill_buffer();
    409 					break;
    410 				}
    411 				/* FALLTHROUGH */
    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 wasn't 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;
    477 check_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;	/* don't 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;	/* don't 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
    790 							 * aren't 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);	/* don't lose the if,
    806 							 * or 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;	/* don't 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;	/* don't 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 can't be in the
    870 								 * middle of a
    871 								 * declaration, so don't
    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 			tabs_to_var = (use_tabs ? ps.decl_indent > 0 : 0);
   1002 			goto copy_id;
   1003 
   1004 		case ident:	/* got an identifier or constant */
   1005 			if (ps.in_decl) {	/* if we are in a declaration,
   1006 						 * we must indent identifier */
   1007 				if (ps.want_blank)
   1008 					*e_code++ = ' ';
   1009 				ps.want_blank = false;
   1010 				if (is_procname == 0 || !procnames_start_line) {
   1011 					if (!ps.block_init) {
   1012 						if (troff && !ps.dumped_decl_indent) {
   1013 							sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
   1014 							ps.dumped_decl_indent = 1;
   1015 							e_code += strlen(e_code);
   1016 							CHECK_SIZE_CODE;
   1017 						} else {
   1018 							int cur_dec_ind;
   1019 							int pos, startpos;
   1020 
   1021 							/*
   1022 							 * in order to get the tab math right for
   1023 							 * indentations that are not multiples of 8 we
   1024 							 * need to modify both startpos and dec_ind
   1025 							 * (cur_dec_ind) here by eight minus the
   1026 							 * remainder of the current starting column
   1027 							 * divided by eight. This seems to be a
   1028 							 * properly working fix
   1029 							 */
   1030 							startpos = e_code - s_code;
   1031 							cur_dec_ind = dec_ind;
   1032 							pos = startpos;
   1033 							if ((ps.ind_level * ps.ind_size) % 8 != 0) {
   1034 								pos += (ps.ind_level * ps.ind_size) % 8;
   1035 								cur_dec_ind += (ps.ind_level * ps.ind_size) % 8;
   1036 							}
   1037 
   1038 							if (tabs_to_var) {
   1039 								while ((pos & ~7) + 8 <= cur_dec_ind) {
   1040 									CHECK_SIZE_CODE;
   1041 									*e_code++ = '\t';
   1042 									pos = (pos & ~7) + 8;
   1043 								}
   1044 							}
   1045 							while (pos < cur_dec_ind) {
   1046 								CHECK_SIZE_CODE;
   1047 								*e_code++ = ' ';
   1048 								pos++;
   1049 							}
   1050 							if (ps.want_blank && e_code - s_code == startpos)
   1051 								*e_code++ = ' ';
   1052 							ps.want_blank = false;
   1053 						}
   1054 					}
   1055 				} else {
   1056 					if (dec_ind && s_code != e_code)
   1057 						dump_line();
   1058 					dec_ind = 0;
   1059 					ps.want_blank = false;
   1060 				}
   1061 			} else
   1062 				if (sp_sw && ps.p_l_follow == 0) {
   1063 					sp_sw = false;
   1064 					force_nl = true;
   1065 					ps.last_u_d = true;
   1066 					ps.in_stmt = false;
   1067 					parse(hd_type);
   1068 				}
   1069 	copy_id:
   1070 			if (ps.want_blank)
   1071 				*e_code++ = ' ';
   1072 			if (troff && ps.its_a_keyword) {
   1073 				e_code = chfont(&bodyf, &keywordf, e_code);
   1074 				for (t_ptr = token; *t_ptr; ++t_ptr) {
   1075 					CHECK_SIZE_CODE;
   1076 					*e_code++ = keywordf.allcaps
   1077 					    ? toupper((unsigned char)*t_ptr)
   1078 					    : *t_ptr;
   1079 				}
   1080 				e_code = chfont(&keywordf, &bodyf, e_code);
   1081 			} else
   1082 				for (t_ptr = token; *t_ptr; ++t_ptr) {
   1083 					CHECK_SIZE_CODE;
   1084 					*e_code++ = *t_ptr;
   1085 				}
   1086 			ps.want_blank = true;
   1087 			break;
   1088 
   1089 		case period:	/* treat a period kind of like a binary
   1090 				 * operation */
   1091 			*e_code++ = '.';	/* move the period into line */
   1092 			ps.want_blank = false;	/* don't put a blank after a
   1093 						 * period */
   1094 			break;
   1095 
   1096 		case comma:
   1097 			ps.want_blank = (s_code != e_code);	/* only put blank after
   1098 								 * comma if comma does
   1099 								 * not start the line */
   1100 			if (ps.in_decl && is_procname == 0 && !ps.block_init)
   1101 				while ((e_code - s_code) < (dec_ind - 1)) {
   1102 					CHECK_SIZE_CODE;
   1103 					*e_code++ = ' ';
   1104 				}
   1105 
   1106 			*e_code++ = ',';
   1107 			if (ps.p_l_follow == 0) {
   1108 				if (ps.block_init_level <= 0)
   1109 					ps.block_init = 0;
   1110 				if (break_comma && (!ps.leave_comma || compute_code_target() + (e_code - s_code) > max_col - 8))
   1111 					force_nl = true;
   1112 			}
   1113 			break;
   1114 
   1115 		case preesc:	/* got the character '#' */
   1116 			if ((s_com != e_com) ||
   1117 			    (s_lab != e_lab) ||
   1118 			    (s_code != e_code))
   1119 				dump_line();
   1120 			*e_lab++ = '#';	/* move whole line to 'label' buffer */
   1121 			{
   1122 				int     in_comment = 0;
   1123 				int     com_start = 0;
   1124 				char    quote = 0;
   1125 				int     com_end = 0;
   1126 
   1127 				while (*buf_ptr == ' ' || *buf_ptr == '\t') {
   1128 					buf_ptr++;
   1129 					if (buf_ptr >= buf_end)
   1130 						fill_buffer();
   1131 				}
   1132 				while (*buf_ptr != '\n' || in_comment) {
   1133 					CHECK_SIZE_LAB;
   1134 					*e_lab = *buf_ptr++;
   1135 					if (buf_ptr >= buf_end)
   1136 						fill_buffer();
   1137 					switch (*e_lab++) {
   1138 					case BACKSLASH:
   1139 						if (troff)
   1140 							*e_lab++ = BACKSLASH;
   1141 						if (!in_comment) {
   1142 							*e_lab++ = *buf_ptr++;
   1143 							if (buf_ptr >= buf_end)
   1144 								fill_buffer();
   1145 						}
   1146 						break;
   1147 					case '/':
   1148 						if (*buf_ptr == '*' && !in_comment && !quote) {
   1149 							in_comment = 1;
   1150 							*e_lab++ = *buf_ptr++;
   1151 							com_start = e_lab - s_lab - 2;
   1152 						}
   1153 						break;
   1154 					case '"':
   1155 						if (quote == '"')
   1156 							quote = 0;
   1157 						break;
   1158 					case '\'':
   1159 						if (quote == '\'')
   1160 							quote = 0;
   1161 						break;
   1162 					case '*':
   1163 						if (*buf_ptr == '/' && in_comment) {
   1164 							in_comment = 0;
   1165 							*e_lab++ = *buf_ptr++;
   1166 							com_end = e_lab - s_lab;
   1167 						}
   1168 						break;
   1169 					}
   1170 				}
   1171 
   1172 				while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
   1173 					e_lab--;
   1174 				if (e_lab - s_lab == com_end && bp_save == 0) {	/* comment on
   1175 										 * preprocessor line */
   1176 					if (sc_end == 0)	/* if this is the first
   1177 								 * comment, we must set
   1178 								 * up the buffer */
   1179 						sc_end = &(save_com[0]);
   1180 					else {
   1181 						*sc_end++ = '\n';	/* add newline between
   1182 									 * comments */
   1183 						*sc_end++ = ' ';
   1184 						--line_no;
   1185 					}
   1186 					memmove(sc_end, s_lab + com_start, com_end - com_start);
   1187 					sc_end += com_end - com_start;
   1188 					if (sc_end >= &save_com[sc_size])
   1189 						abort();
   1190 					e_lab = s_lab + com_start;
   1191 					while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
   1192 						e_lab--;
   1193 					bp_save = buf_ptr;	/* save current input
   1194 								 * buffer */
   1195 					be_save = buf_end;
   1196 					buf_ptr = save_com;	/* fix so that
   1197 								 * subsequent calls to
   1198 								 * lexi will take tokens
   1199 								 * out of save_com */
   1200 					*sc_end++ = ' ';	/* add trailing blank,
   1201 								 * just in case */
   1202 					buf_end = sc_end;
   1203 					sc_end = 0;
   1204 				}
   1205 				*e_lab = '\0';	/* null terminate line */
   1206 				ps.pcase = false;
   1207 			}
   1208 
   1209 			if (strncmp(s_lab, "#if", 3) == 0) {
   1210 				if (blanklines_around_conditional_compilation) {
   1211 					int     c;
   1212 					prefix_blankline_requested++;
   1213 					while ((c = getc(input)) == '\n');
   1214 					ungetc(c, input);
   1215 				}
   1216 				if (ifdef_level < (int)(sizeof state_stack / sizeof state_stack[0])) {
   1217 					match_state[ifdef_level].tos = -1;
   1218 					state_stack[ifdef_level++] = ps;
   1219 				} else
   1220 					diag(1, "#if stack overflow");
   1221 			} else
   1222 				if (strncmp(s_lab, "#else", 5) == 0) {
   1223 					if (ifdef_level <= 0)
   1224 						diag(1, "Unmatched #else");
   1225 					else {
   1226 						match_state[ifdef_level - 1] = ps;
   1227 						ps = state_stack[ifdef_level - 1];
   1228 					}
   1229 				} else
   1230 					if (strncmp(s_lab, "#endif", 6) == 0) {
   1231 						if (ifdef_level <= 0)
   1232 							diag(1, "Unmatched #endif");
   1233 						else {
   1234 							ifdef_level--;
   1235 
   1236 #ifdef undef
   1237 							/*
   1238 						         * This match needs to be more intelligent before the
   1239 						         * message is useful
   1240 						         */
   1241 							if (match_state[ifdef_level].tos >= 0
   1242 							    && memcmp(&ps, &match_state[ifdef_level], sizeof ps))
   1243 								diag(0, "Syntactically inconsistant #ifdef alternatives.");
   1244 #endif
   1245 						}
   1246 						if (blanklines_around_conditional_compilation) {
   1247 							postfix_blankline_requested++;
   1248 							n_real_blanklines = 0;
   1249 						}
   1250 					}
   1251 			break;	/* subsequent processing of the newline
   1252 				 * character will cause the line to be printed */
   1253 
   1254 		case comment:	/* we have gotten a start comment */
   1255 			/* this is a biggie */
   1256 			if (flushed_nl) {	/* we should force a broken
   1257 						 * line here */
   1258 				flushed_nl = false;
   1259 				dump_line();
   1260 				ps.want_blank = false;	/* don't insert blank at
   1261 							 * line start */
   1262 				force_nl = false;
   1263 			}
   1264 			pr_comment();
   1265 			break;
   1266 		}		/* end of big switch stmt */
   1267 
   1268 		*e_code = '\0';	/* make sure code section is null terminated */
   1269 		if (type_code != comment && type_code != newline && type_code != preesc)
   1270 			ps.last_token = type_code;
   1271 	}			/* end of main while (1) loop */
   1272 }
   1273 /*
   1274  * copy input file to backup file if in_name is /blah/blah/blah/file, then
   1275  * backup file will be ".Bfile" then make the backup file the input and
   1276  * original input file the output
   1277  */
   1278 void
   1279 bakcopy(void)
   1280 {
   1281 	int     n, bakchn;
   1282 	char    buff[8 * 1024];
   1283 	const char *p;
   1284 
   1285 	/* construct file name .Bfile */
   1286 	for (p = in_name; *p; p++);	/* skip to end of string */
   1287 	while (p > in_name && *p != '/')	/* find last '/' */
   1288 		p--;
   1289 	if (*p == '/')
   1290 		p++;
   1291 	sprintf(bakfile, "%s.BAK", p);
   1292 
   1293 	/* copy in_name to backup file */
   1294 	bakchn = creat(bakfile, 0600);
   1295 	if (bakchn < 0)
   1296 		err(1, "%s", bakfile);
   1297 	while ((n = read(fileno(input), buff, sizeof buff)) > 0)
   1298 		if (write(bakchn, buff, n) != n)
   1299 			err(1, "%s", bakfile);
   1300 	if (n < 0)
   1301 		err(1, "%s", in_name);
   1302 	close(bakchn);
   1303 	fclose(input);
   1304 
   1305 	/* re-open backup file as the input file */
   1306 	input = fopen(bakfile, "r");
   1307 	if (input == 0)
   1308 		err(1, "%s", bakfile);
   1309 	/* now the original input file will be the output */
   1310 	output = fopen(in_name, "w");
   1311 	if (output == 0) {
   1312 		unlink(bakfile);
   1313 		err(1, "%s", in_name);
   1314 	}
   1315 }
   1316