Annotation of src/usr.bin/indent/indent.c, Revision 1.3
1.3 ! deraadt 1: /* $OpenBSD$ */
! 2:
1.1 deraadt 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";*/
1.3 ! deraadt 48: static char rcsid[] = "$OpenBSD: indent.c,v 1.2 1996/05/21 21:51:18 deraadt Exp $";
1.1 deraadt 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>
1.2 deraadt 60: #include <errno.h>
1.1 deraadt 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: }