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