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