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