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