1 
2 /* Copyright (c) 1992, Free Software Foundation, Inc.  All rights reserved.
3 
4    Copyright (c) 1985 Sun Microsystems, Inc. Copyright (c) 1980 The Regents
5    of the University of California. Copyright (c) 1976 Board of Trustees of
6    the University of Illinois. All rights reserved.
7 
8    Redistribution and use in source and binary forms are permitted
9    provided that
10    the above copyright notice and this paragraph are duplicated in all such
11    forms and that any documentation, advertising materials, and other
12    materials related to such distribution and use acknowledge that the
13    software was developed by the University of California, Berkeley, the
14    University of Illinois, Urbana, and Sun Microsystems, Inc.  The name of
15    either University or Sun Microsystems may not be used to endorse or
16    promote products derived from this software without specific prior written
17    permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18    IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
19    OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
20 
21 #include "sys.h"
22 #include "indent.h"
23 #include <ctype.h>
24 
25 void
usage()26 usage ()
27 {
28   fprintf (stderr, "usage: indent file [-o outfile ] [ options ]\n");
29   fprintf (stderr, "       indent file1 file2 ... fileN [ options ]\n");
30   exit (1);
31 }
32 
33 
34 /* Stuff that needs to be shared with the rest of indent.
35    Documented in indent.h.  */
36 char *labbuf;
37 char *s_lab;
38 char *e_lab;
39 char *l_lab;
40 char *codebuf;
41 char *s_code;
42 char *e_code;
43 char *l_code;
44 char *combuf;
45 char *s_com;
46 char *e_com;
47 char *l_com;
48 struct buf save_com;
49 char *bp_save;
50 char *be_save;
51 int code_lines;
52 int line_no;
53 struct fstate keywordf;
54 struct fstate stringf;
55 struct fstate boxcomf;
56 struct fstate blkcomf;
57 struct fstate scomf;
58 struct fstate bodyf;
59 int break_comma;
60 
61 /* Insure that BUFSTRUC has at least REQ more chars left, if not extend it.
62       Note:  This may change bufstruc.ptr.  */
63 #define need_chars(bufstruc, req) \
64   if ((bufstruc.end - bufstruc.ptr + (req)) >= bufstruc.size) \
65 {\
66          int cur_chars = bufstruc.end - bufstruc.ptr;\
67          bufstruc.size *= 2;\
68          bufstruc.ptr = xrealloc(bufstruc.ptr,bufstruc.size);\
69          bufstruc.end = bufstruc.ptr + cur_chars;\
70 }
71 
72 int else_or_endif;
73 
74 /* true iff last keyword was an else */
75 int last_else;
76 
77 /* True if we have just encountered the end of an if (...), etc. (i.e. the
78    ')' of the if (...) was the last token).  The variable is set to 2 in
79    the middle of the main token reading loop and is decremented at the
80    beginning of the loop, so it will reach zero when the second token after
81    the ')' is read.  */
82 int last_token_ends_sp;
83 
84 /* current indentation for declarations */
85 int dec_ind;
86 
87 /* structure indentation levels */
88 int *di_stack;
89 
90 /* Currently allocated size of di_stack.  */
91 int di_stack_alloc;
92 
93 /* used when buffering up comments to remember that
94    a newline was passed over */
95 int flushed_nl;
96 int force_nl;
97 
98 /* set to true when we see a case, so we will know what to do
99    with the following colon */
100 int scase;
101 
102 /* when true, we are in the expressin of if(...), while(...), etc. */
103 int sp_sw;
104 
105 /* when this is positive, we have seen a ? without
106    the matching : in a <c>?<s>:<s> construct */
107 int squest;
108 
109 static void
indent(this_file)110 indent (this_file)
111      struct file_buffer *this_file;
112 {
113   register int i;
114   enum codes hd_type;
115   register char *t_ptr;
116   enum codes type_code;
117   int dec_ind;			/* current indentation for declarations */
118   int flushed_nl;
119   int force_nl;
120   int scase;			/* true when we've just see a case */
121   int sp_sw;			/* when true, we are in the expressin of
122 				   if(...), while(...), etc. */
123 
124   /* True if we have just encountered the end of an if (...), etc. (i.e. the
125      ')' of the if (...) was the last token).  The variable is set to 2 in
126      the middle of the main token reading loop and is decremented at the
127      beginning of the loop, so it will reach zero when the second token after
128      the ')' is read.  */
129   int last_token_ends_sp;
130 
131   int squest;			/* when this is positive, we have seen a ?
132 				   without the matching : in a <c>?<s>:<s>
133 				   construct */
134   int last_else;		/* true iff last keyword was an else */
135 
136 
137   in_prog = in_prog_pos = this_file->data;
138   in_prog_size = this_file->size;
139 
140   hd_type = code_eof;
141   dec_ind = 0;
142   last_token_ends_sp = false;
143   last_else = false;
144   sp_sw = force_nl = false;
145   scase = false;
146 
147   if (com_ind <= 1)
148     com_ind = 2;		/* dont put normal comments before column 2 */
149   if (troff)
150     {
151       if (bodyf.font[0] == 0)
152 	parsefont (&bodyf, "R");
153       if (scomf.font[0] == 0)
154 	parsefont (&scomf, "I");
155       if (blkcomf.font[0] == 0)
156 	blkcomf = scomf, blkcomf.size += 2;
157       if (boxcomf.font[0] == 0)
158 	boxcomf = blkcomf;
159       if (stringf.font[0] == 0)
160 	parsefont (&stringf, "L");
161       if (keywordf.font[0] == 0)
162 	parsefont (&keywordf, "B");
163       writefdef (&bodyf, 'B');
164       writefdef (&scomf, 'C');
165       writefdef (&blkcomf, 'L');
166       writefdef (&boxcomf, 'X');
167       writefdef (&stringf, 'S');
168       writefdef (&keywordf, 'K');
169     }
170   if (block_comment_max_col <= 0)
171     block_comment_max_col = max_col;
172   if (decl_com_ind <= 0)	/* if not specified by user, set this */
173     decl_com_ind =
174       ljust_decl ? (com_ind <= 10 ? 2 : com_ind - 8) : com_ind;
175   if (continuation_indent == 0)
176     continuation_indent = ind_size;
177   fill_buffer ();		/* get first batch of stuff into input buffer */
178 
179   parse (semicolon);
180   {
181     register char *p = buf_ptr;
182     register col = 1;
183 
184     while (1)
185       {
186 	if (*p == ' ')
187 	  col++;
188 	else if (*p == '\t')
189 	  col = ((col - 1) & ~7) + 9;
190 	else
191 	  break;
192 	p++;
193       }
194     if (col > ind_size)
195       parser_state_tos->ind_level = parser_state_tos->i_l_follow = col;
196   }
197   if (troff)
198     {
199       register char *p = in_name, *beg = in_name;
200 
201       while (*p)
202 	if (*p++ == '/')
203 	  beg = p;
204       fprintf (output, ".Fn \"%s\"\n", beg);
205     }
206   /* START OF MAIN LOOP */
207 
208   while (1)
209     {				/* this is the main loop.  it will go until
210 				   we reach eof */
211       int is_procname;
212 
213       type_code = lexi ();	/* lexi reads one token.  "token" points to
214 				   the actual characters. lexi returns a code
215 				   indicating the type of token */
216 
217       if (last_token_ends_sp > 0)
218 	last_token_ends_sp--;
219       is_procname = parser_state_tos->procname[0];
220 
221       /* The following code moves everything following an if (), while (),
222          else, etc. up to the start of the following stmt to a buffer. This
223          allows proper handling of both kinds of brace placement. */
224 
225       flushed_nl = false;
226       while (parser_state_tos->search_brace)
227 	{
228 	  /* After scanning an if(), while (), etc., it might be necessary to
229 	     keep track of the text between the if() and the start of the
230 	     statement which follows.  Use save_com to do so.  */
231 
232 	  switch (type_code)
233 	    {
234 	    case newline:
235 	      ++line_no;
236 	      flushed_nl = true;
237 	    case form_feed:
238 	      break;		/* form feeds and newlines found here will be
239 				   ignored */
240 
241 	    case lbrace:	/* this is a brace that starts the compound
242 				   stmt */
243 	      if (save_com.end == save_com.ptr)
244 		{
245 		  /* ignore buffering if a comment wasnt stored up */
246 		  parser_state_tos->search_brace = false;
247 		  goto check_type;
248 		}
249 	      /* We need to put the '{' back into save_com somewhere.  */
250 	      if (btype_2)
251 		/* Put it at the beginning, e.g. if (foo) { / * comment here *
252 		   / */
253 
254 		save_com.ptr[0] = '{';
255 
256 	      else
257 		{
258 		  /* Put it at the end, e.g. if (foo) / * comment here * / { */
259 
260 		  /* Putting in this newline causes a dump_line to occur
261 		     right after the comment, thus insuring that it will be
262 		     put in the correct column.  */
263 		  *save_com.end++ = '\n';
264 		  *save_com.end++ = '{';
265 		}
266 
267 	      /* Go to common code to get out of this loop.  */
268 	      goto sw_buffer;
269 
270 	    case comment:	/* we have a comment, so we must copy it into
271 				   the buffer */
272 	      if (!flushed_nl || save_com.end != save_com.ptr)
273 		{
274 		  need_chars (save_com, 10);
275 		  if (save_com.end == save_com.ptr)
276 		    {		/* if this is the first comment, we must set
277 				   up the buffer */
278 		      save_com.ptr[0] = save_com.ptr[1] = ' ';
279 		      save_com.end = save_com.ptr + 2;
280 		    }
281 		  else
282 		    {
283 		      *save_com.end++ = '\n';	/* add newline between
284 						   comments */
285 		      *save_com.end++ = ' ';
286 		      --line_no;
287 		    }
288 		  *save_com.end++ = '/';	/* copy in start of comment */
289 		  *save_com.end++ = '*';
290 
291 		  for (;;)
292 		    {		/* loop until we get to the end of the
293 				   comment */
294 		      /* make sure there is room for this character and
295 		         (while we're at it) the '/' we might add at the end
296 		         of the loop. */
297 		      need_chars (save_com, 2);
298 		      *save_com.end = *buf_ptr++;
299 		      if (buf_ptr >= buf_end)
300 			{
301 			  fill_buffer ();
302 			  if (had_eof)
303 			    {
304 			      diag (1, "Unclosed comment");
305 			      exit (1);
306 			    }
307 			}
308 
309 		      if (*save_com.end++ == '*' && *buf_ptr == '/')
310 			break;	/* we are at end of comment */
311 
312 		    }
313 		  *save_com.end++ = '/';	/* add ending slash */
314 		  if (++buf_ptr >= buf_end)	/* get past / in buffer */
315 		    fill_buffer ();
316 		  break;
317 		}
318 	    default:		/* it is the start of a normal statment */
319 	      if (flushed_nl)	/* if we flushed a newline, make sure it is
320 				   put back */
321 		force_nl = true;
322 	      if ((type_code == sp_paren && *token == 'i'
323 		   && last_else && else_if)
324 		  ||
325 		  (type_code == sp_nparen && *token == 'e'
326 		   && e_code != s_code && e_code[-1] == '}'))
327 		force_nl = false;
328 
329 	      if (save_com.end == save_com.ptr)
330 		{
331 		  /* ignore buffering if comment wasnt saved up */
332 		  parser_state_tos->search_brace = false;
333 		  goto check_type;
334 		}
335 	      if (force_nl)
336 		{		/* if we should insert a nl here, put it into
337 				   the buffer */
338 		  force_nl = false;
339 		  --line_no;	/* this will be re-increased when the nl is
340 				   read from the buffer */
341 		  need_chars (save_com, 2);
342 		  *save_com.end++ = '\n';
343 		  *save_com.end++ = ' ';
344 		  if (verbose && !flushed_nl)	/* print error msg if the
345 						   line was not already
346 						   broken */
347 		    diag (0, "Line broken");
348 		  flushed_nl = false;
349 		}
350 	      for (t_ptr = token; t_ptr < token_end; ++t_ptr)
351 		{
352 		  need_chars (save_com, 1);
353 		  *save_com.end++ = *t_ptr;	/* copy token into temp
354 						   buffer */
355 		}
356 	      parser_state_tos->procname = "\0";
357 
358 	    sw_buffer:
359 	      parser_state_tos->search_brace = false;	/* stop looking for
360 							   start of stmt */
361 	      bp_save = buf_ptr;/* save current input buffer */
362 	      be_save = buf_end;
363 	      buf_ptr = save_com.ptr;	/* fix so that subsequent calls to
364 					   lexi will take tokens out of
365 					   save_com */
366 	      need_chars (save_com, 1);
367 	      *save_com.end++ = ' ';	/* add trailing blank, just in case */
368 	      buf_end = save_com.end;
369 	      save_com.end = save_com.ptr;	/* make save_com empty */
370 	      break;
371 	    }			/* end of switch */
372 	  /* we must make this check, just in case there was an unexpected
373 	     EOF */
374 	  if (type_code != code_eof)
375 	    type_code = lexi ();/* read another token */
376 	  /* if (parser_state_tos->search_brace)
377 	     parser_state_tos->procname[0] = 0; */
378 	  if ((is_procname = parser_state_tos->procname[0]) && flushed_nl
379 	      && !procnames_start_line && parser_state_tos->in_decl
380 	      && type_code == ident)
381 	    flushed_nl = 0;
382 	}			/* end of while (search_brace) */
383       last_else = 0;
384 
385     check_type:
386       if (type_code == code_eof)
387 	{			/* we got eof */
388 	  if (s_lab != e_lab || s_code != e_code
389 	      || s_com != e_com)/* must dump end of line */
390 	    dump_line ();
391 	  if (parser_state_tos->tos > 1)	/* check for balanced braces */
392 	    diag (1, "Stuff missing from end of file.");
393 
394 	  if (verbose)
395 	    {
396 	      printf ("There were %d output lines and %d comments\n",
397 		      out_lines, out_coms);
398 	      printf ("(Lines with comments)/(Lines with code): %6.3f\n",
399 		      (1.0 * com_lines) / code_lines);
400 	    }
401 	  fflush (output);
402 	  if (found_err)
403 	    exit (found_err);
404 
405 	  return;
406 	}
407 
408       if ((type_code != comment) &&
409 	  (type_code != newline) &&
410 	  (type_code != preesc) &&
411 	  (type_code != form_feed))
412 	{
413 	  if (force_nl &&
414 	      (type_code != semicolon) &&
415 	      (type_code != lbrace || !btype_2))
416 	    {
417 	      /* we should force a broken line here */
418 	      if (verbose && !flushed_nl)
419 		diag (0, "Line broken");
420 	      flushed_nl = false;
421 	      dump_line ();
422 	      parser_state_tos->want_blank = false;	/* dont insert blank at
423 							   line start */
424 	      force_nl = false;
425 	    }
426 	  parser_state_tos->in_stmt = true;	/* turn on flag which causes
427 						   an extra level of
428 						   indentation. this is
429 						   turned off by a ; or } */
430 	  if (s_com != e_com)
431 	    {			/* the turkey has embedded a comment in a
432 				   line. Move it from the com buffer to the
433 				   code buffer.  */
434 	      /* Do not add a space before the comment if it is the first
435 	         thing on the line.  */
436 	      if (e_code != s_code)
437 		{
438 		  *e_code++ = ' ';
439 		}
440 	      for (t_ptr = s_com; *t_ptr; ++t_ptr)
441 		{
442 		  check_code_size;
443 		  *e_code++ = *t_ptr;
444 		}
445 	      *e_code++ = ' ';
446 	      *e_code = '\0';	/* null terminate code sect */
447 	      parser_state_tos->want_blank = false;
448 	      e_com = s_com;
449 	    }
450 	}
451       else if (type_code != comment)	/* preserve force_nl thru a comment */
452 	force_nl = false;	/* cancel forced newline after newline, form
453 				   feed, etc */
454 
455 
456 
457       /*-----------------------------------------------------*\
458       |	   do switch on type of token scanned		|
459       \*-----------------------------------------------------*/
460       check_code_size;
461       switch (type_code)
462 	{			/* now, decide what to do with the token */
463 
464 	case form_feed:	/* found a form feed in line */
465 	  parser_state_tos->use_ff = true;	/* a form feed is treated
466 						   much like a newline */
467 	  dump_line ();
468 	  parser_state_tos->want_blank = false;
469 	  break;
470 
471 	case newline:
472 	  if (parser_state_tos->last_token != comma
473 	      || parser_state_tos->p_l_follow > 0
474 	      || !leave_comma || parser_state_tos->block_init
475 	      || !break_comma || s_com != e_com)
476 	    {
477 	      dump_line ();
478 	      parser_state_tos->want_blank = false;
479 	    }
480 	  /* If we were on the line with a #else or a #endif, we aren't
481 	     anymore.  */
482 	  else_or_endif = false;
483 	  ++line_no;		/* keep track of input line number */
484 	  break;
485 
486 	case lparen:
487 	  /* Braces in initializer lists should be put on new lines. This is
488 	     necessary so that -gnu does not cause things like char
489 	     *this_is_a_string_array[] = { "foo", "this_string_does_not_fit",
490 	     "nor_does_this_rather_long_string" } which is what happens
491 	     because we are trying to line the strings up with the
492 	     parentheses, and those that are too long are moved to the right
493 	     an ugly amount.
494 
495 	     However, if the current line is empty, the left brace is
496 	     already on a new line, so don't molest it.  */
497 	  if (token[0] == '{'
498 	      && (s_code != e_code || s_com != e_com || s_lab != e_lab))
499 	    {
500 	      dump_line ();
501 	      /* Do not put a space before the '{'.  */
502 	      parser_state_tos->want_blank = false;
503 	    }
504 
505 	  /* Count parens so we know how deep we are.  */
506 	  if (++parser_state_tos->p_l_follow
507 	      >= parser_state_tos->paren_indents_size)
508 	    {
509 	      parser_state_tos->paren_indents_size *= 2;
510 	      parser_state_tos->paren_indents = (short *)
511 		xrealloc (parser_state_tos->paren_indents,
512 			  parser_state_tos->paren_indents_size
513 			  * sizeof (short));
514 	    }
515 	  parser_state_tos->paren_depth++;
516 	  if (parser_state_tos->want_blank && *token != '['
517 	      && (parser_state_tos->last_token != ident || proc_calls_space
518 		  || (parser_state_tos->its_a_keyword
519 		      && (!parser_state_tos->sizeof_keyword
520 			  || blank_after_sizeof))))
521 	    *e_code++ = ' ';
522 
523 	  if (parser_state_tos->in_decl && !parser_state_tos->block_init)
524 	    if (troff
525 		&& !parser_state_tos->dumped_decl_indent
526 		&& !is_procname
527 		&& parser_state_tos->last_token == decl)
528 	      {
529 		parser_state_tos->dumped_decl_indent = 1;
530 		sprintf (e_code, "\n.Du %dp+\200p \"%.*s\"\n", dec_ind * 7,
531 			 token_end - token, token);
532 		e_code += strlen (e_code);
533 	      }
534 	    else
535 	      {
536 		while ((e_code - s_code) < dec_ind)
537 		  {
538 		    check_code_size;
539 		    *e_code++ = ' ';
540 		  }
541 		*e_code++ = token[0];
542 	      }
543 	  else
544 	    *e_code++ = token[0];
545 
546 	  parser_state_tos->paren_indents[parser_state_tos->p_l_follow - 1]
547 	    = e_code - s_code;
548 	  if (sp_sw && parser_state_tos->p_l_follow == 1
549 	      && extra_expression_indent
550 	      && parser_state_tos->paren_indents[0] < 2 * ind_size)
551 	    parser_state_tos->paren_indents[0] = 2 * ind_size;
552 	  parser_state_tos->want_blank = false;
553 
554 	  if (parser_state_tos->in_or_st
555 	      && *token == '('
556 	      && parser_state_tos->tos <= 2)
557 	    {
558 	      /* this is a kluge to make sure that declarations will be
559 	         aligned right if proc decl has an explicit type on it, i.e.
560 	         "int a(x) {..." */
561 	      parse_lparen_in_decl ();
562 
563 	      /* Turn off flag for structure decl or initialization.  */
564 	      parser_state_tos->in_or_st = false;
565 	    }
566 	  if (parser_state_tos->sizeof_keyword)
567 	    parser_state_tos->sizeof_mask |= 1 << parser_state_tos->p_l_follow;
568 
569 	  /* The '(' that starts a cast can never be preceeded by an
570 	     indentifier or decl.  */
571 	  if (parser_state_tos->last_token == decl
572 	      || (parser_state_tos->last_token == ident
573 		  && parser_state_tos->last_rw != rw_return))
574 	    parser_state_tos->noncast_mask |=
575 	      1 << parser_state_tos->p_l_follow;
576 	  else
577 	    parser_state_tos->noncast_mask &=
578 	      ~(1 << parser_state_tos->p_l_follow);
579 
580 	  break;
581 
582 	case rparen:
583 	  if (parser_state_tos->cast_mask
584 	      & (1 << parser_state_tos->p_l_follow)
585 	      & ~parser_state_tos->sizeof_mask)
586 	    {
587 	      parser_state_tos->last_u_d = true;
588 	      parser_state_tos->cast_mask &=
589 		(1 << parser_state_tos->p_l_follow) - 1;
590 	      if (!parser_state_tos->cast_mask && cast_space)
591 		parser_state_tos->want_blank = true;
592 	      else
593 		parser_state_tos->want_blank = false;
594 	    }
595 	  parser_state_tos->sizeof_mask
596 	    &= (1 << parser_state_tos->p_l_follow) - 1;
597 	  if (--parser_state_tos->p_l_follow < 0)
598 	    {
599 	      parser_state_tos->p_l_follow = 0;
600 	      diag (0, "Extra %c", *token);
601 	    }
602 
603 	  parser_state_tos->paren_depth--;
604 	  /* if the paren starts the line, then indent it */
605 	  if (e_code == s_code)
606 	    {
607 	      int level = parser_state_tos->p_l_follow;
608 	      parser_state_tos->paren_level = level;
609 	      if (level > 0)
610 		paren_target = -parser_state_tos->paren_indents[level - 1];
611 	      else
612 		paren_target = 0;
613 	    }
614 	  else if (parser_state_tos->in_decl
615 		   && parser_state_tos->paren_depth == 0)
616 	    parser_state_tos->want_blank = true;
617 	  *e_code++ = token[0];
618 
619 #if 0
620 	  if (!parser_state_tos->cast_mask || cast_space)
621 	    parser_state_tos->want_blank = true;
622 #endif
623 
624 	  /* check for end of if (...), or some such */
625 	  if (sp_sw && (parser_state_tos->p_l_follow == 0))
626 	    {
627 
628 	      /* Indicate that we have just left the parenthesized expression
629 	         of a while, if, or for, unless we are getting out of the
630 	         parenthesized expression of the while of a do-while loop.
631 	         (do-while is different because a semicolon immediately
632 	         following this will not indicate a null loop body).  */
633 	      if (parser_state_tos->p_stack[parser_state_tos->tos]
634 		  != dohead)
635 		last_token_ends_sp = 2;
636 	      sp_sw = false;
637 	      force_nl = true;	/* must force newline after if */
638 	      parser_state_tos->last_u_d = true;	/* inform lexi that a
639 							   following operator is
640 							   unary */
641 	      parser_state_tos->in_stmt = false;	/* dont use stmt
642 							   continuation
643 							   indentation */
644 
645 	      parse (hd_type);	/* let parser worry about if, or whatever */
646 	    }
647 	  parser_state_tos->search_brace = btype_2;	/* this should insure
648 							   that constructs such
649 							   as main(){...} and
650 							   int[]{...} have their
651 							   braces put in the
652 							   right place */
653 	  break;
654 
655 	case unary_op:		/* this could be any unary operation */
656 	  if (parser_state_tos->want_blank)
657 	    *e_code++ = ' ';
658 
659 	  if (troff
660 	      && !parser_state_tos->dumped_decl_indent
661 	      && parser_state_tos->in_decl && !is_procname)
662 	    {
663 	      sprintf (e_code, "\n.Du %dp+\200p \"%.*s\"\n", dec_ind * 7,
664 		       token_end - token, token);
665 	      parser_state_tos->dumped_decl_indent = 1;
666 	      e_code += strlen (e_code);
667 	    }
668 	  else
669 	    {
670 	      char *res = token;
671 	      char *res_end = token_end;
672 
673 	      /* if this is a unary op in a declaration, we should
674 		 indent this token */
675 	      if (parser_state_tos->paren_depth == 0
676 		  && parser_state_tos->in_decl
677 		  && !parser_state_tos->block_init)
678 		{
679 		  while ((e_code - s_code) < (dec_ind - (token_end - token)))
680 		    {
681 		      check_code_size;
682 		      *e_code++ = ' ';
683 		    }
684 		}
685 
686 	      if (troff && token[0] == '-' && token[1] == '>')
687 		{
688 		  static char resval[] = "\\(->";
689 		  res = resval;
690 		  res_end = res + sizeof (resval);
691 		}
692 
693 	      for (t_ptr = res; t_ptr < res_end; ++t_ptr)
694 		{
695 		  check_code_size;
696 		  *e_code++ = *t_ptr;
697 		}
698 	    }
699 	  parser_state_tos->want_blank = false;
700 	  break;
701 
702 	case binary_op:	/* any binary operation */
703 	  if (parser_state_tos->want_blank
704 	      || (e_code > s_code && *e_code != ' '))
705 	    *e_code++ = ' ';
706 
707 	  {
708 	    char *res = token;
709 	    char *res_end = token_end;
710 #define set_res(str) \
711 	      {\
712 		static char resval[] = str;\
713 		res = resval;\
714 		res_end = res + sizeof(resval);\
715 	      }
716 
717 	    if (troff)
718 	      switch (token[0])
719 		{
720 		case '<':
721 		  if (token[1] == '=')
722 		    set_res ("\\(<=");
723 		  break;
724 		case '>':
725 		  if (token[1] == '=')
726 		    set_res ("\\(>=");
727 		  break;
728 		case '!':
729 		  if (token[1] == '=')
730 		    set_res ("\\(!=");
731 		  break;
732 		case '|':
733 		  if (token[1] == '|')
734 		    {
735 		      set_res ("\\(br\\(br");
736 		    }
737 		  else if (token[1] == 0)
738 		    set_res ("\\(br");
739 		  break;
740 		}
741 
742 	    for (t_ptr = res; t_ptr < res_end; ++t_ptr)
743 	      {
744 		check_code_size;
745 		*e_code++ = *t_ptr;	/* move the operator */
746 	      }
747 	  }
748 	  parser_state_tos->want_blank = true;
749 	  break;
750 
751 	case postop:		/* got a trailing ++ or -- */
752 	  *e_code++ = token[0];
753 	  *e_code++ = token[1];
754 	  parser_state_tos->want_blank = true;
755 	  break;
756 
757 	case question:		/* got a ? */
758 	  squest++;		/* this will be used when a later colon
759 				   appears so we can distinguish the
760 				   <c>?<n>:<n> construct */
761 	  if (parser_state_tos->want_blank)
762 	    *e_code++ = ' ';
763 	  *e_code++ = '?';
764 	  parser_state_tos->want_blank = true;
765 	  break;
766 
767 	case casestmt:		/* got word 'case' or 'default' */
768 	  scase = true;		/* so we can process the later colon properly */
769 	  goto copy_id;
770 
771 	case colon:		/* got a ':' */
772 	  if (squest > 0)
773 	    {			/* it is part of the <c>?<n>: <n> construct */
774 	      --squest;
775 	      if (parser_state_tos->want_blank)
776 		*e_code++ = ' ';
777 	      *e_code++ = ':';
778 	      parser_state_tos->want_blank = true;
779 	      break;
780 	    }
781 	  if (parser_state_tos->in_decl)
782 	    {
783 	      *e_code++ = ':';
784 	      parser_state_tos->want_blank = false;
785 	      break;
786 	    }
787 	  parser_state_tos->in_stmt = false;	/* seeing a label does not
788 						   imply we are in a stmt */
789 	  for (t_ptr = s_code; *t_ptr; ++t_ptr)
790 	    *e_lab++ = *t_ptr;	/* turn everything so far into a label */
791 	  e_code = s_code;
792 	  *e_lab++ = ':';
793 	  *e_lab++ = ' ';
794 	  *e_lab = '\0';
795 	  /* parser_state_tos->pcas e will be used by dump_line to decide
796 	     how to indent the label. force_nl will force a case n: to be
797 	     on a line by itself */
798 	  force_nl = parser_state_tos->pcase = scase;
799 	  scase = false;
800 	  parser_state_tos->want_blank = false;
801 	  break;
802 
803 	case semicolon:
804 	  /* we are not in an initialization or structure declaration */
805 	  parser_state_tos->in_or_st = false;
806 	  scase = false;
807 	  squest = 0;
808 	  /* The following code doesn't seem to do much good. Just because
809 	     we've found something like extern int foo();    or int (*foo)();
810 	     doesn't mean we are out of a declaration.  Now if it was serving
811 	     some purpose we'll have to address that.... if
812 	     (parser_state_tos->last_token == rparen)
813 	     parser_state_tos->in_parameter_declaration = 0; */
814 	  parser_state_tos->cast_mask = 0;
815 	  parser_state_tos->sizeof_mask = 0;
816 	  parser_state_tos->block_init = 0;
817 	  parser_state_tos->block_init_level = 0;
818 	  parser_state_tos->just_saw_decl--;
819 
820 	  if (parser_state_tos->in_decl
821 	      && s_code == e_code
822 	      && !parser_state_tos->block_init)
823 	    while ((e_code - s_code) < (dec_ind - 1))
824 	      {
825 		check_code_size;
826 		*e_code++ = ' ';
827 	      }
828 
829 	  /* if we were in a first level structure declaration,
830 	     we aren't any more */
831 	  parser_state_tos->in_decl = (parser_state_tos->dec_nest > 0);
832 	  if ((!sp_sw || hd_type != forstmt)
833 	      && parser_state_tos->p_l_follow > 0)
834 	    {
835 
836 	      /* This should be true iff there were unbalanced parens in the
837 	         stmt.  It is a bit complicated, because the semicolon might
838 	         be in a for stmt */
839 	      diag (1, "Unbalanced parens");
840 	      parser_state_tos->p_l_follow = 0;
841 	      if (sp_sw)
842 		{		/* this is a check for a if, while, etc. with
843 				   unbalanced parens */
844 		  sp_sw = false;
845 		  parse (hd_type);	/* dont lose the if, or whatever */
846 		}
847 	    }
848 
849 	  /* If we have a semicolon following an if, while, or for, and the
850 	     user wants us to, we should insert a space (to show that there
851 	     is a null statement there).  */
852 	  if (last_token_ends_sp && space_sp_semicolon)
853 	    {
854 	      *e_code++ = ' ';
855 	    }
856 	  *e_code++ = ';';
857 	  parser_state_tos->want_blank = true;
858 	  /* we are no longer in the middle of a stmt */
859 	  parser_state_tos->in_stmt = (parser_state_tos->p_l_follow > 0);
860 
861 	  if (!sp_sw)
862 	    {			/* if not if for (;;) */
863 	      parse (semicolon);/* let parser know about end of stmt */
864 	      force_nl = true;	/* force newline after a end of stmt */
865 	    }
866 	  break;
867 
868 	case lbrace:		/* got a '{' */
869 	  parser_state_tos->in_stmt = false;	/* dont indent the {} */
870 	  if (!parser_state_tos->block_init)
871 	    force_nl = true;	/* force other stuff on same line as '{' onto
872 				   new line */
873 	  else if (parser_state_tos->block_init_level <= 0)
874 	    parser_state_tos->block_init_level = 1;
875 	  else
876 	    parser_state_tos->block_init_level++;
877 
878 	  if (s_code != e_code && !parser_state_tos->block_init)
879 	    {
880 	      if (!btype_2)
881 		{
882 		  dump_line ();
883 		  parser_state_tos->want_blank = false;
884 		}
885 	      else
886 		{
887 		  if (parser_state_tos->in_parameter_declaration
888 		      && !parser_state_tos->in_or_st)
889 		    {
890 		      parser_state_tos->i_l_follow = 0;
891 		      dump_line ();
892 		      parser_state_tos->want_blank = false;
893 		    }
894 		  else
895 		    parser_state_tos->want_blank = true;
896 		}
897 	    }
898 	  if (parser_state_tos->in_parameter_declaration)
899 	    prefix_blankline_requested = 0;
900 
901 	  if (parser_state_tos->p_l_follow > 0)
902 	    {			/* check for preceeding unbalanced parens */
903 	      diag (1, "Unbalanced parens");
904 	      parser_state_tos->p_l_follow = 0;
905 	      if (sp_sw)
906 		{		/* check for unclosed if, for, etc. */
907 		  sp_sw = false;
908 		  parse (hd_type);
909 		  parser_state_tos->ind_level = parser_state_tos->i_l_follow;
910 		}
911 	    }
912 	  if (s_code == e_code)
913 	    parser_state_tos->ind_stmt = false;	/* dont put extra indentation
914 						   on line with '{' */
915 	  if (parser_state_tos->in_decl && parser_state_tos->in_or_st)
916 	    {
917 	      /* This is a structure declaration.  */
918 	      if (parser_state_tos->dec_nest >= di_stack_alloc)
919 		{
920 		  di_stack_alloc *= 2;
921 		  di_stack = (int *)
922 		    xrealloc (di_stack,
923 			      di_stack_alloc * sizeof (*di_stack));
924 		}
925 	      di_stack[parser_state_tos->dec_nest++] = dec_ind;
926 	      /* ?		dec_ind = 0; */
927 	    }
928 	  else
929 	    {
930 	      parser_state_tos->decl_on_line = false;	/* we cant be in the
931 							   middle of a
932 							   declaration, so dont
933 							   do special
934 							   indentation of
935 							   comments */
936 
937 #if 0				/* Doesn't work currently. */
938 	      if (blanklines_after_declarations_at_proctop
939 		  && parser_state_tos->in_parameter_declaration)
940 		postfix_blankline_requested = 1;
941 #endif
942 	      parser_state_tos->in_parameter_declaration = 0;
943 	    }
944 	  dec_ind = 0;
945 
946 	  /* We are no longer looking for an initializer or structure. Needed
947 	     so that the '=' in "enum bar {a = 1" does not get interpreted as
948 	     the start of an initializer.  */
949 	  parser_state_tos->in_or_st = false;
950 
951 	  parse (lbrace);	/* let parser know about this */
952 	  if (parser_state_tos->want_blank)	/* put a blank before '{' if
953 						   '{' is not at start of
954 						   line */
955 	    *e_code++ = ' ';
956 	  parser_state_tos->want_blank = false;
957 	  *e_code++ = '{';
958 	  parser_state_tos->just_saw_decl = 0;
959 	  break;
960 
961 	case rbrace:		/* got a '}' */
962 	  /* semicolons can be omitted in declarations */
963 	  if (parser_state_tos->p_stack[parser_state_tos->tos] == decl
964 	      && !parser_state_tos->block_init)
965 	    parse (semicolon);
966 	  if (parser_state_tos->p_l_follow)
967 	    {			/* check for unclosed if, for, else. */
968 	      diag (1, "Unbalanced parens");
969 	      parser_state_tos->p_l_follow = 0;
970 	      sp_sw = false;
971 	    }
972 	  parser_state_tos->just_saw_decl = 0;
973 	  parser_state_tos->block_init_level--;
974 	  if (s_code != e_code && !parser_state_tos->block_init)
975 	    {			/* '}' must be first on line */
976 	      if (verbose)
977 		diag (0, "Line broken");
978 	      dump_line ();
979 	    }
980 	  *e_code++ = '}';
981 	  parser_state_tos->want_blank = true;
982 	  parser_state_tos->in_stmt = parser_state_tos->ind_stmt = false;
983 	  if (parser_state_tos->dec_nest > 0)
984 	    {			/* we are in multi-level structure
985 				   declaration */
986 	      dec_ind = di_stack[--parser_state_tos->dec_nest];
987 	      if (parser_state_tos->dec_nest == 0
988 		  && !parser_state_tos->in_parameter_declaration)
989 		parser_state_tos->just_saw_decl = 2;
990 	      parser_state_tos->in_decl = true;
991 	    }
992 	  prefix_blankline_requested = 0;
993 	  parse (rbrace);	/* let parser know about this */
994 	  if (parser_state_tos->p_stack[parser_state_tos->tos] == dohead
995 	      && !btype_2)
996 	    force_nl = true;
997 	  parser_state_tos->search_brace
998 	    = (cuddle_else
999 	     && parser_state_tos->p_stack[parser_state_tos->tos] == ifhead);
1000 
1001 #if 0
1002 	  parser_state_tos->search_brace
1003 	    = (cuddle_else
1004 	       && parser_state_tos->p_stack[parser_state_tos->tos] == ifhead
1005 	       && (parser_state_tos->il[parser_state_tos->tos] >= parser_state_tos->ind_level));
1006 #endif
1007 
1008 	  if (parser_state_tos->tos <= 1
1009 	      && blanklines_after_procs
1010 	      && parser_state_tos->dec_nest <= 0)
1011 	    postfix_blankline_requested = 1;
1012 	  break;
1013 
1014 	case swstmt:		/* got keyword "switch" */
1015 	  sp_sw = true;
1016 	  hd_type = swstmt;	/* keep this for when we have seen the
1017 				   expression */
1018 	  goto copy_id;		/* go move the token into buffer */
1019 
1020 	case sp_paren:		/* token is if, while, for */
1021 	  sp_sw = true;		/* the interesting stuff is done after the
1022 				   expression is scanned */
1023 	  hd_type = (*token == 'i' ? ifstmt :
1024 		     (*token == 'w' ? whilestmt : forstmt));
1025 
1026 	  /* remember the type of header for later use by parser */
1027 	  goto copy_id;		/* copy the token into line */
1028 
1029 	case sp_nparen:	/* got else, do */
1030 	  parser_state_tos->in_stmt = false;
1031 	  if (*token == 'e')
1032 	    {
1033 	      if (e_code != s_code && (!cuddle_else || e_code[-1] != '}'))
1034 		{
1035 		  if (verbose)
1036 		    diag (0, "Line broken");
1037 		  dump_line ();	/* make sure this starts a line */
1038 		  parser_state_tos->want_blank = false;
1039 		}
1040 	      force_nl = true;	/* also, following stuff must go onto new
1041 				   line */
1042 	      last_else = 1;
1043 	      parse (elselit);
1044 	    }
1045 	  else
1046 	    {
1047 	      if (e_code != s_code)
1048 		{		/* make sure this starts a line */
1049 		  if (verbose)
1050 		    diag (0, "Line broken");
1051 		  dump_line ();
1052 		  parser_state_tos->want_blank = false;
1053 		}
1054 	      force_nl = true;	/* also, following stuff must go onto new
1055 				   line */
1056 	      last_else = 0;
1057 	      parse (dolit);
1058 	    }
1059 	  goto copy_id;		/* move the token into line */
1060 
1061 	case decl:		/* we have a declaration type (int, register,
1062 				   etc.) */
1063 
1064 	  parse (decl);		/* let parser worry about indentation */
1065 	  if (parser_state_tos->last_token == rparen
1066 	      && parser_state_tos->tos <= 1)
1067 	    {
1068 	      parser_state_tos->in_parameter_declaration = 1;
1069 	      if (s_code != e_code)
1070 		{
1071 		  dump_line ();
1072 		  parser_state_tos->want_blank = false;
1073 		}
1074 	    }
1075 	  if (parser_state_tos->in_parameter_declaration
1076 	      && indent_parameters
1077 	      && parser_state_tos->dec_nest == 0
1078 	      && parser_state_tos->p_l_follow == 0)
1079 	    {
1080 	      parser_state_tos->ind_level = parser_state_tos->i_l_follow = indent_parameters;
1081 	      parser_state_tos->ind_stmt = 0;
1082 	    }
1083 
1084 	  /* in_or_st set for struct or initialization decl. Don't set it if
1085 	     we're in ansi prototype */
1086 	  if (!parser_state_tos->paren_depth)
1087 	    parser_state_tos->in_or_st = true;
1088 
1089 	  parser_state_tos->in_decl = parser_state_tos->decl_on_line = true;
1090 #if 0
1091 	  if (!parser_state_tos->in_or_st && parser_state_tos->dec_nest <= 0)
1092 #endif
1093 	    if (parser_state_tos->dec_nest <= 0)
1094 	      parser_state_tos->just_saw_decl = 2;
1095 	  if (prefix_blankline_requested
1096 	      && (parser_state_tos->block_init != 0
1097 		  || parser_state_tos->block_init_level != -1
1098 		  || parser_state_tos->last_token != rbrace
1099 		  || e_code != s_code
1100 		  || e_lab != s_lab
1101 		  || e_com != s_com))
1102 	    prefix_blankline_requested = 0;
1103 	  i = token_end - token + 1;	/* get length of token plus 1 */
1104 
1105 	  /* dec_ind = e_code - s_code + (parser_state_tos->decl_indent>i ?
1106 	     parser_state_tos->decl_indent : i); */
1107 	  dec_ind = decl_indent > 0 ? decl_indent : i;
1108 	  goto copy_id;
1109 
1110 	case ident:		/* got an identifier or constant */
1111 	  /* If we are in a declaration, we must indent identifier. But not
1112 	     inside the parentheses of an ANSI function declaration.  */
1113 	  if (parser_state_tos->in_decl
1114 	      && parser_state_tos->p_l_follow == 0
1115 	      && parser_state_tos->last_token != rbrace)
1116 	    {
1117 	      if (parser_state_tos->want_blank)
1118 		*e_code++ = ' ';
1119 	      parser_state_tos->want_blank = false;
1120 	      if (is_procname == 0 || !procnames_start_line)
1121 		{
1122 		  if (!parser_state_tos->block_init)
1123 		    if (troff && !parser_state_tos->dumped_decl_indent)
1124 		      {
1125 			sprintf (e_code, "\n.De %dp+\200p\n", dec_ind * 7);
1126 			parser_state_tos->dumped_decl_indent = 1;
1127 			e_code += strlen (e_code);
1128 		      }
1129 		    else
1130 		      while ((e_code - s_code) < dec_ind)
1131 			{
1132 			  check_code_size;
1133 			  *e_code++ = ' ';
1134 			}
1135 		}
1136 	      else
1137 		{
1138 		  if (dec_ind && s_code != e_code)
1139 		    dump_line ();
1140 		  dec_ind = 0;
1141 		  parser_state_tos->want_blank = false;
1142 		}
1143 	    }
1144 	  else if (sp_sw && parser_state_tos->p_l_follow == 0)
1145 	    {
1146 	      sp_sw = false;
1147 	      force_nl = true;
1148 	      parser_state_tos->last_u_d = true;
1149 	      parser_state_tos->in_stmt = false;
1150 	      parse (hd_type);
1151 	    }
1152 	copy_id:
1153 	  if (parser_state_tos->want_blank)
1154 	    *e_code++ = ' ';
1155 	  if (troff && parser_state_tos->its_a_keyword)
1156 	    {
1157 	      e_code = chfont (&bodyf, &keywordf, e_code);
1158 	      for (t_ptr = token; t_ptr < token_end; ++t_ptr)
1159 		{
1160 		  check_code_size;
1161 		  *e_code++ = keywordf.allcaps && islower (*t_ptr)
1162 		    ? toupper (*t_ptr) : *t_ptr;
1163 		}
1164 	      e_code = chfont (&keywordf, &bodyf, e_code);
1165 	    }
1166 	  else
1167 	    {
1168 	      /* Troff mode requires that strings be processed specially.  */
1169 	      if (troff && (*token == '"' || *token == '\''))
1170 		{
1171 		  char qchar;
1172 
1173 		  qchar = *token;
1174 		  *e_code++ = '`';
1175 		  if (qchar == '"')
1176 		    *e_code++ = '`';
1177 		  e_code = chfont (&bodyf, &stringf, e_code);
1178 
1179 		  t_ptr = token + 1;
1180 		  while (t_ptr < token_end)
1181 		    {
1182 		      *e_code = *t_ptr++;
1183 		      if (*e_code == '\\')
1184 			{
1185 			  *++e_code = '\\';
1186 			  if (*t_ptr == '\\')
1187 			    *++e_code = '\\';
1188 			  /* Copy char after backslash.  */
1189 			  *++e_code = *t_ptr++;
1190 			  /* Point after the last char we copied.  */
1191 			  e_code++;
1192 			}
1193 		    }
1194 		  e_code = chfont (&stringf, &bodyf, e_code - 1);
1195 		  if (qchar == '"')
1196 		    *e_code++ = '\'';
1197 		}
1198 	      else
1199 		for (t_ptr = token; t_ptr < token_end; ++t_ptr)
1200 		  {
1201 		    check_code_size;
1202 		    *e_code++ = *t_ptr;
1203 		  }
1204 	    }
1205 	  parser_state_tos->want_blank = true;
1206 
1207 	  /* If the token is va_dcl, it appears without a semicolon, so we
1208 	     need to pretend that one was there.  */
1209 	  if ((token_end - token) == 6
1210 	      && strncmp (token, "va_dcl", 6) == 0)
1211 	    {
1212 	      parser_state_tos->in_or_st = false;
1213 	      parser_state_tos->just_saw_decl--;
1214 	      parser_state_tos->in_decl = 0;
1215 	      parse (semicolon);
1216 	      force_nl = true;
1217 	    }
1218 	  break;
1219 
1220 	case period:		/* treat a period kind of like a binary
1221 				   operation */
1222 	  *e_code++ = '.';	/* move the period into line */
1223 	  parser_state_tos->want_blank = false;	/* dont put a blank after a
1224 						   period */
1225 	  break;
1226 
1227 	case comma:
1228 	  /* only put blank after comma if comma does not start the line */
1229 	  parser_state_tos->want_blank = (s_code != e_code);
1230 	  if (parser_state_tos->paren_depth == 0
1231 	      && parser_state_tos->in_decl
1232 	      && is_procname == 0
1233 	      && !parser_state_tos->block_init)
1234 	    while ((e_code - s_code) < (dec_ind - 1))
1235 	      {
1236 		check_code_size;
1237 		*e_code++ = ' ';
1238 	      }
1239 
1240 	  *e_code++ = ',';
1241 	  if (parser_state_tos->p_l_follow == 0)
1242 	    {
1243 	      if (parser_state_tos->block_init_level <= 0)
1244 		parser_state_tos->block_init = 0;
1245 	      /* If we are in a declaration, and either the user wants all
1246 	         comma'd declarations broken, or the line is getting too
1247 	         long, break the line.  */
1248 	      if (break_comma &&
1249 		  (!leave_comma
1250 		   || (compute_code_target () + (e_code - s_code)
1251 		       > max_col - 8)
1252 		  ))
1253 		force_nl = true;
1254 	    }
1255 	  break;
1256 
1257 	case preesc:		/* got the character '#' */
1258 	  if ((s_com != e_com) ||
1259 	      (s_lab != e_lab) ||
1260 	      (s_code != e_code))
1261 	    dump_line ();
1262 	  *e_lab++ = '#';	/* move whole line to 'label' buffer */
1263 	  {
1264 	    int in_comment = 0;
1265 	    int com_start = 0;
1266 	    char quote = 0;
1267 	    int com_end = 0;
1268 
1269 	    /* ANSI allows spaces between '#' and preprocessor directives.
1270 	       Remove such spaces unless user has specified "-lpb".  */
1271 	    while (*buf_ptr == ' ' || *buf_ptr == '\t')
1272 	      {
1273 		if (leave_preproc_space)
1274 		  *e_lab++ = *buf_ptr;
1275 		buf_ptr++;
1276 		if (buf_ptr >= buf_end)
1277 		  fill_buffer ();
1278 	      }
1279 	    while (*buf_ptr != '\n' || (in_comment && !had_eof))
1280 	      {
1281 		check_lab_size;
1282 		*e_lab = *buf_ptr++;
1283 		if (buf_ptr >= buf_end)
1284 		  fill_buffer ();
1285 		switch (*e_lab++)
1286 		  {
1287 		  case BACKSLASH:
1288 		    if (troff)
1289 		      *e_lab++ = BACKSLASH;
1290 		    if (!in_comment)
1291 		      {
1292 			*e_lab++ = *buf_ptr++;
1293 			if (buf_ptr >= buf_end)
1294 			  fill_buffer ();
1295 		      }
1296 		    break;
1297 		  case '/':
1298 		    if (*buf_ptr == '*' && !in_comment && !quote)
1299 		      {
1300 			in_comment = 1;
1301 			*e_lab++ = *buf_ptr++;
1302 			com_start = e_lab - s_lab - 2;
1303 		      }
1304 		    break;
1305 		  case '"':
1306 		    if (quote == '"')
1307 		      quote = 0;
1308 		    break;
1309 		  case '\'':
1310 		    if (quote == '\'')
1311 		      quote = 0;
1312 		    break;
1313 		  case '*':
1314 		    if (*buf_ptr == '/' && in_comment)
1315 		      {
1316 			in_comment = 0;
1317 			*e_lab++ = *buf_ptr++;
1318 			com_end = e_lab - s_lab;
1319 		      }
1320 		    break;
1321 		  }
1322 	      }
1323 
1324 	    while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1325 	      e_lab--;
1326 	    if (e_lab - s_lab == com_end && bp_save == 0)
1327 	      {			/* comment on preprocessor line */
1328 		if (save_com.end != save_com.ptr)
1329 		  {
1330 		    need_chars (save_com, 2);
1331 		    *save_com.end++ = '\n';	/* add newline between
1332 						   comments */
1333 		    *save_com.end++ = ' ';
1334 		    --line_no;
1335 		  }
1336 		need_chars (save_com, com_end - com_start);
1337 		strncpy (save_com.end, s_lab + com_start,
1338 			 com_end - com_start);
1339 		save_com.end += com_end - com_start;
1340 
1341 		e_lab = s_lab + com_start;
1342 		while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1343 		  e_lab--;
1344 		bp_save = buf_ptr;	/* save current input buffer */
1345 		be_save = buf_end;
1346 		buf_ptr = save_com.ptr;	/* fix so that subsequent calls to
1347 					   lexi will take tokens out of
1348 					   save_com */
1349 		need_chars (save_com, 1);
1350 		*save_com.end++ = ' ';	/* add trailing blank, just in case */
1351 		buf_end = save_com.end;
1352 		save_com.end = save_com.ptr;	/* make save_com empty */
1353 	      }
1354 	    *e_lab = '\0';	/* null terminate line */
1355 	    parser_state_tos->pcase = false;
1356 	  }
1357 
1358 	  if (strncmp (s_lab + 1, "if", 2) == 0)
1359 	    {
1360 	      if (blanklines_around_conditional_compilation)
1361 		{
1362 		  register c;
1363 		  prefix_blankline_requested++;
1364 		  while ((c = *in_prog_pos++) == '\n');
1365 		  in_prog_pos--;
1366 		}
1367 	      {
1368 		/* Push a copy of the parser_state onto the stack. All
1369 		   manipulations will use the copy at the top of stack, and
1370 		   then we can return to the previous state by popping the
1371 		   stack.  */
1372 		struct parser_state *new;
1373 
1374 		new = (struct parser_state *)
1375 		  xmalloc (sizeof (struct parser_state));
1376 		memcpy (new, parser_state_tos, sizeof (struct parser_state));
1377 
1378 		/* We need to copy the dynamically allocated arrays in the
1379 		   struct parser_state too.  */
1380 		new->p_stack = (enum codes *)
1381 		  xmalloc (parser_state_tos->p_stack_size
1382 			   * sizeof (enum codes));
1383 		memcpy (new->p_stack, parser_state_tos->p_stack,
1384 		      parser_state_tos->p_stack_size * sizeof (enum codes));
1385 
1386 		new->il = (int *)
1387 		  xmalloc (parser_state_tos->p_stack_size * sizeof (int));
1388 		memcpy (new->il, parser_state_tos->il,
1389 			parser_state_tos->p_stack_size * sizeof (int));
1390 
1391 		new->cstk = (int *)
1392 		  xmalloc (parser_state_tos->p_stack_size
1393 			   * sizeof (int));
1394 		memcpy (new->cstk, parser_state_tos->cstk,
1395 			parser_state_tos->p_stack_size * sizeof (int));
1396 
1397 		new->paren_indents = (short *) xmalloc
1398 		  (parser_state_tos->paren_indents_size * sizeof (short));
1399 		memcpy (new->paren_indents, parser_state_tos->paren_indents,
1400 		     parser_state_tos->paren_indents_size * sizeof (short));
1401 
1402 		new->next = parser_state_tos;
1403 		parser_state_tos = new;
1404 	      }
1405 	    }
1406 	  else if (strncmp (s_lab + 1, "else", 4) == 0)
1407 	    {
1408 	      /* When we get #else, we want to restore the parser state to
1409 	         what it was before the matching #if, so that things get
1410 	         lined up with the code before the #if.  However, we do not
1411 	         want to pop the stack; we just want to copy the second to
1412 	         top elt of the stack because when we encounter the #endif,
1413 	         it will pop the stack.  */
1414 	      else_or_endif = true;
1415 	      if (parser_state_tos->next)
1416 		{
1417 		  /* First save the addresses of the arrays for the top of
1418 		     stack.  */
1419 		  enum codes *tos_p_stack = parser_state_tos->p_stack;
1420 		  int *tos_il = parser_state_tos->il;
1421 		  int *tos_cstk = parser_state_tos->cstk;
1422 		  short *tos_paren_indents =
1423 		  parser_state_tos->paren_indents;
1424 		  struct parser_state *second =
1425 		  parser_state_tos->next;
1426 
1427 		  memcpy (parser_state_tos, second,
1428 			  sizeof (struct parser_state));
1429 		  parser_state_tos->next = second;
1430 
1431 		  /* Now copy the arrays from the second to top of stack to
1432 		     the top of stack.  */
1433 		  /* Since the p_stack, etc. arrays only grow, never shrink,
1434 		     we know that they will be big enough to fit the array
1435 		     from the second to top of stack.  */
1436 		  parser_state_tos->p_stack = tos_p_stack;
1437 		  memcpy (parser_state_tos->p_stack,
1438 			  parser_state_tos->next->p_stack,
1439 			  parser_state_tos->p_stack_size
1440 			  * sizeof (enum codes));
1441 
1442 		  parser_state_tos->il = tos_il;
1443 		  memcpy (parser_state_tos->il,
1444 			  parser_state_tos->next->il,
1445 			  parser_state_tos->p_stack_size * sizeof (int));
1446 
1447 		  parser_state_tos->cstk = tos_cstk;
1448 		  memcpy (parser_state_tos->cstk,
1449 			  parser_state_tos->next->cstk,
1450 			  parser_state_tos->p_stack_size * sizeof (int));
1451 
1452 		  parser_state_tos->paren_indents = tos_paren_indents;
1453 		  memcpy (parser_state_tos->paren_indents,
1454 			  parser_state_tos->next->paren_indents,
1455 			  parser_state_tos->paren_indents_size
1456 			  * sizeof (short));
1457 		}
1458 	      else
1459 		diag (1, "Unmatched #else");
1460 	    }
1461 	  else if (strncmp (s_lab + 1, "endif", 5) == 0)
1462 	    {
1463 	      else_or_endif = true;
1464 	      /* We want to remove the second to top elt on the stack, which
1465 	         was put there by #if and was used to restore the stack at
1466 	         the #else (if there was one). We want to leave the top of
1467 	         stack unmolested so that the state which we have been using
1468 	         is unchanged.  */
1469 	      if (parser_state_tos->next)
1470 		{
1471 		  struct parser_state *second = parser_state_tos->next;
1472 
1473 		  parser_state_tos->next = second->next;
1474 		  free (second->p_stack);
1475 		  free (second->il);
1476 		  free (second->cstk);
1477 		  free (second->paren_indents);
1478 		  free (second);
1479 		}
1480 	      else
1481 		diag (1, "Unmatched #endif");
1482 	      if (blanklines_around_conditional_compilation)
1483 		{
1484 		  postfix_blankline_requested++;
1485 		  n_real_blanklines = 0;
1486 		}
1487 	    }
1488 
1489 	  /* Normally, subsequent processing of the newline character
1490 	     causes the line to be printed.  The following clause handles
1491 	     a special case (comma-separated declarations separated
1492 	     by the preprocessor lines) where this doesn't happen. */
1493 	  if (parser_state_tos->last_token == comma
1494 	      && parser_state_tos->p_l_follow <= 0
1495 	      && leave_comma && !parser_state_tos->block_init
1496 	      && break_comma && s_com == e_com)
1497 	    {
1498 	      dump_line ();
1499 	      parser_state_tos->want_blank = false;
1500 	    }
1501 	  break;
1502 
1503 	case comment:		/* we have gotten a /*  this is a biggie */
1504 	  if (flushed_nl)
1505 	    {			/* we should force a broken line here */
1506 	      flushed_nl = false;
1507 	      dump_line ();
1508 	      parser_state_tos->want_blank = false;	/* dont insert blank at
1509 							   line start */
1510 	      force_nl = false;
1511 	    }
1512 	  pr_comment ();
1513 	  break;
1514 	}			/* end of big switch stmt */
1515 
1516       *e_code = '\0';		/* make sure code section is null terminated */
1517       if (type_code != comment
1518 	  && type_code != newline
1519 	  && type_code != preesc
1520 	  && type_code != form_feed)
1521 	parser_state_tos->last_token = type_code;
1522 
1523     }				/* end of main while (1) loop */
1524 }
1525 
1526 
1527 
1528 char *set_profile ();
1529 void set_defaults ();
1530 int set_option ();
1531 
1532 /* Points to current input file */
1533 char *in_name = 0;
1534 
1535 /* Points to the name of the output file */
1536 char *out_name = 0;
1537 
1538 /* How many input files were specified */
1539 int input_files;
1540 
1541 /* Names of all input files */
1542 char **in_file_names;
1543 
1544 /* Initial number of input filenames to allocate. */
1545 int max_input_files = 128;
1546 
1547 
1548 #ifdef DEBUG
1549 int debug;
1550 #endif
1551 
main(argc,argv)1552 main (argc, argv)
1553      int argc;
1554      char **argv;
1555 {
1556   register int i;
1557   struct file_buffer *current_input;
1558   char *profile_pathname = 0;
1559   int using_stdin = false;
1560 
1561 #ifdef DEBUG
1562   if (debug)
1563     debug_init ();
1564 #endif
1565 
1566   init_parser ();
1567   initialize_backups ();
1568 
1569   output = 0;
1570   input_files = 0;
1571   in_file_names = (char **) xmalloc (max_input_files * sizeof (char *));
1572 
1573   set_defaults ();
1574   for (i = 1; i < argc; ++i)
1575     if (strcmp (argv[i], "-npro") == 0
1576 	|| strcmp (argv[i], "--ignore-profile") == 0
1577 	|| strcmp (argv[i], "+ignore-profile") == 0)
1578       break;
1579   if (i >= argc)
1580     profile_pathname = set_profile ();
1581 
1582   for (i = 1; i < argc; ++i)
1583     {
1584       if (argv[i][0] != '-' && argv[i][0] != '+')	/* Filename */
1585 	{
1586 	  if (expect_output_file == true)	/* Last arg was "-o" */
1587 	    {
1588 	      if (out_name != 0)
1589 		{
1590 		  fprintf (stderr, "indent: only one output file (2nd was %s)\n", argv[i]);
1591 		  exit (1);
1592 		}
1593 
1594 	      if (input_files > 1)
1595 		{
1596 		  fprintf (stderr, "indent: only one input file when output file is specified\n");
1597 		  exit (1);
1598 		}
1599 
1600 	      out_name = argv[i];
1601 	      expect_output_file = false;
1602 	      continue;
1603 	    }
1604 	  else
1605 	    {
1606 	      if (using_stdin)
1607 		{
1608 		  fprintf (stderr, "indent: can't have filenames when specifying standard input\n");
1609 		  exit (1);
1610 		}
1611 
1612 	      input_files++;
1613 	      if (input_files > 1)
1614 		{
1615 		  if (out_name != 0)
1616 		    {
1617 		      fprintf (stderr, "indent: only one input file when output file is specified\n");
1618 		      exit (1);
1619 		    }
1620 
1621 		  if (use_stdout != 0)
1622 		    {
1623 		      fprintf (stderr, "indent: only one input file when stdout is used\n");
1624 		      exit (1);
1625 		    }
1626 
1627 		  if (input_files > max_input_files)
1628 		    {
1629 		      max_input_files = 2 * max_input_files;
1630 		      in_file_names = (char **) xrealloc (in_file_names,
1631 				       (max_input_files * sizeof (char *)));
1632 		    }
1633 		}
1634 
1635 	      in_file_names[input_files - 1] = argv[i];
1636 	    }
1637 	}
1638       else
1639 	{
1640 	  /* '-' as filename means stdin. */
1641 	  if (argv[i][0] == '-' && argv[i][1] == '\0')
1642 	    {
1643 	      if (input_files > 0)
1644 		{
1645 		  fprintf (stderr, "indent: can't have filenames when specifying standard input\n");
1646 		  exit (1);
1647 		}
1648 
1649 	      using_stdin = true;
1650 	    }
1651 	  else
1652 	    i += set_option (argv[i], (i < argc ? argv[i + 1] : 0), 1);
1653 	}
1654     }
1655 
1656   if (verbose && profile_pathname)
1657     fprintf (stderr, "Read profile %s\n", profile_pathname);
1658 
1659   if (input_files > 1)
1660     {
1661       /* When multiple input files are specified, make a backup copy
1662 	 and then output the indented code into the same filename. */
1663 
1664       for (i = 0; input_files; i++, input_files--)
1665 	{
1666 	  current_input = read_file (in_file_names[i]);
1667 	  in_name = out_name = in_file_names[i];
1668 	  output = fopen (out_name, "w");
1669 	  if (output == 0)
1670 	    {
1671 	      fprintf (stderr, "indent: can't create %s\n", out_name);
1672 	      exit (1);
1673 	    }
1674 
1675 	  make_backup (current_input);
1676 	  reset_parser ();
1677 	  indent (current_input);
1678 	  if (fclose (output) != 0)
1679 	    sys_error (out_name);
1680 	}
1681     }
1682   else
1683     {
1684       /* One input stream -- specified file, or stdin */
1685 
1686       if (input_files == 0 || using_stdin)
1687 	{
1688 	  input_files = 1;
1689 	  in_file_names[0] = "Standard input";
1690 	  current_input = read_stdin ();
1691 	}
1692       else
1693 	/* 1 input file */
1694 	{
1695 	  current_input = read_file (in_file_names[0]);
1696 	  if (!out_name && !use_stdout)
1697 	    {
1698 	      out_name = in_file_names[0];
1699 	      make_backup (current_input);
1700 	    }
1701 	}
1702       in_name = in_file_names[0];
1703 
1704       /* Uset stdout if it was specified ("-st"), or neither input
1705          nor output file was specified, or we're doing troff. */
1706       if (use_stdout || !out_name || troff)
1707 	output = stdout;
1708       else
1709 	{
1710 	  output = fopen (out_name, "w");
1711 	  if (output == 0)
1712 	    {
1713 	      fprintf (stderr, "indent: can't create %s\n", out_name);
1714 	      exit (1);
1715 	    }
1716 	}
1717 
1718       reset_parser ();
1719       indent (current_input);
1720     }
1721 
1722   exit (0);
1723 }
1724