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