declare timecmp for ANSI C
[unix-history] / usr / src / usr.bin / indent / indent.c
CommitLineData
c0bc4ef7
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
13#ifndef lint
d1e6224c 14static char sccsid[] = "@(#)indent.c 5.5 (Berkeley) %G%";
c0bc4ef7 15#endif not lint
c6468b47 16
1009bf5e
KM
17/*-
18
19 Copyright (C) 1976
20 by the
21 Board of Trustees
22 of the
23 University of Illinois
24
25 All rights reserved
26
27
c6468b47 28NAME:
1009bf5e
KM
29indent main program
30
c6468b47 31FUNCTION:
1009bf5e
KM
32This is the main program of the indent program. Indent will take a C
33program source and reformat it into a semi-reasonable form.
34
c6468b47 35ALGORITHM:
1009bf5e
KM
36The routine lexi scans tokens and passes them back one at a time to the
37main routine. The subroutine parse takes care of much of the work of
38figuring indentation level.
39
401) Call lexi
412) Enter a monster switch statement on the code returned by lexi. If
42the indentation level for the line yet to be printed should be
43changed, set the variable ps.ind_level. If the indentation level for
44the following line should be changed, set the variable ps.i_l_follow.
45
46*/
c6468b47
KM
47#include "indent_globs.h";
48#include "indent_codes.h";
49
1009bf5e
KM
50char *in_name = "Standard Input"; /* will always point to name of
51 * input file */
52char *out_name = "Standard Output"; /* will always point to
53 * name of output file */
54char bakfile[32] = "";
c6468b47 55
1009bf5e
KM
56main(argc, argv)
57 int argc;
58 char **argv;
c6468b47 59{
d1e6224c 60 extern int found_err; /* if any error occurred */
c6468b47 61
1009bf5e
KM
62 int dec_ind; /* current indentation for declarations */
63 int di_stack[20]; /* a stack of structure indentation levels */
64 int flushed_nl; /* used when buffering up comments to
65 * remember that a newline was passed over */
66 int force_nl; /* when true, code must be broken */
67 int hd_type; /* used to store type of stmt for if
68 * (...), for (...), etc */
69 register int i; /* local loop counter */
70 register int j; /* local loop counter */
71 int scase; /* set to true when we see a case, so we
72 * will know what to do with the following
73 * colon */
74 int sp_sw; /* when true, we are in the expressin of
75 * if(...), while(...), etc. */
76 int squest; /* when this is positive, we have seen a ?
77 * without the matching : in a <c>?<s>:<s>
78 * construct */
79 register char *t_ptr; /* used for copying tokens */
80 int type_code; /* the type of token, returned by lexi */
81
82 int last_else = 0; /* true iff last keyword was an else */
83
84
85 /*-----------------------------------------------*\
c93d6f87
KM
86 | INITIALIZATION |
87 \*-----------------------------------------------*/
c6468b47
KM
88
89
1009bf5e
KM
90 ps.p_stack[0] = stmt; /* this is the parser's stack */
91 ps.last_nl = true; /* this is true if the last thing scanned
92 * was a newline */
93 ps.last_token = semicolon;
94 combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label, and
95 * comment buffers */
c6468b47
KM
96 combuf[1] = codebuf[1] = labbuf[1] = '\0';
97 s_lab = e_lab = labbuf + 1;
98 s_code = e_code = codebuf + 1;
99 s_com = e_com = combuf + 1;
100
101 buf_ptr = buf_end = in_buffer;
102 line_no = 1;
1009bf5e 103 had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
c6468b47 104 sp_sw = force_nl = false;
1009bf5e
KM
105 ps.in_or_st = false;
106 ps.bl_line = true;
c6468b47 107 dec_ind = 0;
1009bf5e
KM
108 di_stack[ps.dec_nest = 0] = 0;
109 ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
c6468b47
KM
110
111
1009bf5e 112 scase = ps.pcase = false;
c6468b47
KM
113 squest = 0;
114 sc_end = 0;
115 bp_save = 0;
116 be_save = 0;
117
1009bf5e 118 output = 0;
c6468b47
KM
119
120
121
1009bf5e 122 /*--------------------------------------------------*\
c93d6f87
KM
123 | COMMAND LINE SCAN
124 \*--------------------------------------------------*/
1009bf5e 125
c93d6f87 126 set_defaults();
1009bf5e 127
c93d6f87
KM
128 /*
129 * Unfortunately, we must look for -npro here because the profiles
130 * are read before the command line arguments.
131 */
1009bf5e
KM
132 for (i = 1; i < argc; ++i)
133 if (strcmp(argv[i], "-npro") == 0)
134 break;
135 if (i >= argc)
136 set_profile();
c6468b47 137
c93d6f87
KM
138 input = 0; /* cancel -st if it was in the profiles, */
139 output = 0; /* as it doesn't make any sense there. */
140
c6468b47 141 for (i = 1; i < argc; ++i) {
1009bf5e
KM
142
143 /*
144 * look thru args (if any) for changes to defaults
145 */
c6468b47 146 if (argv[i][0] != '-') {/* no flag on parameter */
1009bf5e
KM
147 if (input == 0) { /* we must have the input file */
148 in_name = argv[i]; /* remember name of input file */
149 input = fopen(in_name, "r");
150 if (input == 0) { /* check for open error */
c93d6f87
KM
151 fprintf(stderr, "indent: can't open %s\n", argv[i]);
152 exit(1);
c6468b47
KM
153 }
154 continue;
1009bf5e
KM
155 } else if (output == 0) { /* we have the output file */
156 out_name = argv[i]; /* remember name of output file */
157 if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite
158 * the file */
c93d6f87
KM
159 fprintf(stderr, "indent: input and output files must be different\n");
160 exit(1);
c6468b47 161 }
1009bf5e
KM
162 output = fopen(out_name, "w");
163 if (output == 0) { /* check for create error */
c93d6f87
KM
164 fprintf(stderr, "indent: can't create %s\n", argv[i]);
165 exit(1);
1009bf5e
KM
166 }
167 continue;
168 }
c93d6f87
KM
169 fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
170 exit(1);
1009bf5e
KM
171 } else
172 set_option(argv[i]);
173
174 } /* end of for */
175 if (input == 0) {
176 printf("Usage: indent file [ outfile ] [ options ]\n");
c93d6f87 177 exit(1);
1009bf5e
KM
178 }
179 if (output == 0)
180 if (troff)
181 output = stdout;
182 else {
183 out_name = in_name;
184 bakcopy();
c6468b47 185 }
c93d6f87
KM
186
187 /*
188 * Adjust parameters that are out of range, or set defaults if
189 * no values were specified.
190 */
1009bf5e
KM
191 if (ps.com_ind <= 1)
192 ps.com_ind = 2; /* dont put normal comments before column
193 * 2 */
194 if (block_comment_max_col <= 0)
195 block_comment_max_col = max_col;
196 if (ps.decl_com_ind <= 0) /* if not specified by user, set this */
c93d6f87
KM
197 ps.decl_com_ind = ps.ljust_decl ? ps.com_ind - 8 : ps.com_ind;
198 if (ps.decl_com_ind <= 1)
199 ps.decl_com_ind = 2;
1009bf5e
KM
200 if (continuation_indent == 0)
201 continuation_indent = ps.ind_size;
202 fill_buffer(); /* get first batch of stuff into input
203 * buffer */
204
205 parse(semicolon);
206 {
207 register char *p = buf_ptr;
208 register col = 1;
209
210 while (1) {
211 if (*p == ' ')
212 col++;
213 else if (*p == '\t')
214 col = ((col - 1) & ~7) + 9;
215 else
216 break;
217 p++;
218 };
219 if (col > ps.ind_size)
220 ps.ind_level = ps.i_l_follow = col / ps.ind_size;
c6468b47 221 }
1009bf5e
KM
222 if (troff) {
223 register char *p = in_name,
224 *beg = in_name;
225
226 while (*p)
227 if (*p++ == '/')
228 beg = p;
229 fprintf(output, ".Fn \"%s\"\n", beg);
c6468b47
KM
230 }
231
1009bf5e
KM
232 /*
233 * START OF MAIN LOOP
234 */
c6468b47 235
1009bf5e
KM
236 while (1) { /* this is the main loop. it will go
237 * until we reach eof */
238 int is_procname;
c6468b47 239
1009bf5e
KM
240 type_code = lexi(); /* lexi reads one token. The actual
241 * characters read are stored in "token".
242 * lexi returns a code indicating the type
243 * of token */
244 is_procname = ps.procname[0];
c6468b47 245
1009bf5e
KM
246 /*
247 * The following code moves everything following an if (), while
248 * (), else, etc. up to the start of the following stmt to a
249 * buffer. This allows proper handling of both kinds of brace
250 * placement.
251 */
c6468b47
KM
252
253 flushed_nl = false;
1009bf5e
KM
254 while (ps.search_brace) { /* if we scanned an if(), while(),
255 * etc., we might need to copy
256 * stuff into a buffer we must
257 * loop, copying stuff into
258 * save_com, until we find the
259 * start of the stmt which follows
260 * the if, or whatever */
c6468b47 261 switch (type_code) {
1009bf5e 262 case newline:
c6468b47
KM
263 ++line_no;
264 flushed_nl = true;
1009bf5e
KM
265 case form_feed:
266 break; /* form feeds and newlines found here will
267 * be ignored */
268
269 case lbrace: /* this is a brace that starts the
270 * compound stmt */
271 if (sc_end == 0) { /* ignore buffering if a comment
272 * wasnt stored up */
273 ps.search_brace = false;
c6468b47
KM
274 goto check_type;
275 }
c6468b47 276 if (btype_2) {
1009bf5e
KM
277 save_com[0] = '{'; /* we either want to put
278 * the brace right after
279 * the if */
280 goto sw_buffer; /* go to common code to get out of
281 * this loop */
c6468b47 282 }
1009bf5e
KM
283 case comment: /* we have a comment, so we must copy it
284 * into the buffer */
285 if (!flushed_nl) {
286 if (sc_end == 0) { /* if this is the first
287 * comment, we must set up
288 * the buffer */
289 save_com[0] = save_com[1] = ' ';
290 sc_end = &(save_com[2]);
291 } else {
292 *sc_end++ = '\n'; /* add newline between
293 * comments */
294 *sc_end++ = ' ';
295 --line_no;
296 }
297 *sc_end++ = '/'; /* copy in start of
298 * comment */
299 *sc_end++ = '*';
300
301 for (;;) { /* loop until we get to the end of
302 * the comment */
303 *sc_end = *buf_ptr++;
304 if (buf_ptr >= buf_end)
305 fill_buffer();
306
307 if (*sc_end++ == '*' && *buf_ptr == '/')
308 break; /* we are at end of comment */
309
310 if (sc_end >= &(save_com[sc_size])) { /* check for temp buffer
311 * overflow */
312 diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
313 fflush(output);
c93d6f87 314 exit(1);
1009bf5e
KM
315 }
316 }
317 *sc_end++ = '/'; /* add ending slash */
318 if (++buf_ptr >= buf_end) /* get past / in buffer */
319 fill_buffer();
320 break;
321 }
322 default: /* it is the start of a normal statment */
323 if (flushed_nl) /* if we flushed a newline, make
324 * sure it is put back */
c6468b47 325 force_nl = true;
1009bf5e
KM
326 if (type_code == sp_paren && *token == 'i'
327 && last_else && ps.else_if
328 || type_code == sp_nparen && *token == 'e'
329 && e_code != s_code && e_code[-1] == '}')
330 force_nl = false;
c6468b47 331
1009bf5e
KM
332 if (sc_end == 0) { /* ignore buffering if comment
333 * wasnt saved up */
334 ps.search_brace = false;
c6468b47
KM
335 goto check_type;
336 }
1009bf5e
KM
337 if (force_nl) { /* if we should insert a nl here,
338 * put it into the buffer */
c6468b47 339 force_nl = false;
1009bf5e
KM
340 --line_no; /* this will be re-increased when
341 * the nl is read from the buffer */
c6468b47
KM
342 *sc_end++ = '\n';
343 *sc_end++ = ' ';
1009bf5e
KM
344 if (verbose && !flushed_nl) /* print error msg if
345 * the line was not
346 * already broken */
347 diag(0, "Line broken");
c6468b47
KM
348 flushed_nl = false;
349 }
c6468b47 350 for (t_ptr = token; *t_ptr; ++t_ptr)
1009bf5e
KM
351 *sc_end++ = *t_ptr; /* copy token into temp
352 * buffer */
353
354 sw_buffer:
355 ps.search_brace = false; /* stop looking for start
356 * of stmt */
357 bp_save = buf_ptr; /* save current input buffer */
c6468b47 358 be_save = buf_end;
1009bf5e
KM
359 buf_ptr = save_com; /* fix so that subsequent calls to
360 * lexi will take tokens out of
361 * save_com */
362 *sc_end++ = ' '; /* add trailing blank, just in
363 * case */
c6468b47
KM
364 buf_end = sc_end;
365 sc_end = 0;
366 break;
1009bf5e
KM
367 } /* end of switch */
368 if (type_code != 0) /* we must make this check, just in case
369 * there was an unexpected EOF */
370 type_code = lexi(); /* read another token */
371 is_procname = ps.procname[0];
372 } /* end of while (serach_brace) */
373 last_else = 0;
374check_type:
375 if (type_code == 0) { /* we got eof */
c6468b47 376 if (s_lab != e_lab || s_code != e_code
1009bf5e
KM
377 || s_com != e_com) /* must dump end of line */
378 dump_line();
379 if (ps.tos > 1) /* check for balanced braces */
380 diag(1, "Stuff missing from end of file.");
381
c6468b47 382 if (verbose) {
1009bf5e
KM
383 printf("There were %d output lines and %d comments\n",
384 ps.out_lines, ps.out_coms);
385 printf("(Lines with comments)/(Lines with code): %6.3f\n",
386 (1.0 * ps.com_lines) / code_lines);
c6468b47 387 }
1009bf5e 388 fflush(output);
d1e6224c 389 exit(ps.tos > 1 || found_err);
c6468b47 390 }
c6468b47 391 if (
1009bf5e
KM
392 (type_code != comment) &&
393 (type_code != newline) &&
394 (type_code != preesc) &&
395 (type_code != form_feed)) {
c6468b47 396 if (
1009bf5e
KM
397 force_nl
398 &&
399 (type_code != semicolon) &&
400 (
401 type_code != lbrace
402 ||
403 !btype_2
404 )) { /* we should force a broken line here */
c6468b47 405 if (verbose && !flushed_nl)
1009bf5e 406 diag(0, "Line broken");
c6468b47 407 flushed_nl = false;
1009bf5e
KM
408 dump_line();
409 ps.want_blank = false; /* dont insert blank at line start */
c6468b47
KM
410 force_nl = false;
411 }
1009bf5e
KM
412 ps.in_stmt = true; /* turn on flag which causes an extra
413 * level of indentation. this is turned
414 * off by a ; or '}' */
415 if (s_com != e_com) { /* the turkey has embedded a
416 * comment in a line. fix it */
c6468b47
KM
417 *e_code++ = ' ';
418 for (t_ptr = s_com; *t_ptr; ++t_ptr)
419 *e_code++ = *t_ptr;
420 *e_code++ = ' ';
1009bf5e
KM
421 *e_code = '\0'; /* null terminate code sect */
422 ps.want_blank = false;
c6468b47
KM
423 e_com = s_com;
424 }
1009bf5e
KM
425 } else if (type_code != comment) /* preserve force_nl thru
426 * a comment */
427 force_nl = false;
428
429 /*
430 * cancel forced newline after newline, form feed, etc
431 */
c6468b47
KM
432
433
434
1009bf5e 435 /*----------------------------------------------------*\
c93d6f87
KM
436 | do switch on type of token scanned
437 \*----------------------------------------------------*/
1009bf5e 438 switch (type_code) { /* now, decide what to do with the token */
c6468b47 439
1009bf5e
KM
440 case form_feed: /* found a form feed in line */
441 ps.use_ff = true; /* a form feed is treated much
442 * like a newline */
443 dump_line();
444 ps.want_blank = false;
c6468b47
KM
445 break;
446
1009bf5e
KM
447 case newline:
448 if (ps.last_token != comma || ps.p_l_follow > 0
449 || !ps.leave_comma || !break_comma || s_com != e_com) {
450 dump_line();
451 ps.want_blank = false;
452 }
453 ++line_no; /* keep track of input line number */
c6468b47
KM
454 break;
455
1009bf5e
KM
456 case lparen: /* got a '(' or '[' */
457 ++ps.p_l_follow;/* count parens to make Healy happy */
458 if (ps.want_blank && *token != '[' &&
459 (ps.last_token != ident || proc_calls_space
460 || (ps.its_a_keyword && !ps.sizeof_keyword)))
c6468b47 461 *e_code++ = ' ';
1009bf5e
KM
462 if (ps.in_decl && !ps.block_init)
463 if (troff && !ps.dumped_decl_indent) {
464 ps.dumped_decl_indent = 1;
465 sprintf(e_code, "\\c\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
466 e_code += strlen(e_code);
467 } else {
468 while ((e_code - s_code) < dec_ind)
469 *e_code++ = ' ';
470 *e_code++ = token[0];
471 } else
472 *e_code++ = token[0];
473 ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code;
474 ps.want_blank = false;
475 if (ps.in_or_st && *token == '(') {
476
477 /*
478 * this is a kluge to make sure that declarations will
479 * be aligned right if proc decl has an explicit type
480 * on it, i.e. "int a(x) {..."
481 */
482 parse(semicolon); /* I said this was a kluge... */
483 ps.in_or_st = false; /* turn off flag for
484 * structure decl or
485 * initialization */
c6468b47 486 }
1009bf5e 487 if (ps.sizeof_keyword) ps.sizeof_mask |= 1<<ps.p_l_follow;
c6468b47
KM
488 break;
489
1009bf5e
KM
490 case rparen: /* got a ')' or ']' */
491 if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask) {
492 ps.last_u_d = true;
493 ps.cast_mask &= (1 << ps.p_l_follow) - 1;
c6468b47 494 }
1009bf5e
KM
495 ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
496 if (--ps.p_l_follow < 0) {
497 ps.p_l_follow = 0;
498 diag(0, "Extra %c", *token);
499 }
500 if (e_code == s_code) /* if the paren starts the line */
501 ps.paren_level = ps.p_l_follow; /* then indent it */
c6468b47
KM
502
503 *e_code++ = token[0];
1009bf5e 504 ps.want_blank = true;
c6468b47 505
1009bf5e
KM
506 if (sp_sw && (ps.p_l_follow == 0)) { /* check for end of if
507 * (...), or some such */
c6468b47 508 sp_sw = false;
1009bf5e
KM
509 force_nl = true; /* must force newline after if */
510 ps.last_u_d = true; /* inform lexi that a following
511 * operator is unary */
512 ps.in_stmt = false; /* dont use stmt continuation
513 * indentation */
514
515 parse(hd_type); /* let parser worry about if, or
516 * whatever */
c6468b47 517 }
1009bf5e
KM
518 ps.search_brace = btype_2; /* this should insure that
519 * constructs such as
520 * main(){...} and
521 * int[]{...} have their
522 * braces put in the right
523 * place */
c6468b47
KM
524 break;
525
1009bf5e
KM
526 case unary_op: /* this could be any unary operation */
527 if (ps.want_blank)
c6468b47
KM
528 *e_code++ = ' ';
529
1009bf5e
KM
530 if (troff && !ps.dumped_decl_indent && ps.in_decl) {
531 sprintf(e_code, "\\c\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
532 ps.dumped_decl_indent = 1;
533 e_code += strlen(e_code);
534 } else {
535 char *res = token;
536
537 if (ps.in_decl && !ps.block_init) { /* if this is a unary op
538 * in a declaration, we
539 * should indent this
540 * token */
541 for (i = 0; token[i]; ++i); /* find length of token */
542 while ((e_code - s_code) < (dec_ind - i))
543 *e_code++ = ' '; /* pad it */
544 }
545 if (troff && token[0] == '-' && token[1] == '>')
546 res = "\\(->";
547 for (t_ptr = res; *t_ptr; ++t_ptr)
548 *e_code++ = *t_ptr;
c6468b47 549 }
1009bf5e 550 ps.want_blank = false;
c6468b47
KM
551 break;
552
1009bf5e
KM
553 case binary_op: /* any binary operation */
554 do_binary:
555 if (ps.want_blank)
c6468b47 556 *e_code++ = ' ';
1009bf5e
KM
557 {
558 char *res = token;
559
560 if (troff)
561 switch (token[0]) {
562 case '<':
563 if (token[1] == '=')
564 res = "\\(<=";
565 break;
566 case '>':
567 if (token[1] == '=')
568 res = "\\(>=";
569 break;
570 case '!':
571 if (token[1] == '=')
572 res = "\\(!=";
573 break;
574 case '|':
575 if (token[1] == '|')
576 res = "\\(br\\(br";
577 else if (token[1] == 0)
578 res = "\\(br";
579 break;
5c6e73ac
KM
580 case '-':
581 if (token[1] == '>')
582 res = "\\(->";
1009bf5e
KM
583 }
584 for (t_ptr = res; *t_ptr; ++t_ptr)
585 *e_code++ = *t_ptr; /* move the operator */
586 }
587 ps.want_blank = true;
c6468b47
KM
588 break;
589
1009bf5e 590 case postop: /* got a trailing ++ or -- */
c6468b47
KM
591 *e_code++ = token[0];
592 *e_code++ = token[1];
1009bf5e 593 ps.want_blank = true;
c6468b47
KM
594 break;
595
1009bf5e
KM
596 case question: /* got a ? */
597 squest++; /* this will be used when a later colon
598 * appears so we can distinguish the
599 * <c>?<n>:<n> construct */
600 if (ps.want_blank)
c6468b47
KM
601 *e_code++ = ' ';
602 *e_code++ = '?';
1009bf5e 603 ps.want_blank = true;
c6468b47
KM
604 break;
605
1009bf5e
KM
606 case casestmt: /* got word 'case' or 'default' */
607 scase = true; /* so we can process the later colon
608 * properly */
609 goto copy_id;
c6468b47 610
1009bf5e
KM
611 case colon: /* got a ':' */
612 if (squest > 0) { /* it is part of the <c>?<n>: <n>
613 * construct */
c6468b47 614 --squest;
1009bf5e 615 if (ps.want_blank)
c6468b47
KM
616 *e_code++ = ' ';
617 *e_code++ = ':';
1009bf5e 618 ps.want_blank = true;
c6468b47
KM
619 break;
620 }
1009bf5e
KM
621 if (ps.in_decl) {
622 *e_code++ = ':';
623 ps.want_blank = false;
624 break;
625 }
626 ps.in_stmt = false; /* seeing a label does not imply
627 * we are in a stmt */
c6468b47 628 for (t_ptr = s_code; *t_ptr; ++t_ptr)
1009bf5e
KM
629 *e_lab++ = *t_ptr; /* turn everything so far into a
630 * label */
c6468b47
KM
631 e_code = s_code;
632 *e_lab++ = ':';
633 *e_lab++ = ' ';
634 *e_lab = '\0';
635
1009bf5e
KM
636 force_nl = ps.pcase = scase; /* ps.pcase will be used
637 * by dump_line to decide
638 * how to indent the
639 * label. force_nl will
640 * force a case n: to be
641 * on a line by itself */
c6468b47 642 scase = false;
1009bf5e 643 ps.want_blank = false;
c6468b47
KM
644 break;
645
1009bf5e
KM
646 case semicolon: /* got a ';' */
647 ps.in_or_st = false; /* we are not in an initialization
648 * or structure declaration */
649 scase = false; /* these will only need resetting in a
650 * error */
c6468b47 651 squest = 0;
1009bf5e
KM
652 if (ps.last_token == rparen)
653 ps.in_parameter_declaration = 0;
654 ps.cast_mask = 0;
655 ps.sizeof_mask = 0;
656 ps.block_init = 0;
657 ps.just_saw_decl--;
658
659 if (ps.in_decl && s_code == e_code && !ps.block_init)
c6468b47
KM
660 while ((e_code - s_code) < (dec_ind - 1))
661 *e_code++ = ' ';
662
1009bf5e
KM
663 ps.in_decl = (ps.dec_nest > 0); /* if we were in a first
664 * level structure
665 * declaration, we arent
666 * any more */
667
668 if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
669
670 /*
671 * This should be true iff there were unbalanced
672 * parens in the stmt. It is a bit complicated,
673 * because the semicolon might be in a for stmt
674 */
675 diag(1, "Unbalanced parens");
676 ps.p_l_follow = 0;
677 if (sp_sw) {/* this is a check for a if, while, etc.
678 * with unbalanced parens */
c6468b47 679 sp_sw = false;
1009bf5e 680 parse(hd_type); /* dont lose the if, or whatever */
c6468b47
KM
681 }
682 }
c6468b47 683 *e_code++ = ';';
1009bf5e
KM
684 ps.want_blank = true;
685 ps.in_stmt = (ps.p_l_follow > 0); /* we are no longer in
686 * the middle of a stmt */
687
688 if (!sp_sw) { /* if not if for (;;) */
689 parse(semicolon); /* let parser know about end of
690 * stmt */
691 force_nl = true; /* force newline after a end of
692 * stmt */
c6468b47 693 }
c6468b47
KM
694 break;
695
1009bf5e
KM
696 case lbrace: /* got a '{' */
697 ps.in_stmt = false; /* dont indent the {} */
698 if (!ps.block_init)
699 force_nl = true; /* force other stuff on same line
700 * as '{' onto new line */
701
702 if (s_code != e_code && !ps.block_init) {
703 if (!btype_2) {
704 dump_line();
705 ps.want_blank = false;
706 } else if (ps.in_parameter_declaration && !ps.in_or_st) {
707 ps.i_l_follow = 0;
708 dump_line();
709 ps.want_blank = false;
710 }
c6468b47 711 }
1009bf5e
KM
712 if (ps.in_parameter_declaration)
713 prefix_blankline_requested = 0;
714
c93d6f87 715 if (ps.p_l_follow > 0) { /* check for preceding
1009bf5e
KM
716 * unbalanced parens */
717 diag(1, "Unbalanced parens");
718 ps.p_l_follow = 0;
719 if (sp_sw) {/* check for unclosed if, for, etc. */
c6468b47 720 sp_sw = false;
1009bf5e
KM
721 parse(hd_type);
722 ps.ind_level = ps.i_l_follow;
c6468b47
KM
723 }
724 }
c6468b47 725 if (s_code == e_code)
1009bf5e
KM
726 ps.ind_stmt = false; /* dont put extra
727 * indentation on line
728 * with '{' */
729 if (ps.in_decl && ps.in_or_st) { /* this is either a
730 * structure declaration
731 * or an init */
732 di_stack[ps.dec_nest++] = dec_ind;
c6468b47 733 dec_ind = 0;
1009bf5e
KM
734 } else {
735 ps.decl_on_line = false; /* we cant be in the
736 * middle of a
737 * declaration, so dont do
738 * special indentation of
739 * comments */
740 ps.in_parameter_declaration = 0;
c6468b47 741 }
1009bf5e
KM
742 parse(lbrace); /* let parser know about this */
743 if (ps.want_blank) /* put a blank before '{' if '{'
744 * is not at start of line */
c6468b47 745 *e_code++ = ' ';
1009bf5e 746 ps.want_blank = false;
c6468b47 747 *e_code++ = '{';
1009bf5e 748 ps.just_saw_decl = 0;
c6468b47
KM
749 break;
750
1009bf5e
KM
751 case rbrace: /* got a '}' */
752 if (ps.p_l_follow) { /* check for unclosed if, for,
753 * else. */
754 diag(1, "Unbalanced parens");
755 ps.p_l_follow = 0;
c6468b47
KM
756 sp_sw = false;
757 }
1009bf5e
KM
758 ps.just_saw_decl = 0;
759 if (s_code != e_code && !ps.block_init) { /* '}' must be first on
760 * line */
c6468b47 761 if (verbose)
1009bf5e
KM
762 diag(0, "Line broken");
763 dump_line();
c6468b47 764 }
c6468b47 765 *e_code++ = '}';
1009bf5e
KM
766 ps.want_blank = true;
767 ps.in_stmt = ps.ind_stmt = false;
768 if (ps.dec_nest > 0) { /* we are in multi-level structure
769 * declaration */
770 dec_ind = di_stack[--ps.dec_nest];
771 if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
772 ps.just_saw_decl = 2;
773 ps.in_decl = true;
c6468b47 774 }
1009bf5e
KM
775 prefix_blankline_requested = 0;
776 parse(rbrace); /* let parser know about this */
777 ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead && ps.il[ps.tos] >= ps.ind_level;
778 if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
779 postfix_blankline_requested = 1;
c6468b47
KM
780 break;
781
1009bf5e 782 case swstmt: /* got keyword "switch" */
c6468b47 783 sp_sw = true;
1009bf5e
KM
784 hd_type = swstmt; /* keep this for when we have seen
785 * the expression */
786 goto copy_id; /* go move the token into buffer */
c6468b47 787
1009bf5e
KM
788 case sp_paren: /* token is if, while, for */
789 sp_sw = true; /* the interesting stuff is done after the
790 * expression is scanned */
c6468b47 791 hd_type = (*token == 'i' ? ifstmt :
1009bf5e
KM
792 (*token == 'w' ? whilestmt : forstmt));
793
794 /*
795 * remember the type of header for later use by parser
796 */
797 goto copy_id; /* copy the token into line */
798
799 case sp_nparen: /* got else, do */
800 ps.in_stmt = false;
801 if (*token == 'e') {
802 if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
803 if (verbose)
804 diag(0, "Line broken");
805 dump_line(); /* make sure this starts a line */
806 ps.want_blank = false;
807 }
808 force_nl = true; /* also, following stuff must go
809 * onto new line */
810 last_else = 1;
811 parse(elselit);
812 } else {
813 if (e_code != s_code) { /* make sure this starts a
814 * line */
815 if (verbose)
816 diag(0, "Line broken");
817 dump_line();
818 ps.want_blank = false;
819 }
820 force_nl = true; /* also, following stuff must go
821 * onto new line */
822 last_else = 0;
823 parse(dolit);
c6468b47 824 }
1009bf5e
KM
825 goto copy_id; /* move the token into line */
826
827 case decl: /* we have a declaration type (int,
828 * register, etc.) */
829 parse(decl); /* let parser worry about indentation */
830 if (ps.last_token == rparen && ps.tos <= 1)
831 ps.in_parameter_declaration = 1;
832 if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) {
833 ps.ind_level = ps.i_l_follow = 1;
834 ps.ind_stmt = 0;
835 }
836 ps.in_or_st = true; /* this might be a structure or
837 * initialization declaration */
838 ps.in_decl = ps.decl_on_line = true;
839 if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
840 ps.just_saw_decl = 2;
841 prefix_blankline_requested = 0;
842 for (i = 0; token[i++];); /* get length of token */
843
844 /*
845 * dec_ind = e_code - s_code + (ps.decl_indent>i ?
846 * ps.decl_indent : i);
847 */
848 dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
c6468b47
KM
849 goto copy_id;
850
1009bf5e
KM
851 case ident: /* got an identifier or constant */
852 if (ps.in_decl) { /* if we are in a declaration, we
853 * must indent identifier */
854 if (ps.want_blank)
c6468b47 855 *e_code++ = ' ';
1009bf5e
KM
856 ps.want_blank = false;
857 if (is_procname == 0 || !procnames_start_line) {
858 if (!ps.block_init)
859 if (troff && !ps.dumped_decl_indent) {
860 sprintf(e_code, "\\c\n.De %dp+\200p\n", dec_ind * 7);
861 ps.dumped_decl_indent = 1;
862 e_code += strlen(e_code);
863 } else
864 while ((e_code - s_code) < dec_ind)
865 *e_code++ = ' ';
866 } else {
867 if (dec_ind && s_code != e_code)
868 dump_line();
869 dec_ind = 0;
870 ps.want_blank = false;
c6468b47 871 }
1009bf5e
KM
872 } else if (sp_sw && ps.p_l_follow == 0) {
873 sp_sw = false;
874 force_nl = true;
875 ps.last_u_d = true;
876 ps.in_stmt = false;
877 parse(hd_type);
878 }
879 copy_id:
880 if (ps.want_blank)
c6468b47 881 *e_code++ = ' ';
1009bf5e
KM
882 if (troff && ps.its_a_keyword) {
883 *e_code++ = BACKSLASH;
884 *e_code++ = 'f';
885 *e_code++ = 'B';
886 }
c6468b47
KM
887 for (t_ptr = token; *t_ptr; ++t_ptr)
888 *e_code++ = *t_ptr;
1009bf5e
KM
889 if (troff && ps.its_a_keyword) {
890 *e_code++ = BACKSLASH;
891 *e_code++ = 'f';
892 *e_code++ = 'R';
893 }
894 ps.want_blank = true;
c6468b47
KM
895 break;
896
1009bf5e
KM
897 case period: /* treat a period kind of like a binary
898 * operation */
899 *e_code++ = '.';/* move the period into line */
900 ps.want_blank = false; /* dont put a blank after a period */
c6468b47
KM
901 break;
902
1009bf5e
KM
903 case comma:
904 ps.want_blank = (s_code != e_code); /* only put blank after
905 * comma if comma does
906 * not start the line */
907 if (ps.in_decl && is_procname == 0 && !ps.block_init)
c6468b47
KM
908 while ((e_code - s_code) < (dec_ind - 1))
909 *e_code++ = ' ';
910
911 *e_code++ = ',';
1009bf5e
KM
912 if (ps.p_l_follow == 0) {
913 ps.block_init = 0;
914 if (break_comma && !ps.leave_comma)
915 force_nl = true;
916 }
c6468b47
KM
917 break;
918
1009bf5e
KM
919 case preesc: /* got the character '#' */
920 if ((s_com != e_com) ||
921 (s_lab != e_lab) ||
922 (s_code != e_code))
923 dump_line();
924 *e_lab++ = '#'; /* move whole line to 'label' buffer */
925 {
926 int in_comment = 0;
927 char *com_start = 0;
928 char quote = 0;
929 char *com_end = 0;
930
931 while (*buf_ptr != '\n' || in_comment) {
932 *e_lab = *buf_ptr++;
933 if (buf_ptr >= buf_end)
934 fill_buffer();
935 switch (*e_lab++) {
936 case BACKSLASH:
937 if (troff)
938 *e_lab++ = BACKSLASH;
939 if (!in_comment) {
940 *e_lab++ = *buf_ptr++;
941 if (buf_ptr >= buf_end)
942 fill_buffer();
943 }
944 break;
945 case '/':
946 if (*buf_ptr == '*' && !in_comment && !quote) {
947 in_comment = 1;
948 *e_lab++ = *buf_ptr++;
949 com_start = e_lab - 2;
950 }
951 break;
952 case '"':
953 if (quote == '"')
954 quote = 0;
955 break;
956 case '\'':
957 if (quote == '\'')
958 quote = 0;
959 break;
960 case '*':
961 if (*buf_ptr == '/' && in_comment) {
962 in_comment = 0;
963 *e_lab++ = *buf_ptr++;
964 com_end = e_lab;
965 }
966 break;
967 }
968 }
969 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
970 e_lab--;
971 if (e_lab == com_end && bp_save == 0) { /* comment on
972 * preprocessor line */
973 if (sc_end == 0) /* if this is the first
974 * comment, we must set up
975 * the buffer */
976 sc_end = &(save_com[0]);
977 else {
978 *sc_end++ = '\n'; /* add newline between
979 * comments */
980 *sc_end++ = ' ';
981 --line_no;
982 }
983 bcopy(com_start, sc_end, com_end - com_start);
984 sc_end += com_end - com_start;
985 e_lab = com_start;
986 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
987 e_lab--;
988 bp_save = buf_ptr; /* save current input
989 * buffer */
990 be_save = buf_end;
991 buf_ptr = save_com; /* fix so that subsequent
992 * calls to lexi will take
993 * tokens out of save_com */
994 *sc_end++ = ' '; /* add trailing blank,
995 * just in case */
996 buf_end = sc_end;
997 sc_end = 0;
998 }
999 *e_lab = '\0'; /* null terminate line */
1000 ps.pcase = false;
c6468b47 1001 }
1009bf5e
KM
1002 if (strncmp(s_lab, "#if", 3) == 0)
1003 if (ifdef_level < sizeof state_stack / sizeof state_stack[0]) {
1004 match_state[ifdef_level].tos = -1;
1005 state_stack[ifdef_level++] = ps;
1006 } else
1007 diag(1, "#if stack overflow");
1008 else if (strncmp(s_lab, "#else", 5) == 0)
1009 if (ifdef_level <= 0)
1010 diag(1, "Unmatched #else");
1011 else {
1012 match_state[ifdef_level - 1] = ps;
1013 ps = state_stack[ifdef_level - 1];
1014 } else if (strncmp(s_lab, "#endif", 6) == 0)
1015 if (ifdef_level <= 0)
1016 diag(1, "Unmatched #endif");
1017 else {
1018 ifdef_level--;
1019#ifdef undef
1020
1021 /*
1022 * This match needs to be more intelligent before
1023 * the message is useful
1024 */
1025 if (match_state[ifdef_level].tos >= 0
1026 && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
1027 diag(0, "Syntactically inconsistant #ifdef alternatives.");
1028#endif
c6468b47 1029 }
1009bf5e
KM
1030 break; /* subsequent processing of the newline
1031 * character will cause the line to be
1032 * printed */
1033
1034 case comment: /* we have gotten a /* this is a biggie */
1035 proc_comment:
1036 if (flushed_nl) { /* we should force a broken line
1037 * here */
1038 flushed_nl = false;
1039 dump_line();
1040 ps.want_blank = false; /* dont insert blank at
1041 * line start */
1042 force_nl = false;
c6468b47 1043 }
1009bf5e 1044 pr_comment();
c6468b47 1045 break;
1009bf5e
KM
1046 } /* end of big switch stmt */
1047 *e_code = '\0'; /* make sure code section is null
1048 * terminated */
1049 if (type_code != comment && type_code != newline && type_code != preesc)
1050 ps.last_token = type_code;
1051 } /* end of main while (1) loop */
c6468b47
KM
1052};
1053
1054/*
c93d6f87
KM
1055 * copy input file to backup file. If in_name is /blah/blah/blah/file, then
1056 * backup file will be "file.BAK". Then make the backup file the input and
1057 * original input file the output.
c6468b47 1058 */
1009bf5e
KM
1059bakcopy()
1060{
1061 int n,
1062 bakchn;
c93d6f87 1063 char buff[BUFSIZ];
1009bf5e 1064 register char *p;
c93d6f87 1065 char *rindex();
1009bf5e 1066
c93d6f87 1067 if ((p = rindex(in_name, '/')) != NULL)
c6468b47 1068 p++;
c93d6f87
KM
1069 else
1070 p = in_name;
1009bf5e 1071 sprintf(bakfile, "%s.BAK", p);
c6468b47 1072
1009bf5e
KM
1073 /* copy in_name to backup file */
1074 bakchn = creat(bakfile, 0600);
c6468b47 1075 if (bakchn < 0) {
c93d6f87
KM
1076 fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
1077 exit(1);
1078 }
1079 while ((n = read(fileno(input), buff, sizeof buff)) > 0)
1080 if (write(bakchn, buff, n) != n) {
1081 fprintf(stderr, "indent: error writing backup file \"%s\"\n",
1082 bakfile);
1083 exit(1);
1084 }
1085 if (n < 0) {
1086 fprintf(stderr, "indent: error reading input file \"%s\"\n", in_name);
1087 exit(1);
c6468b47 1088 }
1009bf5e
KM
1089 close(bakchn);
1090 fclose(input);
c6468b47 1091
1009bf5e
KM
1092 /* re-open backup file as the input file */
1093 input = fopen(bakfile, "r");
c93d6f87
KM
1094 if (input == NULL) {
1095 fprintf(stderr, "indent: can't re-open backup file\n");
1096 exit(1);
c6468b47 1097 }
1009bf5e
KM
1098 /* now the original input file will be the output */
1099 output = fopen(in_name, "w");
c93d6f87
KM
1100 if (output == NULL) {
1101 fprintf(stderr, "indent: can't create %s\n", in_name);
1009bf5e 1102 unlink(bakfile);
c93d6f87 1103 exit(1);
c6468b47
KM
1104 }
1105}