indent.c revision 1.350 1 /* $NetBSD: indent.c,v 1.350 2023/06/10 06:52:35 rillig Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-4-Clause
5 *
6 * Copyright (c) 1985 Sun Microsystems, Inc.
7 * Copyright (c) 1976 Board of Trustees of the University of Illinois.
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40 #include <sys/cdefs.h>
41 __RCSID("$NetBSD: indent.c,v 1.350 2023/06/10 06:52:35 rillig Exp $");
42
43 #include <sys/param.h>
44 #include <err.h>
45 #include <fcntl.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 #include "indent.h"
53
54 struct options opt = {
55 .brace_same_line = true,
56 .comment_delimiter_on_blankline = true,
57 .cuddle_else = true,
58 .comment_column = 33,
59 .decl_indent = 16,
60 .else_if_in_same_line = true,
61 .function_brace_split = true,
62 .format_col1_comments = true,
63 .format_block_comments = true,
64 .indent_parameters = true,
65 .indent_size = 8,
66 .local_decl_indent = -1,
67 .lineup_to_parens = true,
68 .procnames_start_line = true,
69 .star_comment_cont = true,
70 .tabsize = 8,
71 .max_line_length = 78,
72 .use_tabs = true,
73 };
74
75 struct parser_state ps;
76
77 struct buffer token;
78
79 struct buffer lab;
80 struct buffer code;
81 struct buffer com;
82
83 bool found_err;
84 bool had_eof;
85 int line_no = 1;
86
87 static int ifdef_level;
88 static struct parser_state state_stack[5];
89
90 FILE *input;
91 FILE *output;
92
93 static const char *in_name = "Standard Input";
94 static const char *backup_suffix = ".BAK";
95 static char bakfile[MAXPATHLEN] = "";
96
97
98 void *
99 nonnull(void *p)
100 {
101 if (p == NULL)
102 err(EXIT_FAILURE, NULL);
103 return p;
104 }
105
106 static void
107 buf_expand(struct buffer *buf, size_t add_size)
108 {
109 buf->cap = buf->cap + add_size + 400;
110 buf->s = nonnull(realloc(buf->s, buf->cap));
111 }
112
113 void
114 buf_add_char(struct buffer *buf, char ch)
115 {
116 if (buf->len == buf->cap)
117 buf_expand(buf, 1);
118 buf->s[buf->len++] = ch;
119 }
120
121 void
122 buf_add_chars(struct buffer *buf, const char *s, size_t len)
123 {
124 if (len == 0)
125 return;
126 if (len > buf->cap - buf->len)
127 buf_expand(buf, len);
128 memcpy(buf->s + buf->len, s, len);
129 buf->len += len;
130 }
131
132 static void
133 buf_add_buf(struct buffer *buf, const struct buffer *add)
134 {
135 buf_add_chars(buf, add->s, add->len);
136 }
137
138 void
139 diag(int level, const char *msg, ...)
140 {
141 va_list ap;
142
143 if (level != 0)
144 found_err = true;
145
146 va_start(ap, msg);
147 fprintf(stderr, "%s: %s:%d: ",
148 level == 0 ? "warning" : "error", in_name, line_no);
149 vfprintf(stderr, msg, ap);
150 fprintf(stderr, "\n");
151 va_end(ap);
152 }
153
154 /*
155 * Compute the indentation from starting at 'ind' and adding the text starting
156 * at 's'.
157 */
158 int
159 ind_add(int ind, const char *s, size_t len)
160 {
161 for (const char *p = s; len > 0; p++, len--) {
162 if (*p == '\n')
163 ind = 0;
164 else if (*p == '\t')
165 ind = next_tab(ind);
166 else if (*p == '\b')
167 --ind;
168 else
169 ++ind;
170 }
171 return ind;
172 }
173
174 static void
175 init_globals(void)
176 {
177 ps.psyms.sym[0] = psym_stmt_list;
178 ps.prev_lsym = lsym_semicolon;
179 ps.next_col_1 = true;
180 ps.lbrace_kind = psym_lbrace_block;
181
182 const char *suffix = getenv("SIMPLE_BACKUP_SUFFIX");
183 if (suffix != NULL)
184 backup_suffix = suffix;
185 }
186
187 static void
188 load_profiles(int argc, char **argv)
189 {
190 const char *profile_name = NULL;
191
192 for (int i = 1; i < argc; ++i) {
193 const char *arg = argv[i];
194
195 if (strcmp(arg, "-npro") == 0)
196 return;
197 if (arg[0] == '-' && arg[1] == 'P' && arg[2] != '\0')
198 profile_name = arg + 2;
199 }
200
201 load_profile_files(profile_name);
202 }
203
204 /*
205 * Copy the input file to the backup file, then make the backup file the input
206 * and the original input file the output.
207 */
208 static void
209 bakcopy(void)
210 {
211 ssize_t n;
212 int bak_fd;
213 char buff[8 * 1024];
214
215 const char *last_slash = strrchr(in_name, '/');
216 snprintf(bakfile, sizeof(bakfile), "%s%s",
217 last_slash != NULL ? last_slash + 1 : in_name, backup_suffix);
218
219 /* copy in_name to backup file */
220 bak_fd = creat(bakfile, 0600);
221 if (bak_fd < 0)
222 err(1, "%s", bakfile);
223
224 while ((n = read(fileno(input), buff, sizeof(buff))) > 0)
225 if (write(bak_fd, buff, (size_t)n) != n)
226 err(1, "%s", bakfile);
227 if (n < 0)
228 err(1, "%s", in_name);
229
230 close(bak_fd);
231 (void)fclose(input);
232
233 /* re-open backup file as the input file */
234 input = fopen(bakfile, "r");
235 if (input == NULL)
236 err(1, "%s", bakfile);
237 /* now the original input file will be the output */
238 output = fopen(in_name, "w");
239 if (output == NULL) {
240 unlink(bakfile);
241 err(1, "%s", in_name);
242 }
243 }
244
245 static void
246 parse_command_line(int argc, char **argv)
247 {
248 for (int i = 1; i < argc; ++i) {
249 const char *arg = argv[i];
250
251 if (arg[0] == '-') {
252 set_option(arg, "Command line");
253
254 } else if (input == NULL) {
255 in_name = arg;
256 if ((input = fopen(in_name, "r")) == NULL)
257 err(1, "%s", in_name);
258
259 } else if (output == NULL) {
260 if (strcmp(arg, in_name) == 0)
261 errx(1, "input and output files "
262 "must be different");
263 if ((output = fopen(arg, "w")) == NULL)
264 err(1, "%s", arg);
265
266 } else
267 errx(1, "too many arguments: %s", arg);
268 }
269
270 if (input == NULL) {
271 input = stdin;
272 output = stdout;
273 } else if (output == NULL)
274 bakcopy();
275
276 if (opt.comment_column <= 1)
277 opt.comment_column = 2; /* don't put normal comments in column
278 * 1, see opt.format_col1_comments */
279 if (opt.block_comment_max_line_length <= 0)
280 opt.block_comment_max_line_length = opt.max_line_length;
281 if (opt.local_decl_indent < 0)
282 opt.local_decl_indent = opt.decl_indent;
283 if (opt.decl_comment_column <= 0)
284 opt.decl_comment_column = opt.left_justify_decl
285 ? (opt.comment_column <= 10 ? 2 : opt.comment_column - 8)
286 : opt.comment_column;
287 if (opt.continuation_indent == 0)
288 opt.continuation_indent = opt.indent_size;
289 }
290
291 static void
292 set_initial_indentation(void)
293 {
294 inp_read_line();
295
296 int ind = 0;
297 for (const char *p = inp_p;; p++) {
298 if (*p == ' ')
299 ind++;
300 else if (*p == '\t')
301 ind = next_tab(ind);
302 else
303 break;
304 }
305
306 ps.ind_level = ps.ind_level_follow = ind / opt.indent_size;
307 }
308
309 static void
310 maybe_break_line(lexer_symbol lsym)
311 {
312 if (!ps.force_nl)
313 return;
314 if (lsym == lsym_semicolon)
315 return;
316 if (lsym == lsym_lbrace && opt.brace_same_line
317 && ps.prev_lsym != lsym_lbrace)
318 return;
319
320 output_line();
321 ps.force_nl = false;
322 }
323
324 static void
325 move_com_to_code(lexer_symbol lsym)
326 {
327 if (ps.want_blank)
328 buf_add_char(&code, ' ');
329 buf_add_buf(&code, &com);
330 com.len = 0;
331 ps.want_blank = lsym != lsym_rparen && lsym != lsym_rbracket;
332 }
333
334 static void
335 update_ps_lbrace_kind(lexer_symbol lsym)
336 {
337 if (lsym == lsym_tag) {
338 ps.lbrace_kind = token.s[0] == 's' ? psym_lbrace_struct :
339 token.s[0] == 'u' ? psym_lbrace_union :
340 psym_lbrace_enum;
341 } else if (lsym != lsym_type_outside_parentheses
342 && lsym != lsym_word
343 && lsym != lsym_lbrace)
344 ps.lbrace_kind = psym_lbrace_block;
345 }
346
347 static void
348 indent_declarator(int decl_ind, bool tabs_to_var)
349 {
350 int base = ps.ind_level * opt.indent_size;
351 int ind = base + (int)code.len;
352 int target = base + decl_ind;
353 size_t orig_code_len = code.len;
354
355 if (tabs_to_var)
356 for (int next; (next = next_tab(ind)) <= target; ind = next)
357 buf_add_char(&code, '\t');
358
359 for (; ind < target; ind++)
360 buf_add_char(&code, ' ');
361
362 if (code.len == orig_code_len && ps.want_blank) {
363 buf_add_char(&code, ' ');
364 ps.want_blank = false;
365 }
366 ps.decl_indent_done = true;
367 }
368
369 static bool
370 is_function_pointer_declaration(void)
371 {
372 return ps.in_decl
373 && !ps.in_init
374 && !ps.decl_indent_done
375 && !ps.in_func_def_line
376 && ps.line_start_nparen == 0;
377 }
378
379 static int
380 process_eof(void)
381 {
382 output_finish();
383
384 if (ps.psyms.top > 1) /* check for balanced braces */
385 diag(1, "Stuff missing from end of file");
386
387 return found_err ? EXIT_FAILURE : EXIT_SUCCESS;
388 }
389
390 /* move the whole line to the 'label' buffer */
391 static void
392 read_preprocessing_line(void)
393 {
394 enum {
395 PLAIN, STR, CHR, COMM
396 } state = PLAIN;
397
398 buf_add_char(&lab, '#');
399
400 while (inp_p[0] != '\n' || (state == COMM && !had_eof)) {
401 buf_add_char(&lab, inp_next());
402 switch (lab.s[lab.len - 1]) {
403 case '\\':
404 if (state != COMM)
405 buf_add_char(&lab, inp_next());
406 break;
407 case '/':
408 if (inp_p[0] == '*' && state == PLAIN) {
409 state = COMM;
410 buf_add_char(&lab, *inp_p++);
411 }
412 break;
413 case '"':
414 if (state == STR)
415 state = PLAIN;
416 else if (state == PLAIN)
417 state = STR;
418 break;
419 case '\'':
420 if (state == CHR)
421 state = PLAIN;
422 else if (state == PLAIN)
423 state = CHR;
424 break;
425 case '*':
426 if (inp_p[0] == '/' && state == COMM) {
427 state = PLAIN;
428 buf_add_char(&lab, *inp_p++);
429 }
430 break;
431 }
432 }
433
434 while (lab.len > 0 && ch_isblank(lab.s[lab.len - 1]))
435 lab.len--;
436 }
437
438 static void
439 process_preprocessing(void)
440 {
441 if (lab.len > 0 || code.len > 0 || com.len > 0)
442 output_line();
443
444 read_preprocessing_line();
445
446 const char *dir = lab.s + 1, *line_end = lab.s + lab.len;
447 while (dir < line_end && ch_isblank(*dir))
448 dir++;
449 size_t dir_len = 0;
450 while (dir + dir_len < line_end && ch_isalpha(dir[dir_len]))
451 dir_len++;
452
453 if (dir_len >= 2 && memcmp(dir, "if", 2) == 0) {
454 if ((size_t)ifdef_level < array_length(state_stack))
455 state_stack[ifdef_level++] = ps;
456 else
457 diag(1, "#if stack overflow");
458 out.line_kind = lk_if;
459
460 } else if (dir_len >= 2 && memcmp(dir, "el", 2) == 0) {
461 if (ifdef_level <= 0)
462 diag(1, dir[2] == 'i'
463 ? "Unmatched #elif" : "Unmatched #else");
464 else
465 ps = state_stack[ifdef_level - 1];
466
467 } else if (dir_len == 5 && memcmp(dir, "endif", 5) == 0) {
468 if (ifdef_level <= 0)
469 diag(1, "Unmatched #endif");
470 else
471 ifdef_level--;
472 out.line_kind = lk_endif;
473 }
474 }
475
476 static void
477 process_newline(void)
478 {
479 if (ps.prev_lsym == lsym_comma
480 && ps.nparen == 0 && !ps.in_init
481 && !opt.break_after_comma && ps.break_after_comma
482 && lab.len == 0 /* for preprocessing lines */
483 && com.len == 0)
484 goto stay_in_line;
485 if (ps.psyms.sym[ps.psyms.top] == psym_switch_expr
486 && opt.brace_same_line) {
487 ps.force_nl = true;
488 goto stay_in_line;
489 }
490
491 output_line();
492
493 stay_in_line:
494 ++line_no;
495 }
496
497 static bool
498 want_blank_before_lparen(void)
499 {
500 if (!ps.want_blank)
501 return false;
502 if (opt.proc_calls_space)
503 return true;
504 if (ps.prev_lsym == lsym_rparen || ps.prev_lsym == lsym_rbracket)
505 return false;
506 if (ps.prev_lsym == lsym_offsetof)
507 return false;
508 if (ps.prev_lsym == lsym_sizeof)
509 return opt.blank_after_sizeof;
510 if (ps.prev_lsym == lsym_word || ps.prev_lsym == lsym_funcname)
511 return false;
512 return true;
513 }
514
515 static void
516 process_lparen(void)
517 {
518 if (++ps.nparen == array_length(ps.paren)) {
519 diag(0, "Reached internal limit of %zu unclosed parentheses",
520 array_length(ps.paren));
521 ps.nparen--;
522 }
523
524 if (is_function_pointer_declaration())
525 indent_declarator(ps.decl_ind, ps.tabs_to_var);
526 else if (want_blank_before_lparen())
527 buf_add_char(&code, ' ');
528 ps.want_blank = false;
529 buf_add_char(&code, token.s[0]);
530
531 if (opt.extra_expr_indent && ps.spaced_expr_psym != psym_0)
532 ps.extra_expr_indent = eei_maybe;
533
534 if (ps.in_var_decl && ps.psyms.top <= 2 && !ps.in_init) {
535 parse(psym_stmt); /* prepare for function definition */
536 ps.in_var_decl = false;
537 }
538
539 int indent = ind_add(0, code.s, code.len);
540
541 enum paren_level_cast cast = cast_unknown;
542 if (ps.prev_lsym == lsym_offsetof
543 || ps.prev_lsym == lsym_sizeof
544 || ps.prev_lsym == lsym_for
545 || ps.prev_lsym == lsym_if
546 || ps.prev_lsym == lsym_switch
547 || ps.prev_lsym == lsym_while
548 || ps.in_func_def_line)
549 cast = cast_no;
550
551 ps.paren[ps.nparen - 1].indent = indent;
552 ps.paren[ps.nparen - 1].cast = cast;
553 debug_println("paren_indents[%d] is now %s%d",
554 ps.nparen - 1, paren_level_cast_name[cast], indent);
555 }
556
557 static void
558 process_rparen(void)
559 {
560 if (ps.nparen == 0) {
561 diag(0, "Extra '%c'", *token.s);
562 goto unbalanced;
563 }
564
565 enum paren_level_cast cast = ps.paren[--ps.nparen].cast;
566 if (ps.in_func_def_params || (ps.line_has_decl && !ps.in_init))
567 cast = cast_no;
568
569 ps.prev_paren_was_cast = cast == cast_maybe;
570 if (cast == cast_maybe) {
571 ps.next_unary = true;
572 ps.want_blank = opt.space_after_cast;
573 } else
574 ps.want_blank = true;
575
576 if (code.len == 0)
577 ps.line_start_nparen = ps.nparen;
578
579 unbalanced:
580 buf_add_char(&code, token.s[0]);
581
582 if (ps.spaced_expr_psym != psym_0 && ps.nparen == 0) {
583 if (ps.extra_expr_indent == eei_maybe)
584 ps.extra_expr_indent = eei_last;
585 ps.force_nl = true;
586 ps.next_unary = true;
587 ps.in_stmt_or_decl = false;
588 parse(ps.spaced_expr_psym);
589 ps.spaced_expr_psym = psym_0;
590 ps.want_blank = true;
591 out.line_kind = lk_stmt_head;
592 }
593 }
594
595 static void
596 process_lbracket(void)
597 {
598 if (++ps.nparen == array_length(ps.paren)) {
599 diag(0, "Reached internal limit of %zu unclosed parentheses",
600 array_length(ps.paren));
601 ps.nparen--;
602 }
603
604 if (code.len > 0
605 && (ps.prev_lsym == lsym_comma || ps.prev_lsym == lsym_binary_op))
606 buf_add_char(&code, ' ');
607 ps.want_blank = false;
608 buf_add_char(&code, token.s[0]);
609
610 int indent = ind_add(0, code.s, code.len);
611
612 ps.paren[ps.nparen - 1].indent = indent;
613 ps.paren[ps.nparen - 1].cast = cast_no;
614 debug_println("paren_indents[%d] is now %d", ps.nparen - 1, indent);
615 }
616
617 static void
618 process_rbracket(void)
619 {
620 if (ps.nparen == 0) {
621 diag(0, "Extra '%c'", *token.s);
622 goto unbalanced;
623 }
624 --ps.nparen;
625
626 ps.want_blank = true;
627 if (code.len == 0)
628 ps.line_start_nparen = ps.nparen;
629
630 unbalanced:
631 buf_add_char(&code, token.s[0]);
632 }
633
634 static void
635 process_lbrace(void)
636 {
637 if (ps.prev_lsym == lsym_rparen && ps.prev_paren_was_cast) {
638 ps.in_var_decl = true; // XXX: not really
639 ps.in_init = true;
640 }
641
642 if (out.line_kind == lk_stmt_head)
643 out.line_kind = lk_other;
644
645 ps.in_stmt_or_decl = false; /* don't indent the {} */
646
647 if (!ps.in_init)
648 ps.force_nl = true;
649 else
650 ps.init_level++;
651
652 if (code.len > 0 && !ps.in_init) {
653 if (!opt.brace_same_line ||
654 (code.len > 0 && code.s[code.len - 1] == '}'))
655 output_line();
656 else if (ps.in_func_def_params && !ps.in_var_decl) {
657 ps.ind_level_follow = 0;
658 if (opt.function_brace_split)
659 output_line();
660 else
661 ps.want_blank = true;
662 }
663 }
664
665 if (ps.nparen > 0 && ps.init_level == 0) {
666 diag(1, "Unbalanced parentheses");
667 ps.nparen = 0;
668 if (ps.spaced_expr_psym != psym_0) {
669 parse(ps.spaced_expr_psym);
670 ps.spaced_expr_psym = psym_0;
671 ps.ind_level = ps.ind_level_follow;
672 }
673 }
674
675 if (code.len == 0)
676 ps.in_stmt_cont = false; /* don't indent the '{' itself
677 */
678 if (ps.in_decl && ps.in_var_decl) {
679 ps.di_stack[ps.decl_level] = ps.decl_ind;
680 if (++ps.decl_level == (int)array_length(ps.di_stack)) {
681 diag(0, "Reached internal limit of %zu struct levels",
682 array_length(ps.di_stack));
683 ps.decl_level--;
684 }
685 } else {
686 ps.line_has_decl = false; /* we can't be in the middle of
687 * a declaration, so don't do
688 * special indentation of
689 * comments */
690 ps.in_func_def_params = false;
691 ps.in_decl = false;
692 }
693
694 ps.decl_ind = 0;
695 parse(ps.lbrace_kind);
696 if (ps.want_blank)
697 buf_add_char(&code, ' ');
698 ps.want_blank = false;
699 buf_add_char(&code, '{');
700 ps.declaration = decl_no;
701 }
702
703 static void
704 process_rbrace(void)
705 {
706 if (ps.nparen > 0 && ps.init_level == 0) {
707 diag(1, "Unbalanced parentheses");
708 ps.nparen = 0;
709 ps.spaced_expr_psym = psym_0;
710 }
711
712 ps.declaration = decl_no;
713 if (ps.init_level > 0)
714 ps.init_level--;
715
716 if (code.len > 0 && !ps.in_init)
717 output_line();
718
719 buf_add_char(&code, '}');
720 ps.want_blank = true;
721 ps.in_stmt_or_decl = false; // XXX: Initializers don't end a stmt
722 ps.in_stmt_cont = false;
723
724 if (ps.decl_level > 0) { /* multi-level structure declaration */
725 ps.decl_ind = ps.di_stack[--ps.decl_level];
726 if (ps.decl_level == 0 && !ps.in_func_def_params) {
727 ps.declaration = decl_begin;
728 ps.decl_ind = ps.ind_level == 0
729 ? opt.decl_indent : opt.local_decl_indent;
730 }
731 ps.in_decl = true;
732 }
733
734 if (ps.psyms.top == 2)
735 out.line_kind = lk_func_end;
736
737 parse(psym_rbrace);
738
739 if (!ps.in_var_decl
740 && ps.psyms.sym[ps.psyms.top] != psym_do_stmt
741 && ps.psyms.sym[ps.psyms.top] != psym_if_expr_stmt)
742 ps.force_nl = true;
743 }
744
745 static void
746 process_period(void)
747 {
748 if (code.len > 0 && code.s[code.len - 1] == ',')
749 buf_add_char(&code, ' ');
750 buf_add_char(&code, '.');
751 ps.want_blank = false;
752 }
753
754 static void
755 process_unary_op(void)
756 {
757 if (is_function_pointer_declaration()) {
758 int ind = ps.decl_ind - (int)token.len;
759 indent_declarator(ind, ps.tabs_to_var);
760 ps.want_blank = false;
761 } else if ((token.s[0] == '+' || token.s[0] == '-')
762 && code.len > 0 && code.s[code.len - 1] == token.s[0])
763 ps.want_blank = true;
764
765 if (ps.want_blank)
766 buf_add_char(&code, ' ');
767 buf_add_buf(&code, &token);
768 ps.want_blank = false;
769 }
770
771 static void
772 process_postfix_op(void)
773 {
774 buf_add_buf(&code, &token);
775 ps.want_blank = true;
776 }
777
778 static void
779 process_question(void)
780 {
781 ps.quest_level++;
782 if (code.len == 0) {
783 ps.in_stmt_cont = true;
784 ps.in_stmt_or_decl = true;
785 ps.in_decl = false;
786 }
787 }
788
789 static void
790 process_colon_question(void)
791 {
792 if (code.len == 0) {
793 ps.in_stmt_cont = true;
794 ps.in_stmt_or_decl = true;
795 ps.in_decl = false;
796 }
797 }
798
799 static void
800 process_comma(void)
801 {
802 ps.want_blank = code.len > 0; /* only put blank after comma if comma
803 * does not start the line */
804
805 if (ps.in_decl && !ps.in_func_def_line && !ps.in_init &&
806 !ps.decl_indent_done && ps.line_start_nparen == 0) {
807 /* indent leading commas and not the actual identifiers */
808 indent_declarator(ps.decl_ind - 1, ps.tabs_to_var);
809 }
810
811 buf_add_char(&code, ',');
812
813 if (ps.nparen == 0) {
814 if (ps.init_level == 0)
815 ps.in_init = false;
816 int typical_varname_length = 8;
817 if (ps.break_after_comma && (opt.break_after_comma ||
818 ind_add(compute_code_indent(), code.s, code.len)
819 >= opt.max_line_length - typical_varname_length))
820 ps.force_nl = true;
821 }
822 }
823
824 static void
825 process_colon_label(void)
826 {
827 buf_add_buf(&lab, &code);
828 buf_add_char(&lab, ':');
829 code.len = 0;
830
831 if (ps.seen_case)
832 out.line_kind = lk_case_or_default;
833 ps.in_stmt_or_decl = false;
834 ps.force_nl = ps.seen_case;
835 ps.seen_case = false;
836 ps.want_blank = false;
837 }
838
839 static void
840 process_colon_other(void)
841 {
842 buf_add_char(&code, ':');
843 ps.want_blank = ps.decl_level == 0;
844 }
845
846 static void
847 process_semicolon(void)
848 {
849 if (out.line_kind == lk_stmt_head)
850 out.line_kind = lk_other;
851 if (ps.decl_level == 0)
852 ps.in_var_decl = false;
853 ps.seen_case = false; /* only needs to be reset on error */
854 ps.quest_level = 0; /* only needs to be reset on error */
855 if (ps.prev_lsym == lsym_rparen)
856 ps.in_func_def_params = false;
857 ps.in_init = false;
858 ps.init_level = 0;
859 ps.declaration = ps.declaration == decl_begin ? decl_end : decl_no;
860
861 if (ps.in_decl && code.len == 0 && !ps.in_init &&
862 !ps.decl_indent_done && ps.line_start_nparen == 0) {
863 /* indent stray semicolons in declarations */
864 indent_declarator(ps.decl_ind - 1, ps.tabs_to_var);
865 }
866
867 ps.in_decl = ps.decl_level > 0; /* if we were in a first level
868 * structure declaration before, we
869 * aren't anymore */
870
871 if (ps.nparen > 0 && ps.spaced_expr_psym != psym_for_exprs) {
872 /* There were unbalanced parentheses in the statement. It is a
873 * bit complicated, because the semicolon might be in a for
874 * statement. */
875 diag(1, "Unbalanced parentheses");
876 ps.nparen = 0;
877 if (ps.spaced_expr_psym != psym_0) {
878 parse(ps.spaced_expr_psym);
879 ps.spaced_expr_psym = psym_0;
880 }
881 }
882 buf_add_char(&code, ';');
883 ps.want_blank = true;
884 ps.in_stmt_or_decl = ps.nparen > 0;
885 ps.decl_ind = 0;
886
887 if (ps.spaced_expr_psym == psym_0) {
888 parse(psym_stmt);
889 ps.force_nl = true;
890 }
891 }
892
893 static void
894 process_type(void)
895 {
896 parse(psym_decl); /* let the parser worry about indentation */
897
898 if (ps.prev_lsym == lsym_rparen && ps.psyms.top <= 1 && code.len > 0)
899 output_line();
900
901 if (ps.in_func_def_params && opt.indent_parameters &&
902 ps.decl_level == 0) {
903 ps.ind_level = ps.ind_level_follow = 1;
904 ps.in_stmt_cont = false;
905 }
906
907 ps.in_var_decl = /* maybe */ true;
908 ps.in_decl = ps.line_has_decl = ps.prev_lsym != lsym_typedef;
909 if (ps.decl_level <= 0)
910 ps.declaration = decl_begin;
911
912 int len = (int)token.len + 1;
913 int ind = ps.ind_level == 0 || ps.decl_level > 0
914 ? opt.decl_indent /* global variable or local member */
915 : opt.local_decl_indent; /* local variable */
916 ps.decl_ind = ind > 0 ? ind : len;
917 ps.tabs_to_var = opt.use_tabs && ind > 0;
918 }
919
920 static void
921 process_ident(lexer_symbol lsym)
922 {
923 if (ps.in_decl) {
924 if (lsym == lsym_funcname) {
925 ps.in_decl = false;
926 if (opt.procnames_start_line && code.len > 0)
927 output_line();
928 else if (ps.want_blank)
929 buf_add_char(&code, ' ');
930 ps.want_blank = false;
931
932 } else if (!ps.in_init && !ps.decl_indent_done &&
933 ps.line_start_nparen == 0) {
934 if (opt.decl_indent == 0
935 && code.len > 0 && code.s[code.len - 1] == '}')
936 ps.decl_ind = ind_add(0, code.s, code.len) + 1;
937 indent_declarator(ps.decl_ind, ps.tabs_to_var);
938 ps.want_blank = false;
939 }
940
941 } else if (ps.spaced_expr_psym != psym_0 && ps.nparen == 0) {
942 ps.force_nl = true;
943 ps.next_unary = true;
944 ps.in_stmt_or_decl = false;
945 parse(ps.spaced_expr_psym);
946 ps.spaced_expr_psym = psym_0;
947 }
948 }
949
950 static void
951 process_do(void)
952 {
953 ps.in_stmt_or_decl = false;
954 ps.in_decl = false;
955
956 if (code.len > 0)
957 output_line();
958
959 ps.force_nl = true;
960 parse(psym_do);
961 }
962
963 static void
964 process_else(void)
965 {
966 ps.in_stmt_or_decl = false;
967
968 if (code.len > 0
969 && !(opt.cuddle_else && code.s[code.len - 1] == '}'))
970 output_line();
971
972 ps.force_nl = true;
973 parse(psym_else);
974 }
975
976 static void
977 process_lsym(lexer_symbol lsym)
978 {
979 switch (lsym) {
980 /* INDENT OFF */
981 case lsym_preprocessing: process_preprocessing(); break;
982 case lsym_newline: process_newline(); break;
983 case lsym_comment: process_comment(); break;
984 case lsym_lparen: process_lparen(); break;
985 case lsym_lbracket: process_lbracket(); break;
986 case lsym_rparen: process_rparen(); break;
987 case lsym_rbracket: process_rbracket(); break;
988 case lsym_lbrace: process_lbrace(); break;
989 case lsym_rbrace: process_rbrace(); break;
990 case lsym_period: process_period(); break;
991 case lsym_unary_op: process_unary_op(); break;
992 case lsym_postfix_op: process_postfix_op(); break;
993 case lsym_binary_op: goto copy_token;
994 case lsym_question: process_question(); goto copy_token;
995 case lsym_colon_question: process_colon_question(); goto copy_token;
996 case lsym_colon_label: process_colon_label(); break;
997 case lsym_colon_other: process_colon_other(); break;
998 case lsym_comma: process_comma(); break;
999 case lsym_semicolon: process_semicolon(); break;
1000 case lsym_typedef: goto copy_token;
1001 case lsym_modifier: goto copy_token;
1002 case lsym_case: ps.seen_case = true; goto copy_token;
1003 case lsym_default: ps.seen_case = true; goto copy_token;
1004 case lsym_do: process_do(); goto copy_token;
1005 case lsym_else: process_else(); goto copy_token;
1006 case lsym_for: ps.spaced_expr_psym = psym_for_exprs; goto copy_token;
1007 case lsym_if: ps.spaced_expr_psym = psym_if_expr; goto copy_token;
1008 case lsym_switch: ps.spaced_expr_psym = psym_switch_expr; goto copy_token;
1009 case lsym_while: ps.spaced_expr_psym = psym_while_expr; goto copy_token;
1010 /* INDENT ON */
1011
1012 case lsym_tag:
1013 if (ps.nparen > 0)
1014 goto copy_token;
1015 /* FALLTHROUGH */
1016 case lsym_type_outside_parentheses:
1017 process_type();
1018 goto copy_token;
1019
1020 case lsym_type_in_parentheses:
1021 case lsym_sizeof:
1022 case lsym_offsetof:
1023 case lsym_word:
1024 case lsym_funcname:
1025 case lsym_return:
1026 process_ident(lsym);
1027 copy_token:
1028 if (ps.want_blank)
1029 buf_add_char(&code, ' ');
1030 buf_add_buf(&code, &token);
1031 if (lsym != lsym_funcname)
1032 ps.want_blank = true;
1033 break;
1034
1035 default:
1036 break;
1037 }
1038 }
1039
1040 static int
1041 indent(void)
1042 {
1043 debug_parser_state();
1044
1045 for (;;) { /* loop until we reach eof */
1046 lexer_symbol lsym = lexi();
1047
1048 debug_blank_line();
1049 debug_printf("line %d: %s", line_no, lsym_name[lsym]);
1050 debug_print_buf("token", &token);
1051 debug_buffers();
1052 debug_blank_line();
1053
1054 if (lsym == lsym_eof)
1055 return process_eof();
1056
1057 if (lsym == lsym_if && ps.prev_lsym == lsym_else
1058 && opt.else_if_in_same_line)
1059 ps.force_nl = false;
1060
1061 if (lsym == lsym_newline || lsym == lsym_preprocessing)
1062 ps.force_nl = false;
1063 else if (lsym == lsym_comment) {
1064 /* no special processing */
1065 } else {
1066 maybe_break_line(lsym);
1067 ps.in_stmt_or_decl = true;
1068 if (com.len > 0)
1069 move_com_to_code(lsym);
1070 update_ps_lbrace_kind(lsym);
1071 }
1072
1073 process_lsym(lsym);
1074
1075 debug_parser_state();
1076
1077 if (lsym != lsym_comment && lsym != lsym_newline &&
1078 lsym != lsym_preprocessing)
1079 ps.prev_lsym = lsym;
1080 }
1081 }
1082
1083 int
1084 main(int argc, char **argv)
1085 {
1086 init_globals();
1087 load_profiles(argc, argv);
1088 parse_command_line(argc, argv);
1089 set_initial_indentation();
1090 return indent();
1091 }
1092