further update by Chris Torek
[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
c93d6f87 14static char sccsid[] = "@(#)indent.c 5.3 (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
KM
59{
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);
c93d6f87 388 exit(ps.tos <= 1);
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;
579 }
580 for (t_ptr = res; *t_ptr; ++t_ptr)
581 *e_code++ = *t_ptr; /* move the operator */
582 }
583 ps.want_blank = true;
c6468b47
KM
584 break;
585
1009bf5e 586 case postop: /* got a trailing ++ or -- */
c6468b47
KM
587 *e_code++ = token[0];
588 *e_code++ = token[1];
1009bf5e 589 ps.want_blank = true;
c6468b47
KM
590 break;
591
1009bf5e
KM
592 case question: /* got a ? */
593 squest++; /* this will be used when a later colon
594 * appears so we can distinguish the
595 * <c>?<n>:<n> construct */
596 if (ps.want_blank)
c6468b47
KM
597 *e_code++ = ' ';
598 *e_code++ = '?';
1009bf5e 599 ps.want_blank = true;
c6468b47
KM
600 break;
601
1009bf5e
KM
602 case casestmt: /* got word 'case' or 'default' */
603 scase = true; /* so we can process the later colon
604 * properly */
605 goto copy_id;
c6468b47 606
1009bf5e
KM
607 case colon: /* got a ':' */
608 if (squest > 0) { /* it is part of the <c>?<n>: <n>
609 * construct */
c6468b47 610 --squest;
1009bf5e 611 if (ps.want_blank)
c6468b47
KM
612 *e_code++ = ' ';
613 *e_code++ = ':';
1009bf5e 614 ps.want_blank = true;
c6468b47
KM
615 break;
616 }
1009bf5e
KM
617 if (ps.in_decl) {
618 *e_code++ = ':';
619 ps.want_blank = false;
620 break;
621 }
622 ps.in_stmt = false; /* seeing a label does not imply
623 * we are in a stmt */
c6468b47 624 for (t_ptr = s_code; *t_ptr; ++t_ptr)
1009bf5e
KM
625 *e_lab++ = *t_ptr; /* turn everything so far into a
626 * label */
c6468b47
KM
627 e_code = s_code;
628 *e_lab++ = ':';
629 *e_lab++ = ' ';
630 *e_lab = '\0';
631
1009bf5e
KM
632 force_nl = ps.pcase = scase; /* ps.pcase will be used
633 * by dump_line to decide
634 * how to indent the
635 * label. force_nl will
636 * force a case n: to be
637 * on a line by itself */
c6468b47 638 scase = false;
1009bf5e 639 ps.want_blank = false;
c6468b47
KM
640 break;
641
1009bf5e
KM
642 case semicolon: /* got a ';' */
643 ps.in_or_st = false; /* we are not in an initialization
644 * or structure declaration */
645 scase = false; /* these will only need resetting in a
646 * error */
c6468b47 647 squest = 0;
1009bf5e
KM
648 if (ps.last_token == rparen)
649 ps.in_parameter_declaration = 0;
650 ps.cast_mask = 0;
651 ps.sizeof_mask = 0;
652 ps.block_init = 0;
653 ps.just_saw_decl--;
654
655 if (ps.in_decl && s_code == e_code && !ps.block_init)
c6468b47
KM
656 while ((e_code - s_code) < (dec_ind - 1))
657 *e_code++ = ' ';
658
1009bf5e
KM
659 ps.in_decl = (ps.dec_nest > 0); /* if we were in a first
660 * level structure
661 * declaration, we arent
662 * any more */
663
664 if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
665
666 /*
667 * This should be true iff there were unbalanced
668 * parens in the stmt. It is a bit complicated,
669 * because the semicolon might be in a for stmt
670 */
671 diag(1, "Unbalanced parens");
672 ps.p_l_follow = 0;
673 if (sp_sw) {/* this is a check for a if, while, etc.
674 * with unbalanced parens */
c6468b47 675 sp_sw = false;
1009bf5e 676 parse(hd_type); /* dont lose the if, or whatever */
c6468b47
KM
677 }
678 }
c6468b47 679 *e_code++ = ';';
1009bf5e
KM
680 ps.want_blank = true;
681 ps.in_stmt = (ps.p_l_follow > 0); /* we are no longer in
682 * the middle of a stmt */
683
684 if (!sp_sw) { /* if not if for (;;) */
685 parse(semicolon); /* let parser know about end of
686 * stmt */
687 force_nl = true; /* force newline after a end of
688 * stmt */
c6468b47 689 }
c6468b47
KM
690 break;
691
1009bf5e
KM
692 case lbrace: /* got a '{' */
693 ps.in_stmt = false; /* dont indent the {} */
694 if (!ps.block_init)
695 force_nl = true; /* force other stuff on same line
696 * as '{' onto new line */
697
698 if (s_code != e_code && !ps.block_init) {
699 if (!btype_2) {
700 dump_line();
701 ps.want_blank = false;
702 } else if (ps.in_parameter_declaration && !ps.in_or_st) {
703 ps.i_l_follow = 0;
704 dump_line();
705 ps.want_blank = false;
706 }
c6468b47 707 }
1009bf5e
KM
708 if (ps.in_parameter_declaration)
709 prefix_blankline_requested = 0;
710
c93d6f87 711 if (ps.p_l_follow > 0) { /* check for preceding
1009bf5e
KM
712 * unbalanced parens */
713 diag(1, "Unbalanced parens");
714 ps.p_l_follow = 0;
715 if (sp_sw) {/* check for unclosed if, for, etc. */
c6468b47 716 sp_sw = false;
1009bf5e
KM
717 parse(hd_type);
718 ps.ind_level = ps.i_l_follow;
c6468b47
KM
719 }
720 }
c6468b47 721 if (s_code == e_code)
1009bf5e
KM
722 ps.ind_stmt = false; /* dont put extra
723 * indentation on line
724 * with '{' */
725 if (ps.in_decl && ps.in_or_st) { /* this is either a
726 * structure declaration
727 * or an init */
728 di_stack[ps.dec_nest++] = dec_ind;
c6468b47 729 dec_ind = 0;
1009bf5e
KM
730 } else {
731 ps.decl_on_line = false; /* we cant be in the
732 * middle of a
733 * declaration, so dont do
734 * special indentation of
735 * comments */
736 ps.in_parameter_declaration = 0;
c6468b47 737 }
1009bf5e
KM
738 parse(lbrace); /* let parser know about this */
739 if (ps.want_blank) /* put a blank before '{' if '{'
740 * is not at start of line */
c6468b47 741 *e_code++ = ' ';
1009bf5e 742 ps.want_blank = false;
c6468b47 743 *e_code++ = '{';
1009bf5e 744 ps.just_saw_decl = 0;
c6468b47
KM
745 break;
746
1009bf5e
KM
747 case rbrace: /* got a '}' */
748 if (ps.p_l_follow) { /* check for unclosed if, for,
749 * else. */
750 diag(1, "Unbalanced parens");
751 ps.p_l_follow = 0;
c6468b47
KM
752 sp_sw = false;
753 }
1009bf5e
KM
754 ps.just_saw_decl = 0;
755 if (s_code != e_code && !ps.block_init) { /* '}' must be first on
756 * line */
c6468b47 757 if (verbose)
1009bf5e
KM
758 diag(0, "Line broken");
759 dump_line();
c6468b47 760 }
c6468b47 761 *e_code++ = '}';
1009bf5e
KM
762 ps.want_blank = true;
763 ps.in_stmt = ps.ind_stmt = false;
764 if (ps.dec_nest > 0) { /* we are in multi-level structure
765 * declaration */
766 dec_ind = di_stack[--ps.dec_nest];
767 if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
768 ps.just_saw_decl = 2;
769 ps.in_decl = true;
c6468b47 770 }
1009bf5e
KM
771 prefix_blankline_requested = 0;
772 parse(rbrace); /* let parser know about this */
773 ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead && ps.il[ps.tos] >= ps.ind_level;
774 if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
775 postfix_blankline_requested = 1;
c6468b47
KM
776 break;
777
1009bf5e 778 case swstmt: /* got keyword "switch" */
c6468b47 779 sp_sw = true;
1009bf5e
KM
780 hd_type = swstmt; /* keep this for when we have seen
781 * the expression */
782 goto copy_id; /* go move the token into buffer */
c6468b47 783
1009bf5e
KM
784 case sp_paren: /* token is if, while, for */
785 sp_sw = true; /* the interesting stuff is done after the
786 * expression is scanned */
c6468b47 787 hd_type = (*token == 'i' ? ifstmt :
1009bf5e
KM
788 (*token == 'w' ? whilestmt : forstmt));
789
790 /*
791 * remember the type of header for later use by parser
792 */
793 goto copy_id; /* copy the token into line */
794
795 case sp_nparen: /* got else, do */
796 ps.in_stmt = false;
797 if (*token == 'e') {
798 if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
799 if (verbose)
800 diag(0, "Line broken");
801 dump_line(); /* make sure this starts a line */
802 ps.want_blank = false;
803 }
804 force_nl = true; /* also, following stuff must go
805 * onto new line */
806 last_else = 1;
807 parse(elselit);
808 } else {
809 if (e_code != s_code) { /* make sure this starts a
810 * line */
811 if (verbose)
812 diag(0, "Line broken");
813 dump_line();
814 ps.want_blank = false;
815 }
816 force_nl = true; /* also, following stuff must go
817 * onto new line */
818 last_else = 0;
819 parse(dolit);
c6468b47 820 }
1009bf5e
KM
821 goto copy_id; /* move the token into line */
822
823 case decl: /* we have a declaration type (int,
824 * register, etc.) */
825 parse(decl); /* let parser worry about indentation */
826 if (ps.last_token == rparen && ps.tos <= 1)
827 ps.in_parameter_declaration = 1;
828 if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) {
829 ps.ind_level = ps.i_l_follow = 1;
830 ps.ind_stmt = 0;
831 }
832 ps.in_or_st = true; /* this might be a structure or
833 * initialization declaration */
834 ps.in_decl = ps.decl_on_line = true;
835 if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
836 ps.just_saw_decl = 2;
837 prefix_blankline_requested = 0;
838 for (i = 0; token[i++];); /* get length of token */
839
840 /*
841 * dec_ind = e_code - s_code + (ps.decl_indent>i ?
842 * ps.decl_indent : i);
843 */
844 dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
c6468b47
KM
845 goto copy_id;
846
1009bf5e
KM
847 case ident: /* got an identifier or constant */
848 if (ps.in_decl) { /* if we are in a declaration, we
849 * must indent identifier */
850 if (ps.want_blank)
c6468b47 851 *e_code++ = ' ';
1009bf5e
KM
852 ps.want_blank = false;
853 if (is_procname == 0 || !procnames_start_line) {
854 if (!ps.block_init)
855 if (troff && !ps.dumped_decl_indent) {
856 sprintf(e_code, "\\c\n.De %dp+\200p\n", dec_ind * 7);
857 ps.dumped_decl_indent = 1;
858 e_code += strlen(e_code);
859 } else
860 while ((e_code - s_code) < dec_ind)
861 *e_code++ = ' ';
862 } else {
863 if (dec_ind && s_code != e_code)
864 dump_line();
865 dec_ind = 0;
866 ps.want_blank = false;
c6468b47 867 }
1009bf5e
KM
868 } else if (sp_sw && ps.p_l_follow == 0) {
869 sp_sw = false;
870 force_nl = true;
871 ps.last_u_d = true;
872 ps.in_stmt = false;
873 parse(hd_type);
874 }
875 copy_id:
876 if (ps.want_blank)
c6468b47 877 *e_code++ = ' ';
1009bf5e
KM
878 if (troff && ps.its_a_keyword) {
879 *e_code++ = BACKSLASH;
880 *e_code++ = 'f';
881 *e_code++ = 'B';
882 }
c6468b47
KM
883 for (t_ptr = token; *t_ptr; ++t_ptr)
884 *e_code++ = *t_ptr;
1009bf5e
KM
885 if (troff && ps.its_a_keyword) {
886 *e_code++ = BACKSLASH;
887 *e_code++ = 'f';
888 *e_code++ = 'R';
889 }
890 ps.want_blank = true;
c6468b47
KM
891 break;
892
1009bf5e
KM
893 case period: /* treat a period kind of like a binary
894 * operation */
895 *e_code++ = '.';/* move the period into line */
896 ps.want_blank = false; /* dont put a blank after a period */
c6468b47
KM
897 break;
898
1009bf5e
KM
899 case comma:
900 ps.want_blank = (s_code != e_code); /* only put blank after
901 * comma if comma does
902 * not start the line */
903 if (ps.in_decl && is_procname == 0 && !ps.block_init)
c6468b47
KM
904 while ((e_code - s_code) < (dec_ind - 1))
905 *e_code++ = ' ';
906
907 *e_code++ = ',';
1009bf5e
KM
908 if (ps.p_l_follow == 0) {
909 ps.block_init = 0;
910 if (break_comma && !ps.leave_comma)
911 force_nl = true;
912 }
c6468b47
KM
913 break;
914
1009bf5e
KM
915 case preesc: /* got the character '#' */
916 if ((s_com != e_com) ||
917 (s_lab != e_lab) ||
918 (s_code != e_code))
919 dump_line();
920 *e_lab++ = '#'; /* move whole line to 'label' buffer */
921 {
922 int in_comment = 0;
923 char *com_start = 0;
924 char quote = 0;
925 char *com_end = 0;
926
927 while (*buf_ptr != '\n' || in_comment) {
928 *e_lab = *buf_ptr++;
929 if (buf_ptr >= buf_end)
930 fill_buffer();
931 switch (*e_lab++) {
932 case BACKSLASH:
933 if (troff)
934 *e_lab++ = BACKSLASH;
935 if (!in_comment) {
936 *e_lab++ = *buf_ptr++;
937 if (buf_ptr >= buf_end)
938 fill_buffer();
939 }
940 break;
941 case '/':
942 if (*buf_ptr == '*' && !in_comment && !quote) {
943 in_comment = 1;
944 *e_lab++ = *buf_ptr++;
945 com_start = e_lab - 2;
946 }
947 break;
948 case '"':
949 if (quote == '"')
950 quote = 0;
951 break;
952 case '\'':
953 if (quote == '\'')
954 quote = 0;
955 break;
956 case '*':
957 if (*buf_ptr == '/' && in_comment) {
958 in_comment = 0;
959 *e_lab++ = *buf_ptr++;
960 com_end = e_lab;
961 }
962 break;
963 }
964 }
965 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
966 e_lab--;
967 if (e_lab == com_end && bp_save == 0) { /* comment on
968 * preprocessor line */
969 if (sc_end == 0) /* if this is the first
970 * comment, we must set up
971 * the buffer */
972 sc_end = &(save_com[0]);
973 else {
974 *sc_end++ = '\n'; /* add newline between
975 * comments */
976 *sc_end++ = ' ';
977 --line_no;
978 }
979 bcopy(com_start, sc_end, com_end - com_start);
980 sc_end += com_end - com_start;
981 e_lab = com_start;
982 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
983 e_lab--;
984 bp_save = buf_ptr; /* save current input
985 * buffer */
986 be_save = buf_end;
987 buf_ptr = save_com; /* fix so that subsequent
988 * calls to lexi will take
989 * tokens out of save_com */
990 *sc_end++ = ' '; /* add trailing blank,
991 * just in case */
992 buf_end = sc_end;
993 sc_end = 0;
994 }
995 *e_lab = '\0'; /* null terminate line */
996 ps.pcase = false;
c6468b47 997 }
1009bf5e
KM
998 if (strncmp(s_lab, "#if", 3) == 0)
999 if (ifdef_level < sizeof state_stack / sizeof state_stack[0]) {
1000 match_state[ifdef_level].tos = -1;
1001 state_stack[ifdef_level++] = ps;
1002 } else
1003 diag(1, "#if stack overflow");
1004 else if (strncmp(s_lab, "#else", 5) == 0)
1005 if (ifdef_level <= 0)
1006 diag(1, "Unmatched #else");
1007 else {
1008 match_state[ifdef_level - 1] = ps;
1009 ps = state_stack[ifdef_level - 1];
1010 } else if (strncmp(s_lab, "#endif", 6) == 0)
1011 if (ifdef_level <= 0)
1012 diag(1, "Unmatched #endif");
1013 else {
1014 ifdef_level--;
1015#ifdef undef
1016
1017 /*
1018 * This match needs to be more intelligent before
1019 * the message is useful
1020 */
1021 if (match_state[ifdef_level].tos >= 0
1022 && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
1023 diag(0, "Syntactically inconsistant #ifdef alternatives.");
1024#endif
c6468b47 1025 }
1009bf5e
KM
1026 break; /* subsequent processing of the newline
1027 * character will cause the line to be
1028 * printed */
1029
1030 case comment: /* we have gotten a /* this is a biggie */
1031 proc_comment:
1032 if (flushed_nl) { /* we should force a broken line
1033 * here */
1034 flushed_nl = false;
1035 dump_line();
1036 ps.want_blank = false; /* dont insert blank at
1037 * line start */
1038 force_nl = false;
c6468b47 1039 }
1009bf5e 1040 pr_comment();
c6468b47 1041 break;
1009bf5e
KM
1042 } /* end of big switch stmt */
1043 *e_code = '\0'; /* make sure code section is null
1044 * terminated */
1045 if (type_code != comment && type_code != newline && type_code != preesc)
1046 ps.last_token = type_code;
1047 } /* end of main while (1) loop */
c6468b47
KM
1048};
1049
1050/*
c93d6f87
KM
1051 * copy input file to backup file. If in_name is /blah/blah/blah/file, then
1052 * backup file will be "file.BAK". Then make the backup file the input and
1053 * original input file the output.
c6468b47 1054 */
1009bf5e
KM
1055bakcopy()
1056{
1057 int n,
1058 bakchn;
c93d6f87 1059 char buff[BUFSIZ];
1009bf5e 1060 register char *p;
c93d6f87 1061 char *rindex();
1009bf5e 1062
c93d6f87 1063 if ((p = rindex(in_name, '/')) != NULL)
c6468b47 1064 p++;
c93d6f87
KM
1065 else
1066 p = in_name;
1009bf5e 1067 sprintf(bakfile, "%s.BAK", p);
c6468b47 1068
1009bf5e
KM
1069 /* copy in_name to backup file */
1070 bakchn = creat(bakfile, 0600);
c6468b47 1071 if (bakchn < 0) {
c93d6f87
KM
1072 fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
1073 exit(1);
1074 }
1075 while ((n = read(fileno(input), buff, sizeof buff)) > 0)
1076 if (write(bakchn, buff, n) != n) {
1077 fprintf(stderr, "indent: error writing backup file \"%s\"\n",
1078 bakfile);
1079 exit(1);
1080 }
1081 if (n < 0) {
1082 fprintf(stderr, "indent: error reading input file \"%s\"\n", in_name);
1083 exit(1);
c6468b47 1084 }
1009bf5e
KM
1085 close(bakchn);
1086 fclose(input);
c6468b47 1087
1009bf5e
KM
1088 /* re-open backup file as the input file */
1089 input = fopen(bakfile, "r");
c93d6f87
KM
1090 if (input == NULL) {
1091 fprintf(stderr, "indent: can't re-open backup file\n");
1092 exit(1);
c6468b47 1093 }
1009bf5e
KM
1094 /* now the original input file will be the output */
1095 output = fopen(in_name, "w");
c93d6f87
KM
1096 if (output == NULL) {
1097 fprintf(stderr, "indent: can't create %s\n", in_name);
1009bf5e 1098 unlink(bakfile);
c93d6f87 1099 exit(1);
c6468b47
KM
1100 }
1101}