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