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