indent.c revision 1.24 1 /* $NetBSD: indent.c,v 1.24 2019/02/03 03:19:29 mrg 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.\
69 Copyright (c) 1976 Board of Trustees of the University of Illinois.\
70 Copyright (c) 1980, 1993\
71 The Regents of the University of California. All rights reserved.");
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.24 2019/02/03 03:19:29 mrg 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 const char *in_name = "Standard Input"; /* will always point to name of
98 * input file */
99 const char *out_name = "Standard Output"; /* will always point to name of
100 * output file */
101 char bakfile[MAXPATHLEN] = "";
102
103 int
104 main(int argc, char **argv)
105 {
106
107 extern int found_err; /* flag set in diag() on error */
108 int dec_ind; /* current indentation for declarations */
109 int di_stack[20]; /* a stack of structure indentation levels */
110 int flushed_nl; /* used when buffering up comments to remember
111 * that a newline was passed over */
112 int force_nl; /* when true, code must be broken */
113 int hd_type; /* used to store type of stmt for if (...),
114 * for (...), etc */
115 int i; /* local loop counter */
116 int scase; /* set to true when we see a case, so we will
117 * know what to do with the following colon */
118 int sp_sw; /* when true, we are in the expressin of
119 * if(...), while(...), etc. */
120 int squest; /* when this is positive, we have seen a ?
121 * without the matching : in a <c>?<s>:<s>
122 * construct */
123 const char *t_ptr; /* used for copying tokens */
124 int tabs_to_var = 0; /* true if using tabs to indent to var name */
125 int type_code; /* the type of token, returned by lexi */
126
127 int last_else = 0; /* true iff last keyword was an else */
128
129
130 /*-----------------------------------------------*\
131 | INITIALIZATION |
132 \*-----------------------------------------------*/
133
134 if (!setlocale(LC_ALL, ""))
135 warnx("can't set locale.");
136
137 hd_type = 0;
138 ps.p_stack[0] = stmt; /* this is the parser's stack */
139 ps.last_nl = true; /* this is true if the last thing scanned was
140 * a newline */
141 ps.last_token = semicolon;
142 combuf = (char *) malloc(bufsize);
143 labbuf = (char *) malloc(bufsize);
144 codebuf = (char *) malloc(bufsize);
145 tokenbuf = (char *) malloc(bufsize);
146 l_com = combuf + bufsize - 5;
147 l_lab = labbuf + bufsize - 5;
148 l_code = codebuf + bufsize - 5;
149 l_token = tokenbuf + bufsize - 5;
150 combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label,
151 * and comment buffers */
152 combuf[1] = codebuf[1] = labbuf[1] = '\0';
153 ps.else_if = 1; /* Default else-if special processing to on */
154 s_lab = e_lab = labbuf + 1;
155 s_code = e_code = codebuf + 1;
156 s_com = e_com = combuf + 1;
157 s_token = e_token = tokenbuf + 1;
158
159 in_buffer = (char *) malloc(10);
160 in_buffer_limit = in_buffer + 8;
161 buf_ptr = buf_end = in_buffer;
162 line_no = 1;
163 had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
164 sp_sw = force_nl = false;
165 ps.in_or_st = false;
166 ps.bl_line = true;
167 dec_ind = 0;
168 di_stack[ps.dec_nest = 0] = 0;
169 ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
170
171
172 scase = ps.pcase = false;
173 squest = 0;
174 sc_end = 0;
175 bp_save = 0;
176 be_save = 0;
177
178 output = 0;
179
180
181
182 /*--------------------------------------------------*\
183 | COMMAND LINE SCAN |
184 \*--------------------------------------------------*/
185
186 #ifdef undef
187 max_col = 78; /* -l78 */
188 lineup_to_parens = 1; /* -lp */
189 ps.ljust_decl = 0; /* -ndj */
190 ps.com_ind = 33; /* -c33 */
191 star_comment_cont = 1; /* -sc */
192 ps.ind_size = 8; /* -i8 */
193 verbose = 0;
194 ps.decl_indent = 16; /* -di16 */
195 ps.indent_parameters = 1; /* -ip */
196 ps.decl_com_ind = 0; /* if this is not set to some positive value
197 * by an arg, we will set this equal to
198 * ps.com_ind */
199 btype_2 = 1; /* -br */
200 cuddle_else = 1; /* -ce */
201 ps.unindent_displace = 0; /* -d0 */
202 ps.case_indent = 0; /* -cli0 */
203 format_col1_comments = 1; /* -fc1 */
204 procnames_start_line = 1; /* -psl */
205 proc_calls_space = 0; /* -npcs */
206 comment_delimiter_on_blankline = 1; /* -cdb */
207 ps.leave_comma = 1; /* -nbc */
208 #endif
209
210 for (i = 1; i < argc; ++i)
211 if (strcmp(argv[i], "-npro") == 0)
212 break;
213 set_defaults();
214 if (i >= argc)
215 set_profile();
216
217 for (i = 1; i < argc; ++i) {
218
219 /*
220 * look thru args (if any) for changes to defaults
221 */
222 if (argv[i][0] != '-') { /* no flag on parameter */
223 if (input == 0) { /* we must have the input file */
224 in_name = argv[i]; /* remember name of
225 * input file */
226 input = fopen(in_name, "r");
227 if (input == 0) /* check for open error */
228 err(1, "%s", in_name);
229 continue;
230 } else
231 if (output == 0) { /* we have the output
232 * file */
233 out_name = argv[i]; /* remember name of
234 * output file */
235 if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite
236 * the file */
237 errx(1, "input and output files must be different");
238 }
239 output = fopen(out_name, "w");
240 if (output == 0) /* check for create
241 * error */
242 err(1, "%s", out_name);
243 continue;
244 }
245 errx(1, "unknown parameter: %s", argv[i]);
246 } else
247 set_option(argv[i]);
248 } /* end of for */
249 if (input == 0) {
250 input = stdin;
251 }
252 if (output == 0) {
253 if (troff || input == stdin)
254 output = stdout;
255 else {
256 out_name = in_name;
257 bakcopy();
258 }
259 }
260 if (ps.com_ind <= 1)
261 ps.com_ind = 2; /* don't put normal comments before column 2 */
262 if (troff) {
263 if (bodyf.font[0] == 0)
264 parsefont(&bodyf, "R");
265 if (scomf.font[0] == 0)
266 parsefont(&scomf, "I");
267 if (blkcomf.font[0] == 0)
268 blkcomf = scomf, blkcomf.size += 2;
269 if (boxcomf.font[0] == 0)
270 boxcomf = blkcomf;
271 if (stringf.font[0] == 0)
272 parsefont(&stringf, "L");
273 if (keywordf.font[0] == 0)
274 parsefont(&keywordf, "B");
275 writefdef(&bodyf, 'B');
276 writefdef(&scomf, 'C');
277 writefdef(&blkcomf, 'L');
278 writefdef(&boxcomf, 'X');
279 writefdef(&stringf, 'S');
280 writefdef(&keywordf, 'K');
281 }
282 if (block_comment_max_col <= 0)
283 block_comment_max_col = max_col;
284 if (ps.decl_com_ind <= 0) /* if not specified by user, set this */
285 ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
286 if (continuation_indent == 0)
287 continuation_indent = ps.ind_size;
288 fill_buffer(); /* get first batch of stuff into input buffer */
289
290 parse(semicolon);
291 {
292 char *p = buf_ptr;
293 int col = 1;
294
295 while (1) {
296 if (*p == ' ')
297 col++;
298 else
299 if (*p == '\t')
300 col = ((col - 1) & ~7) + 9;
301 else
302 break;
303 p++;
304 }
305 if (col > ps.ind_size)
306 ps.ind_level = ps.i_l_follow = col / ps.ind_size;
307 }
308 if (troff) {
309 const char *p = in_name, *beg = in_name;
310
311 while (*p)
312 if (*p++ == '/')
313 beg = p;
314 fprintf(output, ".Fn \"%s\"\n", beg);
315 }
316 /*
317 * START OF MAIN LOOP
318 */
319
320 while (1) { /* this is the main loop. it will go until we
321 * reach eof */
322 int is_procname;
323
324 type_code = lexi(); /* lexi reads one token. The actual
325 * characters read are stored in
326 * "token". lexi returns a code
327 * indicating the type of token */
328 is_procname = ps.procname[0];
329
330 /*
331 * The following code moves everything following an if (), while (),
332 * else, etc. up to the start of the following stmt to a buffer. This
333 * allows proper handling of both kinds of brace placement.
334 */
335
336 flushed_nl = false;
337 while (ps.search_brace) { /* if we scanned an if(),
338 * while(), etc., we might
339 * need to copy stuff into a
340 * buffer we must loop,
341 * copying stuff into
342 * save_com, until we find the
343 * start of the stmt which
344 * follows the if, or whatever */
345 switch (type_code) {
346 case newline:
347 ++line_no;
348 flushed_nl = true;
349 /* FALLTHROUGH */
350 case form_feed:
351 break; /* form feeds and newlines found here
352 * will be ignored */
353
354 case lbrace: /* this is a brace that starts the
355 * compound stmt */
356 if (sc_end == 0) { /* ignore buffering if a
357 * comment wasn't stored
358 * up */
359 ps.search_brace = false;
360 goto check_type;
361 }
362 if (btype_2) {
363 save_com[0] = '{'; /* we either want to put
364 * the brace right after
365 * the if */
366 goto sw_buffer; /* go to common code to
367 * get out of this loop */
368 }
369 /* FALLTHROUGH */
370 case comment: /* we have a comment, so we must copy
371 * it into the buffer */
372 if (!flushed_nl || sc_end != 0) {
373 if (sc_end == 0) { /* if this is the first
374 * comment, we must set
375 * up the buffer */
376 save_com[0] = save_com[1] = ' ';
377 sc_end = &(save_com[2]);
378 } else {
379 *sc_end++ = '\n'; /* add newline between
380 * comments */
381 *sc_end++ = ' ';
382 --line_no;
383 }
384 *sc_end++ = '/'; /* copy in start of
385 * comment */
386 *sc_end++ = '*';
387
388 for (;;) { /* loop until we get to
389 * the end of the
390 * comment */
391 *sc_end = *buf_ptr++;
392 if (buf_ptr >= buf_end)
393 fill_buffer();
394
395 if (*sc_end++ == '*' && *buf_ptr == '/')
396 break; /* we are at end of
397 * comment */
398
399 if (sc_end >= &(save_com[sc_size])) { /* check for temp buffer
400 * overflow */
401 diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
402 fflush(output);
403 exit(1);
404 }
405 }
406 *sc_end++ = '/'; /* add ending slash */
407 if (++buf_ptr >= buf_end) /* get past / in buffer */
408 fill_buffer();
409 break;
410 }
411 /* FALLTHROUGH */
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 wasn't 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; /* don't 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; /* don't 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 const 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 const 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
790 * aren't 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); /* don't lose the if,
806 * or 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; /* don't 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; /* don't 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 can't be in the
870 * middle of a
871 * declaration, so don't
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 tabs_to_var = (use_tabs ? ps.decl_indent > 0 : 0);
1002 goto copy_id;
1003
1004 case ident: /* got an identifier or constant */
1005 if (ps.in_decl) { /* if we are in a declaration,
1006 * we must indent identifier */
1007 if (ps.want_blank)
1008 *e_code++ = ' ';
1009 ps.want_blank = false;
1010 if (is_procname == 0 || !procnames_start_line) {
1011 if (!ps.block_init) {
1012 if (troff && !ps.dumped_decl_indent) {
1013 sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
1014 ps.dumped_decl_indent = 1;
1015 e_code += strlen(e_code);
1016 CHECK_SIZE_CODE;
1017 } else {
1018 int cur_dec_ind;
1019 int pos, startpos;
1020
1021 /*
1022 * in order to get the tab math right for
1023 * indentations that are not multiples of 8 we
1024 * need to modify both startpos and dec_ind
1025 * (cur_dec_ind) here by eight minus the
1026 * remainder of the current starting column
1027 * divided by eight. This seems to be a
1028 * properly working fix
1029 */
1030 startpos = e_code - s_code;
1031 cur_dec_ind = dec_ind;
1032 pos = startpos;
1033 if ((ps.ind_level * ps.ind_size) % 8 != 0) {
1034 pos += (ps.ind_level * ps.ind_size) % 8;
1035 cur_dec_ind += (ps.ind_level * ps.ind_size) % 8;
1036 }
1037
1038 if (tabs_to_var) {
1039 while ((pos & ~7) + 8 <= cur_dec_ind) {
1040 CHECK_SIZE_CODE;
1041 *e_code++ = '\t';
1042 pos = (pos & ~7) + 8;
1043 }
1044 }
1045 while (pos < cur_dec_ind) {
1046 CHECK_SIZE_CODE;
1047 *e_code++ = ' ';
1048 pos++;
1049 }
1050 if (ps.want_blank && e_code - s_code == startpos)
1051 *e_code++ = ' ';
1052 ps.want_blank = false;
1053 }
1054 }
1055 } else {
1056 if (dec_ind && s_code != e_code)
1057 dump_line();
1058 dec_ind = 0;
1059 ps.want_blank = false;
1060 }
1061 } else
1062 if (sp_sw && ps.p_l_follow == 0) {
1063 sp_sw = false;
1064 force_nl = true;
1065 ps.last_u_d = true;
1066 ps.in_stmt = false;
1067 parse(hd_type);
1068 }
1069 copy_id:
1070 if (ps.want_blank)
1071 *e_code++ = ' ';
1072 if (troff && ps.its_a_keyword) {
1073 e_code = chfont(&bodyf, &keywordf, e_code);
1074 for (t_ptr = token; *t_ptr; ++t_ptr) {
1075 CHECK_SIZE_CODE;
1076 *e_code++ = keywordf.allcaps
1077 ? toupper((unsigned char)*t_ptr)
1078 : *t_ptr;
1079 }
1080 e_code = chfont(&keywordf, &bodyf, e_code);
1081 } else
1082 for (t_ptr = token; *t_ptr; ++t_ptr) {
1083 CHECK_SIZE_CODE;
1084 *e_code++ = *t_ptr;
1085 }
1086 ps.want_blank = true;
1087 break;
1088
1089 case period: /* treat a period kind of like a binary
1090 * operation */
1091 *e_code++ = '.'; /* move the period into line */
1092 ps.want_blank = false; /* don't put a blank after a
1093 * period */
1094 break;
1095
1096 case comma:
1097 ps.want_blank = (s_code != e_code); /* only put blank after
1098 * comma if comma does
1099 * not start the line */
1100 if (ps.in_decl && is_procname == 0 && !ps.block_init)
1101 while ((e_code - s_code) < (dec_ind - 1)) {
1102 CHECK_SIZE_CODE;
1103 *e_code++ = ' ';
1104 }
1105
1106 *e_code++ = ',';
1107 if (ps.p_l_follow == 0) {
1108 if (ps.block_init_level <= 0)
1109 ps.block_init = 0;
1110 if (break_comma && (!ps.leave_comma || compute_code_target() + (e_code - s_code) > max_col - 8))
1111 force_nl = true;
1112 }
1113 break;
1114
1115 case preesc: /* got the character '#' */
1116 if ((s_com != e_com) ||
1117 (s_lab != e_lab) ||
1118 (s_code != e_code))
1119 dump_line();
1120 *e_lab++ = '#'; /* move whole line to 'label' buffer */
1121 {
1122 int in_comment = 0;
1123 int com_start = 0;
1124 char quote = 0;
1125 int com_end = 0;
1126
1127 while (*buf_ptr == ' ' || *buf_ptr == '\t') {
1128 buf_ptr++;
1129 if (buf_ptr >= buf_end)
1130 fill_buffer();
1131 }
1132 while (*buf_ptr != '\n' || in_comment) {
1133 CHECK_SIZE_LAB;
1134 *e_lab = *buf_ptr++;
1135 if (buf_ptr >= buf_end)
1136 fill_buffer();
1137 switch (*e_lab++) {
1138 case BACKSLASH:
1139 if (troff)
1140 *e_lab++ = BACKSLASH;
1141 if (!in_comment) {
1142 *e_lab++ = *buf_ptr++;
1143 if (buf_ptr >= buf_end)
1144 fill_buffer();
1145 }
1146 break;
1147 case '/':
1148 if (*buf_ptr == '*' && !in_comment && !quote) {
1149 in_comment = 1;
1150 *e_lab++ = *buf_ptr++;
1151 com_start = e_lab - s_lab - 2;
1152 }
1153 break;
1154 case '"':
1155 if (quote == '"')
1156 quote = 0;
1157 break;
1158 case '\'':
1159 if (quote == '\'')
1160 quote = 0;
1161 break;
1162 case '*':
1163 if (*buf_ptr == '/' && in_comment) {
1164 in_comment = 0;
1165 *e_lab++ = *buf_ptr++;
1166 com_end = e_lab - s_lab;
1167 }
1168 break;
1169 }
1170 }
1171
1172 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1173 e_lab--;
1174 if (e_lab - s_lab == com_end && bp_save == 0) { /* comment on
1175 * preprocessor line */
1176 if (sc_end == 0) /* if this is the first
1177 * comment, we must set
1178 * up the buffer */
1179 sc_end = &(save_com[0]);
1180 else {
1181 *sc_end++ = '\n'; /* add newline between
1182 * comments */
1183 *sc_end++ = ' ';
1184 --line_no;
1185 }
1186 memmove(sc_end, s_lab + com_start, com_end - com_start);
1187 sc_end += com_end - com_start;
1188 if (sc_end >= &save_com[sc_size])
1189 abort();
1190 e_lab = s_lab + com_start;
1191 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1192 e_lab--;
1193 bp_save = buf_ptr; /* save current input
1194 * buffer */
1195 be_save = buf_end;
1196 buf_ptr = save_com; /* fix so that
1197 * subsequent calls to
1198 * lexi will take tokens
1199 * out of save_com */
1200 *sc_end++ = ' '; /* add trailing blank,
1201 * just in case */
1202 buf_end = sc_end;
1203 sc_end = 0;
1204 }
1205 *e_lab = '\0'; /* null terminate line */
1206 ps.pcase = false;
1207 }
1208
1209 if (strncmp(s_lab, "#if", 3) == 0) {
1210 if (blanklines_around_conditional_compilation) {
1211 int c;
1212 prefix_blankline_requested++;
1213 while ((c = getc(input)) == '\n');
1214 ungetc(c, input);
1215 }
1216 if (ifdef_level < (int)(sizeof state_stack / sizeof state_stack[0])) {
1217 match_state[ifdef_level].tos = -1;
1218 state_stack[ifdef_level++] = ps;
1219 } else
1220 diag(1, "#if stack overflow");
1221 } else
1222 if (strncmp(s_lab, "#else", 5) == 0) {
1223 if (ifdef_level <= 0)
1224 diag(1, "Unmatched #else");
1225 else {
1226 match_state[ifdef_level - 1] = ps;
1227 ps = state_stack[ifdef_level - 1];
1228 }
1229 } else
1230 if (strncmp(s_lab, "#endif", 6) == 0) {
1231 if (ifdef_level <= 0)
1232 diag(1, "Unmatched #endif");
1233 else {
1234 ifdef_level--;
1235
1236 #ifdef undef
1237 /*
1238 * This match needs to be more intelligent before the
1239 * message is useful
1240 */
1241 if (match_state[ifdef_level].tos >= 0
1242 && memcmp(&ps, &match_state[ifdef_level], sizeof ps))
1243 diag(0, "Syntactically inconsistant #ifdef alternatives.");
1244 #endif
1245 }
1246 if (blanklines_around_conditional_compilation) {
1247 postfix_blankline_requested++;
1248 n_real_blanklines = 0;
1249 }
1250 }
1251 break; /* subsequent processing of the newline
1252 * character will cause the line to be printed */
1253
1254 case comment: /* we have gotten a start comment */
1255 /* this is a biggie */
1256 if (flushed_nl) { /* we should force a broken
1257 * line here */
1258 flushed_nl = false;
1259 dump_line();
1260 ps.want_blank = false; /* don't insert blank at
1261 * line start */
1262 force_nl = false;
1263 }
1264 pr_comment();
1265 break;
1266 } /* end of big switch stmt */
1267
1268 *e_code = '\0'; /* make sure code section is null terminated */
1269 if (type_code != comment && type_code != newline && type_code != preesc)
1270 ps.last_token = type_code;
1271 } /* end of main while (1) loop */
1272 }
1273 /*
1274 * copy input file to backup file if in_name is /blah/blah/blah/file, then
1275 * backup file will be ".Bfile" then make the backup file the input and
1276 * original input file the output
1277 */
1278 void
1279 bakcopy(void)
1280 {
1281 int n, bakchn;
1282 char buff[8 * 1024];
1283 const char *p;
1284
1285 /* construct file name .Bfile */
1286 for (p = in_name; *p; p++); /* skip to end of string */
1287 while (p > in_name && *p != '/') /* find last '/' */
1288 p--;
1289 if (*p == '/')
1290 p++;
1291 sprintf(bakfile, "%s.BAK", p);
1292
1293 /* copy in_name to backup file */
1294 bakchn = creat(bakfile, 0600);
1295 if (bakchn < 0)
1296 err(1, "%s", bakfile);
1297 while ((n = read(fileno(input), buff, sizeof buff)) > 0)
1298 if (write(bakchn, buff, n) != n)
1299 err(1, "%s", bakfile);
1300 if (n < 0)
1301 err(1, "%s", in_name);
1302 close(bakchn);
1303 fclose(input);
1304
1305 /* re-open backup file as the input file */
1306 input = fopen(bakfile, "r");
1307 if (input == 0)
1308 err(1, "%s", bakfile);
1309 /* now the original input file will be the output */
1310 output = fopen(in_name, "w");
1311 if (output == 0) {
1312 unlink(bakfile);
1313 err(1, "%s", in_name);
1314 }
1315 }
1316