unstack, sort: cleanup and improvement
[minix.git] / usr.bin / indent / indent.c
blob8001931a6889af807b7e0ab3ce106b383200b825
1 /* $NetBSD: indent.c,v 1.18 2009/04/12 11:09:49 lukem Exp $ */
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
33 * Copyright (c) 1976 Board of Trustees of the University of Illinois.
34 * Copyright (c) 1985 Sun Microsystems, Inc.
35 * All rights reserved.
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.
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.
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 */
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.18 2009/04/12 11:09:49 lukem Exp $");
79 #endif
80 #endif /* not lint */
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"
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] = "";
103 int main(int, char **);
106 main(int argc, char **argv)
109 extern int found_err; /* flag set in diag() on error */
110 int dec_ind; /* current indentation for declarations */
111 int di_stack[20]; /* a stack of structure indentation levels */
112 int flushed_nl; /* used when buffering up comments to remember
113 * that a newline was passed over */
114 int force_nl; /* when true, code must be broken */
115 int hd_type; /* used to store type of stmt for if (...),
116 * for (...), etc */
117 int i; /* local loop counter */
118 int scase; /* set to true when we see a case, so we will
119 * know what to do with the following colon */
120 int sp_sw; /* when true, we are in the expressin of
121 * if(...), while(...), etc. */
122 int squest; /* when this is positive, we have seen a ?
123 * without the matching : in a <c>?<s>:<s>
124 * construct */
125 const char *t_ptr; /* used for copying tokens */
126 int type_code; /* the type of token, returned by lexi */
128 int last_else = 0; /* true iff last keyword was an else */
131 /*-----------------------------------------------*\
132 | INITIALIZATION |
133 \*-----------------------------------------------*/
135 if (!setlocale(LC_ALL, ""))
136 fprintf(stderr, "indent: can't set locale.\n");
138 hd_type = 0;
139 ps.p_stack[0] = stmt; /* this is the parser's stack */
140 ps.last_nl = true; /* this is true if the last thing scanned was
141 * a newline */
142 ps.last_token = semicolon;
143 combuf = (char *) malloc(bufsize);
144 labbuf = (char *) malloc(bufsize);
145 codebuf = (char *) malloc(bufsize);
146 tokenbuf = (char *) malloc(bufsize);
147 l_com = combuf + bufsize - 5;
148 l_lab = labbuf + bufsize - 5;
149 l_code = codebuf + bufsize - 5;
150 l_token = tokenbuf + bufsize - 5;
151 combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label,
152 * and comment buffers */
153 combuf[1] = codebuf[1] = labbuf[1] = '\0';
154 ps.else_if = 1; /* Default else-if special processing to on */
155 s_lab = e_lab = labbuf + 1;
156 s_code = e_code = codebuf + 1;
157 s_com = e_com = combuf + 1;
158 s_token = e_token = tokenbuf + 1;
160 in_buffer = (char *) malloc(10);
161 in_buffer_limit = in_buffer + 8;
162 buf_ptr = buf_end = in_buffer;
163 line_no = 1;
164 had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
165 sp_sw = force_nl = false;
166 ps.in_or_st = false;
167 ps.bl_line = true;
168 dec_ind = 0;
169 di_stack[ps.dec_nest = 0] = 0;
170 ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
173 scase = ps.pcase = false;
174 squest = 0;
175 sc_end = 0;
176 bp_save = 0;
177 be_save = 0;
179 output = 0;
183 /*--------------------------------------------------*\
184 | COMMAND LINE SCAN |
185 \*--------------------------------------------------*/
187 #ifdef undef
188 max_col = 78; /* -l78 */
189 lineup_to_parens = 1; /* -lp */
190 ps.ljust_decl = 0; /* -ndj */
191 ps.com_ind = 33; /* -c33 */
192 star_comment_cont = 1; /* -sc */
193 ps.ind_size = 8; /* -i8 */
194 verbose = 0;
195 ps.decl_indent = 16; /* -di16 */
196 ps.indent_parameters = 1; /* -ip */
197 ps.decl_com_ind = 0; /* if this is not set to some positive value
198 * by an arg, we will set this equal to
199 * ps.com_ind */
200 btype_2 = 1; /* -br */
201 cuddle_else = 1; /* -ce */
202 ps.unindent_displace = 0; /* -d0 */
203 ps.case_indent = 0; /* -cli0 */
204 format_col1_comments = 1; /* -fc1 */
205 procnames_start_line = 1; /* -psl */
206 proc_calls_space = 0; /* -npcs */
207 comment_delimiter_on_blankline = 1; /* -cdb */
208 ps.leave_comma = 1; /* -nbc */
209 #endif
211 for (i = 1; i < argc; ++i)
212 if (strcmp(argv[i], "-npro") == 0)
213 break;
214 set_defaults();
215 if (i >= argc)
216 set_profile();
218 for (i = 1; i < argc; ++i) {
221 * look thru args (if any) for changes to defaults
223 if (argv[i][0] != '-') { /* no flag on parameter */
224 if (input == 0) { /* we must have the input file */
225 in_name = argv[i]; /* remember name of
226 * input file */
227 input = fopen(in_name, "r");
228 if (input == 0) /* check for open error */
229 err(1, "%s", in_name);
230 continue;
231 } else
232 if (output == 0) { /* we have the output
233 * file */
234 out_name = argv[i]; /* remember name of
235 * output file */
236 if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite
237 * the file */
238 fprintf(stderr, "indent: input and output files must be different\n");
239 exit(1);
241 output = fopen(out_name, "w");
242 if (output == 0) /* check for create
243 * error */
244 err(1, "%s", out_name);
245 continue;
247 fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
248 exit(1);
249 } else
250 set_option(argv[i]);
251 } /* end of for */
252 if (input == 0) {
253 input = stdin;
255 if (output == 0) {
256 if (troff || input == stdin)
257 output = stdout;
258 else {
259 out_name = in_name;
260 bakcopy();
263 if (ps.com_ind <= 1)
264 ps.com_ind = 2; /* dont put normal comments before column 2 */
265 if (troff) {
266 if (bodyf.font[0] == 0)
267 parsefont(&bodyf, "R");
268 if (scomf.font[0] == 0)
269 parsefont(&scomf, "I");
270 if (blkcomf.font[0] == 0)
271 blkcomf = scomf, blkcomf.size += 2;
272 if (boxcomf.font[0] == 0)
273 boxcomf = blkcomf;
274 if (stringf.font[0] == 0)
275 parsefont(&stringf, "L");
276 if (keywordf.font[0] == 0)
277 parsefont(&keywordf, "B");
278 writefdef(&bodyf, 'B');
279 writefdef(&scomf, 'C');
280 writefdef(&blkcomf, 'L');
281 writefdef(&boxcomf, 'X');
282 writefdef(&stringf, 'S');
283 writefdef(&keywordf, 'K');
285 if (block_comment_max_col <= 0)
286 block_comment_max_col = max_col;
287 if (ps.decl_com_ind <= 0) /* if not specified by user, set this */
288 ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
289 if (continuation_indent == 0)
290 continuation_indent = ps.ind_size;
291 fill_buffer(); /* get first batch of stuff into input buffer */
293 parse(semicolon);
295 char *p = buf_ptr;
296 int col = 1;
298 while (1) {
299 if (*p == ' ')
300 col++;
301 else
302 if (*p == '\t')
303 col = ((col - 1) & ~7) + 9;
304 else
305 break;
306 p++;
308 if (col > ps.ind_size)
309 ps.ind_level = ps.i_l_follow = col / ps.ind_size;
311 if (troff) {
312 const char *p = in_name, *beg = in_name;
314 while (*p)
315 if (*p++ == '/')
316 beg = p;
317 fprintf(output, ".Fn \"%s\"\n", beg);
320 * START OF MAIN LOOP
323 while (1) { /* this is the main loop. it will go until we
324 * reach eof */
325 int is_procname;
327 type_code = lexi(); /* lexi reads one token. The actual
328 * characters read are stored in
329 * "token". lexi returns a code
330 * indicating the type of token */
331 is_procname = ps.procname[0];
334 * The following code moves everything following an if (), while (),
335 * else, etc. up to the start of the following stmt to a buffer. This
336 * allows proper handling of both kinds of brace placement.
339 flushed_nl = false;
340 while (ps.search_brace) { /* if we scanned an if(),
341 * while(), etc., we might
342 * need to copy stuff into a
343 * buffer we must loop,
344 * copying stuff into
345 * save_com, until we find the
346 * start of the stmt which
347 * follows the if, or whatever */
348 switch (type_code) {
349 case newline:
350 ++line_no;
351 flushed_nl = true;
352 case form_feed:
353 break; /* form feeds and newlines found here
354 * will be ignored */
356 case lbrace: /* this is a brace that starts the
357 * compound stmt */
358 if (sc_end == 0) { /* ignore buffering if a
359 * comment wasnt stored
360 * up */
361 ps.search_brace = false;
362 goto check_type;
364 if (btype_2) {
365 save_com[0] = '{'; /* we either want to put
366 * the brace right after
367 * the if */
368 goto sw_buffer; /* go to common code to
369 * get out of this loop */
371 case comment: /* we have a comment, so we must copy
372 * it into the buffer */
373 if (!flushed_nl || sc_end != 0) {
374 if (sc_end == 0) { /* if this is the first
375 * comment, we must set
376 * up the buffer */
377 save_com[0] = save_com[1] = ' ';
378 sc_end = &(save_com[2]);
379 } else {
380 *sc_end++ = '\n'; /* add newline between
381 * comments */
382 *sc_end++ = ' ';
383 --line_no;
385 *sc_end++ = '/'; /* copy in start of
386 * comment */
387 *sc_end++ = '*';
389 for (;;) { /* loop until we get to
390 * the end of the
391 * comment */
392 *sc_end = *buf_ptr++;
393 if (buf_ptr >= buf_end)
394 fill_buffer();
396 if (*sc_end++ == '*' && *buf_ptr == '/')
397 break; /* we are at end of
398 * comment */
400 if (sc_end >= &(save_com[sc_size])) { /* check for temp buffer
401 * overflow */
402 diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
403 fflush(output);
404 exit(1);
407 *sc_end++ = '/'; /* add ending slash */
408 if (++buf_ptr >= buf_end) /* get past / in buffer */
409 fill_buffer();
410 break;
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;
423 if (sc_end == 0) { /* ignore buffering if
424 * comment wasnt saved
425 * up */
426 ps.search_brace = false;
427 goto check_type;
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;
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;
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.");
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);
491 fflush(output);
492 exit(found_err);
494 if (
495 (type_code != comment) &&
496 (type_code != newline) &&
497 (type_code != preesc) &&
498 (type_code != form_feed)) {
499 if (force_nl &&
500 (type_code != semicolon) &&
501 (type_code != lbrace || !btype_2)) {
502 /* we should force a broken line here */
503 if (verbose && !flushed_nl)
504 diag(0, "Line broken");
505 flushed_nl = false;
506 dump_line();
507 ps.want_blank = false; /* dont insert blank at
508 * line start */
509 force_nl = false;
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;
522 *e_code++ = ' ';
523 *e_code = '\0'; /* null terminate code sect */
524 ps.want_blank = false;
525 e_com = s_com;
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 */
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 */
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;
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;
556 ++line_no; /* keep track of input line number */
557 break;
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++ = ' ';
576 *e_code++ = token[0];
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) {
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) {..."
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 */
597 if (ps.sizeof_keyword)
598 ps.sizeof_mask |= 1 << ps.p_l_follow;
599 break;
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;
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);
612 if (e_code == s_code) /* if the paren starts the
613 * line */
614 ps.paren_level = ps.p_l_follow; /* then indent it */
616 *e_code++ = token[0];
617 ps.want_blank = true;
619 if (sp_sw && (ps.p_l_follow == 0)) { /* check for end of if
620 * (...), or some such */
621 sp_sw = false;
622 force_nl = true; /* must force newline
623 * after if */
624 ps.last_u_d = true; /* inform lexi that a
625 * following operator is
626 * unary */
627 ps.in_stmt = false; /* dont use stmt
628 * continuation
629 * indentation */
631 parse(hd_type); /* let parser worry about if,
632 * or whatever */
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;
642 case unary_op: /* this could be any unary operation */
643 if (ps.want_blank)
644 *e_code++ = ' ';
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;
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 */
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;
670 ps.want_blank = false;
671 break;
673 case binary_op:/* any binary operation */
674 if (ps.want_blank)
675 *e_code++ = ' ';
677 const char *res = token;
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;
701 for (t_ptr = res; *t_ptr; ++t_ptr) {
702 CHECK_SIZE_CODE;
703 *e_code++ = *t_ptr; /* move the operator */
706 ps.want_blank = true;
707 break;
709 case postop: /* got a trailing ++ or -- */
710 *e_code++ = token[0];
711 *e_code++ = token[1];
712 ps.want_blank = true;
713 break;
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;
725 case casestmt: /* got word 'case' or 'default' */
726 scase = true; /* so we can process the later colon
727 * properly */
728 goto copy_id;
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;
740 if (ps.in_or_st) {
741 *e_code++ = ':';
742 ps.want_blank = false;
743 break;
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';
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;
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--;
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++ = ' ';
787 ps.in_decl = (ps.dec_nest > 0); /* if we were in a first
788 * level structure
789 * declaration, we arent
790 * any more */
792 if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
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
799 diag(1, "Unbalanced parens");
800 ps.p_l_follow = 0;
801 if (sp_sw) { /* this is a check for a if,
802 * while, etc. with unbalanced
803 * parens */
804 sp_sw = false;
805 parse(hd_type); /* dont lose the if, or
806 * whatever */
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 */
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 */
820 break;
822 case lbrace: /* got a '{' */
823 ps.in_stmt = false; /* dont indent the {} */
824 if (!ps.block_init)
825 force_nl = true; /* force other stuff on
826 * same line as '{' onto
827 * new line */
828 else
829 if (ps.block_init_level <= 0)
830 ps.block_init_level = 1;
831 else
832 ps.block_init_level++;
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;
845 if (ps.in_parameter_declaration)
846 prefix_blankline_requested = 0;
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;
859 if (s_code == e_code)
860 ps.ind_stmt = false; /* dont put extra
861 * indentation on line
862 * with '{' */
863 if (ps.in_decl && ps.in_or_st) { /* this is either a
864 * structure declaration
865 * or an init */
866 di_stack[ps.dec_nest++] = dec_ind;
867 /* ? dec_ind = 0; */
868 } else {
869 ps.decl_on_line = false; /* we cant be in the
870 * middle of a
871 * declaration, so dont
872 * do special
873 * indentation of
874 * comments */
875 if (blanklines_after_declarations_at_proctop
876 && ps.in_parameter_declaration)
877 postfix_blankline_requested = 1;
878 ps.in_parameter_declaration = 0;
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;
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;
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();
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;
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;
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 */
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));
940 * remember the type of header for later use by parser
942 goto copy_id; /* copy the token into line */
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;
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;
966 force_nl = true; /* also, following stuff
967 * must go onto new line */
968 last_else = 0;
969 parse(dolit);
971 goto copy_id; /* move the token into line */
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;
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;
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 */
997 * dec_ind = e_code - s_code + (ps.decl_indent>i ? ps.decl_indent
998 * : i);
1000 dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
1001 goto copy_id;
1003 case ident: /* got an identifier or constant */
1004 if (ps.in_decl) { /* if we are in a declaration,
1005 * we must indent identifier */
1006 if (ps.want_blank)
1007 *e_code++ = ' ';
1008 ps.want_blank = false;
1009 if (is_procname == 0 || !procnames_start_line) {
1010 if (!ps.block_init) {
1011 if (troff && !ps.dumped_decl_indent) {
1012 sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
1013 ps.dumped_decl_indent = 1;
1014 e_code += strlen(e_code);
1015 } else
1016 while ((e_code - s_code) < dec_ind) {
1017 CHECK_SIZE_CODE;
1018 *e_code++ = ' ';
1021 } else {
1022 if (dec_ind && s_code != e_code)
1023 dump_line();
1024 dec_ind = 0;
1025 ps.want_blank = false;
1027 } else
1028 if (sp_sw && ps.p_l_follow == 0) {
1029 sp_sw = false;
1030 force_nl = true;
1031 ps.last_u_d = true;
1032 ps.in_stmt = false;
1033 parse(hd_type);
1035 copy_id:
1036 if (ps.want_blank)
1037 *e_code++ = ' ';
1038 if (troff && ps.its_a_keyword) {
1039 e_code = chfont(&bodyf, &keywordf, e_code);
1040 for (t_ptr = token; *t_ptr; ++t_ptr) {
1041 CHECK_SIZE_CODE;
1042 *e_code++ = keywordf.allcaps
1043 ? toupper((unsigned char)*t_ptr)
1044 : *t_ptr;
1046 e_code = chfont(&keywordf, &bodyf, e_code);
1047 } else
1048 for (t_ptr = token; *t_ptr; ++t_ptr) {
1049 CHECK_SIZE_CODE;
1050 *e_code++ = *t_ptr;
1052 ps.want_blank = true;
1053 break;
1055 case period: /* treat a period kind of like a binary
1056 * operation */
1057 *e_code++ = '.'; /* move the period into line */
1058 ps.want_blank = false; /* dont put a blank after a
1059 * period */
1060 break;
1062 case comma:
1063 ps.want_blank = (s_code != e_code); /* only put blank after
1064 * comma if comma does
1065 * not start the line */
1066 if (ps.in_decl && is_procname == 0 && !ps.block_init)
1067 while ((e_code - s_code) < (dec_ind - 1)) {
1068 CHECK_SIZE_CODE;
1069 *e_code++ = ' ';
1072 *e_code++ = ',';
1073 if (ps.p_l_follow == 0) {
1074 if (ps.block_init_level <= 0)
1075 ps.block_init = 0;
1076 if (break_comma && (!ps.leave_comma || compute_code_target() + (e_code - s_code) > max_col - 8))
1077 force_nl = true;
1079 break;
1081 case preesc: /* got the character '#' */
1082 if ((s_com != e_com) ||
1083 (s_lab != e_lab) ||
1084 (s_code != e_code))
1085 dump_line();
1086 *e_lab++ = '#'; /* move whole line to 'label' buffer */
1088 int in_comment = 0;
1089 int com_start = 0;
1090 char quote = 0;
1091 int com_end = 0;
1093 while (*buf_ptr == ' ' || *buf_ptr == '\t') {
1094 buf_ptr++;
1095 if (buf_ptr >= buf_end)
1096 fill_buffer();
1098 while (*buf_ptr != '\n' || in_comment) {
1099 CHECK_SIZE_LAB;
1100 *e_lab = *buf_ptr++;
1101 if (buf_ptr >= buf_end)
1102 fill_buffer();
1103 switch (*e_lab++) {
1104 case BACKSLASH:
1105 if (troff)
1106 *e_lab++ = BACKSLASH;
1107 if (!in_comment) {
1108 *e_lab++ = *buf_ptr++;
1109 if (buf_ptr >= buf_end)
1110 fill_buffer();
1112 break;
1113 case '/':
1114 if (*buf_ptr == '*' && !in_comment && !quote) {
1115 in_comment = 1;
1116 *e_lab++ = *buf_ptr++;
1117 com_start = e_lab - s_lab - 2;
1119 break;
1120 case '"':
1121 if (quote == '"')
1122 quote = 0;
1123 break;
1124 case '\'':
1125 if (quote == '\'')
1126 quote = 0;
1127 break;
1128 case '*':
1129 if (*buf_ptr == '/' && in_comment) {
1130 in_comment = 0;
1131 *e_lab++ = *buf_ptr++;
1132 com_end = e_lab - s_lab;
1134 break;
1138 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1139 e_lab--;
1140 if (e_lab - s_lab == com_end && bp_save == 0) { /* comment on
1141 * preprocessor line */
1142 if (sc_end == 0) /* if this is the first
1143 * comment, we must set
1144 * up the buffer */
1145 sc_end = &(save_com[0]);
1146 else {
1147 *sc_end++ = '\n'; /* add newline between
1148 * comments */
1149 *sc_end++ = ' ';
1150 --line_no;
1152 memmove(sc_end, s_lab + com_start, com_end - com_start);
1153 sc_end += com_end - com_start;
1154 if (sc_end >= &save_com[sc_size])
1155 abort();
1156 e_lab = s_lab + com_start;
1157 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1158 e_lab--;
1159 bp_save = buf_ptr; /* save current input
1160 * buffer */
1161 be_save = buf_end;
1162 buf_ptr = save_com; /* fix so that
1163 * subsequent calls to
1164 * lexi will take tokens
1165 * out of save_com */
1166 *sc_end++ = ' '; /* add trailing blank,
1167 * just in case */
1168 buf_end = sc_end;
1169 sc_end = 0;
1171 *e_lab = '\0'; /* null terminate line */
1172 ps.pcase = false;
1175 if (strncmp(s_lab, "#if", 3) == 0) {
1176 if (blanklines_around_conditional_compilation) {
1177 int c;
1178 prefix_blankline_requested++;
1179 while ((c = getc(input)) == '\n');
1180 ungetc(c, input);
1182 if (ifdef_level < (int)(sizeof state_stack / sizeof state_stack[0])) {
1183 match_state[ifdef_level].tos = -1;
1184 state_stack[ifdef_level++] = ps;
1185 } else
1186 diag(1, "#if stack overflow");
1187 } else
1188 if (strncmp(s_lab, "#else", 5) == 0) {
1189 if (ifdef_level <= 0)
1190 diag(1, "Unmatched #else");
1191 else {
1192 match_state[ifdef_level - 1] = ps;
1193 ps = state_stack[ifdef_level - 1];
1195 } else
1196 if (strncmp(s_lab, "#endif", 6) == 0) {
1197 if (ifdef_level <= 0)
1198 diag(1, "Unmatched #endif");
1199 else {
1200 ifdef_level--;
1202 #ifdef undef
1204 * This match needs to be more intelligent before the
1205 * message is useful
1207 if (match_state[ifdef_level].tos >= 0
1208 && memcmp(&ps, &match_state[ifdef_level], sizeof ps))
1209 diag(0, "Syntactically inconsistant #ifdef alternatives.");
1210 #endif
1212 if (blanklines_around_conditional_compilation) {
1213 postfix_blankline_requested++;
1214 n_real_blanklines = 0;
1217 break; /* subsequent processing of the newline
1218 * character will cause the line to be printed */
1220 case comment: /* we have gotten a start comment */
1221 /* this is a biggie */
1222 if (flushed_nl) { /* we should force a broken
1223 * line here */
1224 flushed_nl = false;
1225 dump_line();
1226 ps.want_blank = false; /* dont insert blank at
1227 * line start */
1228 force_nl = false;
1230 pr_comment();
1231 break;
1232 } /* end of big switch stmt */
1234 *e_code = '\0'; /* make sure code section is null terminated */
1235 if (type_code != comment && type_code != newline && type_code != preesc)
1236 ps.last_token = type_code;
1237 } /* end of main while (1) loop */
1240 * copy input file to backup file if in_name is /blah/blah/blah/file, then
1241 * backup file will be ".Bfile" then make the backup file the input and
1242 * original input file the output
1244 void
1245 bakcopy(void)
1247 int n, bakchn;
1248 char buff[8 * 1024];
1249 const char *p;
1251 /* construct file name .Bfile */
1252 for (p = in_name; *p; p++); /* skip to end of string */
1253 while (p > in_name && *p != '/') /* find last '/' */
1254 p--;
1255 if (*p == '/')
1256 p++;
1257 sprintf(bakfile, "%s.BAK", p);
1259 /* copy in_name to backup file */
1260 bakchn = creat(bakfile, 0600);
1261 if (bakchn < 0)
1262 err(1, "%s", bakfile);
1263 while ((n = read(fileno(input), buff, sizeof buff)) > 0)
1264 if (write(bakchn, buff, n) != n)
1265 err(1, "%s", bakfile);
1266 if (n < 0)
1267 err(1, "%s", in_name);
1268 close(bakchn);
1269 fclose(input);
1271 /* re-open backup file as the input file */
1272 input = fopen(bakfile, "r");
1273 if (input == 0)
1274 err(1, "%s", bakfile);
1275 /* now the original input file will be the output */
1276 output = fopen(in_name, "w");
1277 if (output == 0) {
1278 unlink(bakfile);
1279 err(1, "%s", in_name);