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