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