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