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