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