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