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