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