1 /*- 2 * Copyright (c) 1985 Sun Microsystems, Inc. 3 * Copyright (c) 1976 Board of Trustees of the University of Illinois. 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifndef lint 37 static const char copyright[] = 38 "@(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\ 39 @(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\ 40 @(#) Copyright (c) 1980, 1993\n\ 41 The Regents of the University of California. All rights reserved.\n"; 42 #endif /* not lint */ 43 44 #if 0 45 #ifndef lint 46 static char sccsid[] = "@(#)indent.c 5.17 (Berkeley) 6/7/93"; 47 #endif /* not lint */ 48 #endif 49 50 #include <sys/cdefs.h> 51 __FBSDID("$FreeBSD$"); 52 53 #include <sys/param.h> 54 #include <err.h> 55 #include <fcntl.h> 56 #include <unistd.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <ctype.h> 61 #include "indent_globs.h" 62 #include "indent_codes.h" 63 #include "indent.h" 64 65 static void bakcopy(void); 66 static void indent_declaration(int, int); 67 68 const char *in_name = "Standard Input"; /* will always point to name of input 69 * file */ 70 const char *out_name = "Standard Output"; /* will always point to name 71 * of output file */ 72 char bakfile[MAXPATHLEN] = ""; 73 74 int 75 main(int argc, char **argv) 76 { 77 78 int dec_ind; /* current indentation for declarations */ 79 int di_stack[20]; /* a stack of structure indentation levels */ 80 int flushed_nl; /* used when buffering up comments to remember 81 * that a newline was passed over */ 82 int force_nl; /* when true, code must be broken */ 83 int hd_type = 0; /* used to store type of stmt for if (...), 84 * for (...), etc */ 85 int i; /* local loop counter */ 86 int scase; /* set to true when we see a case, so we will 87 * know what to do with the following colon */ 88 int sp_sw; /* when true, we are in the expression of 89 * if(...), while(...), etc. */ 90 int squest; /* when this is positive, we have seen a ? 91 * without the matching : in a <c>?<s>:<s> 92 * construct */ 93 const char *t_ptr; /* used for copying tokens */ 94 int tabs_to_var; /* true if using tabs to indent to var name */ 95 int type_code; /* the type of token, returned by lexi */ 96 97 int last_else = 0; /* true iff last keyword was an else */ 98 99 100 /*-----------------------------------------------*\ 101 | INITIALIZATION | 102 \*-----------------------------------------------*/ 103 104 found_err = 0; 105 106 ps.p_stack[0] = stmt; /* this is the parser's stack */ 107 ps.last_nl = true; /* this is true if the last thing scanned was 108 * a newline */ 109 ps.last_token = semicolon; 110 combuf = (char *) malloc(bufsize); 111 if (combuf == NULL) 112 err(1, NULL); 113 labbuf = (char *) malloc(bufsize); 114 if (labbuf == NULL) 115 err(1, NULL); 116 codebuf = (char *) malloc(bufsize); 117 if (codebuf == NULL) 118 err(1, NULL); 119 tokenbuf = (char *) malloc(bufsize); 120 if (tokenbuf == NULL) 121 err(1, NULL); 122 alloc_typenames(); 123 l_com = combuf + bufsize - 5; 124 l_lab = labbuf + bufsize - 5; 125 l_code = codebuf + bufsize - 5; 126 l_token = tokenbuf + bufsize - 5; 127 combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label, and 128 * comment buffers */ 129 combuf[1] = codebuf[1] = labbuf[1] = '\0'; 130 ps.else_if = 1; /* Default else-if special processing to on */ 131 s_lab = e_lab = labbuf + 1; 132 s_code = e_code = codebuf + 1; 133 s_com = e_com = combuf + 1; 134 s_token = e_token = tokenbuf + 1; 135 136 in_buffer = (char *) malloc(10); 137 if (in_buffer == NULL) 138 err(1, NULL); 139 in_buffer_limit = in_buffer + 8; 140 buf_ptr = buf_end = in_buffer; 141 line_no = 1; 142 had_eof = ps.in_decl = ps.decl_on_line = break_comma = false; 143 sp_sw = force_nl = false; 144 ps.in_or_st = false; 145 ps.bl_line = true; 146 dec_ind = 0; 147 di_stack[ps.dec_nest = 0] = 0; 148 ps.want_blank = ps.in_stmt = ps.ind_stmt = false; 149 150 scase = ps.pcase = false; 151 squest = 0; 152 sc_end = NULL; 153 bp_save = NULL; 154 be_save = NULL; 155 156 output = NULL; 157 tabs_to_var = 0; 158 159 /*--------------------------------------------------*\ 160 | COMMAND LINE SCAN | 161 \*--------------------------------------------------*/ 162 163 #ifdef undef 164 max_col = 78; /* -l78 */ 165 lineup_to_parens = 1; /* -lp */ 166 ps.ljust_decl = 0; /* -ndj */ 167 ps.com_ind = 33; /* -c33 */ 168 star_comment_cont = 1; /* -sc */ 169 ps.ind_size = 8; /* -i8 */ 170 verbose = 0; 171 ps.decl_indent = 16; /* -di16 */ 172 ps.local_decl_indent = -1; /* if this is not set to some nonnegative value 173 * by an arg, we will set this equal to 174 * ps.decl_ind */ 175 ps.indent_parameters = 1; /* -ip */ 176 ps.decl_com_ind = 0; /* if this is not set to some positive value 177 * by an arg, we will set this equal to 178 * ps.com_ind */ 179 btype_2 = 1; /* -br */ 180 cuddle_else = 1; /* -ce */ 181 ps.unindent_displace = 0; /* -d0 */ 182 ps.case_indent = 0; /* -cli0 */ 183 format_block_comments = 1; /* -fcb */ 184 format_col1_comments = 1; /* -fc1 */ 185 procnames_start_line = 1; /* -psl */ 186 proc_calls_space = 0; /* -npcs */ 187 comment_delimiter_on_blankline = 1; /* -cdb */ 188 ps.leave_comma = 1; /* -nbc */ 189 #endif 190 191 for (i = 1; i < argc; ++i) 192 if (strcmp(argv[i], "-npro") == 0) 193 break; 194 set_defaults(); 195 if (i >= argc) 196 set_profile(); 197 198 for (i = 1; i < argc; ++i) { 199 200 /* 201 * look thru args (if any) for changes to defaults 202 */ 203 if (argv[i][0] != '-') {/* no flag on parameter */ 204 if (input == NULL) { /* we must have the input file */ 205 in_name = argv[i]; /* remember name of input file */ 206 input = fopen(in_name, "r"); 207 if (input == NULL) /* check for open error */ 208 err(1, "%s", in_name); 209 continue; 210 } 211 else if (output == NULL) { /* we have the output file */ 212 out_name = argv[i]; /* remember name of output file */ 213 if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite 214 * the file */ 215 errx(1, "input and output files must be different"); 216 } 217 output = fopen(out_name, "w"); 218 if (output == NULL) /* check for create error */ 219 err(1, "%s", out_name); 220 continue; 221 } 222 errx(1, "unknown parameter: %s", argv[i]); 223 } 224 else 225 set_option(argv[i]); 226 } /* end of for */ 227 if (input == NULL) 228 input = stdin; 229 if (output == NULL) { 230 if (troff || input == stdin) 231 output = stdout; 232 else { 233 out_name = in_name; 234 bakcopy(); 235 } 236 } 237 if (ps.com_ind <= 1) 238 ps.com_ind = 2; /* dont put normal comments before column 2 */ 239 if (troff) { 240 if (bodyf.font[0] == 0) 241 parsefont(&bodyf, "R"); 242 if (scomf.font[0] == 0) 243 parsefont(&scomf, "I"); 244 if (blkcomf.font[0] == 0) 245 blkcomf = scomf, blkcomf.size += 2; 246 if (boxcomf.font[0] == 0) 247 boxcomf = blkcomf; 248 if (stringf.font[0] == 0) 249 parsefont(&stringf, "L"); 250 if (keywordf.font[0] == 0) 251 parsefont(&keywordf, "B"); 252 writefdef(&bodyf, 'B'); 253 writefdef(&scomf, 'C'); 254 writefdef(&blkcomf, 'L'); 255 writefdef(&boxcomf, 'X'); 256 writefdef(&stringf, 'S'); 257 writefdef(&keywordf, 'K'); 258 } 259 if (block_comment_max_col <= 0) 260 block_comment_max_col = max_col; 261 if (ps.local_decl_indent < 0) /* if not specified by user, set this */ 262 ps.local_decl_indent = ps.decl_indent; 263 if (ps.decl_com_ind <= 0) /* if not specified by user, set this */ 264 ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind; 265 if (continuation_indent == 0) 266 continuation_indent = ps.ind_size; 267 fill_buffer(); /* get first batch of stuff into input buffer */ 268 269 parse(semicolon); 270 { 271 char *p = buf_ptr; 272 int col = 1; 273 274 while (1) { 275 if (*p == ' ') 276 col++; 277 else if (*p == '\t') 278 col = ((col - 1) & ~7) + 9; 279 else 280 break; 281 p++; 282 } 283 if (col > ps.ind_size) 284 ps.ind_level = ps.i_l_follow = col / ps.ind_size; 285 } 286 if (troff) { 287 const char *p = in_name, 288 *beg = in_name; 289 290 while (*p) 291 if (*p++ == '/') 292 beg = p; 293 fprintf(output, ".Fn \"%s\"\n", beg); 294 } 295 /* 296 * START OF MAIN LOOP 297 */ 298 299 while (1) { /* this is the main loop. it will go until we 300 * reach eof */ 301 int is_procname; 302 303 type_code = lexi(); /* lexi reads one token. The actual 304 * characters read are stored in "token". lexi 305 * returns a code indicating the type of token */ 306 is_procname = ps.procname[0]; 307 308 /* 309 * The following code moves everything following an if (), while (), 310 * else, etc. up to the start of the following stmt to a buffer. This 311 * allows proper handling of both kinds of brace placement. 312 */ 313 314 flushed_nl = false; 315 while (ps.search_brace) { /* if we scanned an if(), while(), 316 * etc., we might need to copy stuff 317 * into a buffer we must loop, copying 318 * stuff into save_com, until we find 319 * the start of the stmt which follows 320 * the if, or whatever */ 321 switch (type_code) { 322 case newline: 323 ++line_no; 324 if (sc_end != NULL) 325 goto sw_buffer; /* dump comment, if any */ 326 flushed_nl = true; 327 case form_feed: 328 break; /* form feeds and newlines found here will be 329 * ignored */ 330 331 case lbrace: /* this is a brace that starts the compound 332 * stmt */ 333 if (sc_end == NULL) { /* ignore buffering if a comment wasn't 334 * stored up */ 335 ps.search_brace = false; 336 goto check_type; 337 } 338 if (btype_2) { 339 save_com[0] = '{'; /* we either want to put the brace 340 * right after the if */ 341 goto sw_buffer; /* go to common code to get out of 342 * this loop */ 343 } 344 case comment: /* we have a comment, so we must copy it into 345 * the buffer */ 346 if (!flushed_nl || sc_end != NULL) { 347 if (sc_end == NULL) { /* if this is the first comment, we 348 * must set up the buffer */ 349 save_com[0] = save_com[1] = ' '; 350 sc_end = &(save_com[2]); 351 } 352 else { 353 *sc_end++ = '\n'; /* add newline between 354 * comments */ 355 *sc_end++ = ' '; 356 --line_no; 357 } 358 *sc_end++ = '/'; /* copy in start of comment */ 359 *sc_end++ = '*'; 360 361 for (;;) { /* loop until we get to the end of the comment */ 362 *sc_end = *buf_ptr++; 363 if (buf_ptr >= buf_end) 364 fill_buffer(); 365 366 if (*sc_end++ == '*' && *buf_ptr == '/') 367 break; /* we are at end of comment */ 368 369 if (sc_end >= &(save_com[sc_size])) { /* check for temp buffer 370 * overflow */ 371 diag2(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever"); 372 fflush(output); 373 exit(1); 374 } 375 } 376 *sc_end++ = '/'; /* add ending slash */ 377 if (++buf_ptr >= buf_end) /* get past / in buffer */ 378 fill_buffer(); 379 break; 380 } 381 default: /* it is the start of a normal statement */ 382 if (flushed_nl) /* if we flushed a newline, make sure it is 383 * put back */ 384 force_nl = true; 385 if ((type_code == sp_paren && *token == 'i' 386 && last_else && ps.else_if) 387 || (type_code == sp_nparen && *token == 'e' 388 && e_code != s_code && e_code[-1] == '}')) 389 force_nl = false; 390 391 if (sc_end == NULL) { /* ignore buffering if comment wasn't 392 * saved up */ 393 ps.search_brace = false; 394 goto check_type; 395 } 396 if (force_nl) { /* if we should insert a nl here, put it into 397 * the buffer */ 398 force_nl = false; 399 --line_no; /* this will be re-increased when the nl is 400 * read from the buffer */ 401 *sc_end++ = '\n'; 402 *sc_end++ = ' '; 403 if (verbose && !flushed_nl) /* print error msg if the line 404 * was not already broken */ 405 diag2(0, "Line broken"); 406 flushed_nl = false; 407 } 408 for (t_ptr = token; *t_ptr; ++t_ptr) 409 *sc_end++ = *t_ptr; /* copy token into temp buffer */ 410 ps.procname[0] = 0; 411 412 sw_buffer: 413 ps.search_brace = false; /* stop looking for start of 414 * stmt */ 415 bp_save = buf_ptr; /* save current input buffer */ 416 be_save = buf_end; 417 buf_ptr = save_com; /* fix so that subsequent calls to 418 * lexi will take tokens out of 419 * save_com */ 420 *sc_end++ = ' ';/* add trailing blank, just in case */ 421 buf_end = sc_end; 422 sc_end = NULL; 423 break; 424 } /* end of switch */ 425 if (type_code != 0) /* we must make this check, just in case there 426 * was an unexpected EOF */ 427 type_code = lexi(); /* read another token */ 428 /* if (ps.search_brace) ps.procname[0] = 0; */ 429 if ((is_procname = ps.procname[0]) && flushed_nl 430 && !procnames_start_line && ps.in_decl 431 && type_code == ident) 432 flushed_nl = 0; 433 } /* end of while (search_brace) */ 434 last_else = 0; 435 check_type: 436 if (type_code == 0) { /* we got eof */ 437 if (s_lab != e_lab || s_code != e_code 438 || s_com != e_com) /* must dump end of line */ 439 dump_line(); 440 if (ps.tos > 1) /* check for balanced braces */ 441 diag2(1, "Stuff missing from end of file"); 442 443 if (verbose) { 444 printf("There were %d output lines and %d comments\n", 445 ps.out_lines, ps.out_coms); 446 printf("(Lines with comments)/(Lines with code): %6.3f\n", 447 (1.0 * ps.com_lines) / code_lines); 448 } 449 fflush(output); 450 exit(found_err); 451 } 452 if ( 453 (type_code != comment) && 454 (type_code != newline) && 455 (type_code != preesc) && 456 (type_code != form_feed)) { 457 if (force_nl && 458 (type_code != semicolon) && 459 (type_code != lbrace || !btype_2)) { 460 /* we should force a broken line here */ 461 if (verbose && !flushed_nl) 462 diag2(0, "Line broken"); 463 flushed_nl = false; 464 dump_line(); 465 ps.want_blank = false; /* dont insert blank at line start */ 466 force_nl = false; 467 } 468 ps.in_stmt = true; /* turn on flag which causes an extra level of 469 * indentation. this is turned off by a ; or 470 * '}' */ 471 if (s_com != e_com) { /* the turkey has embedded a comment 472 * in a line. fix it */ 473 *e_code++ = ' '; 474 for (t_ptr = s_com; *t_ptr; ++t_ptr) { 475 CHECK_SIZE_CODE; 476 *e_code++ = *t_ptr; 477 } 478 *e_code++ = ' '; 479 *e_code = '\0'; /* null terminate code sect */ 480 ps.want_blank = false; 481 e_com = s_com; 482 } 483 } 484 else if (type_code != comment) /* preserve force_nl thru a comment */ 485 force_nl = false; /* cancel forced newline after newline, form 486 * feed, etc */ 487 488 489 490 /*-----------------------------------------------------*\ 491 | do switch on type of token scanned | 492 \*-----------------------------------------------------*/ 493 CHECK_SIZE_CODE; 494 switch (type_code) { /* now, decide what to do with the token */ 495 496 case form_feed: /* found a form feed in line */ 497 ps.use_ff = true; /* a form feed is treated much like a newline */ 498 dump_line(); 499 ps.want_blank = false; 500 break; 501 502 case newline: 503 if (ps.last_token != comma || ps.p_l_follow > 0 504 || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com) { 505 dump_line(); 506 ps.want_blank = false; 507 } 508 ++line_no; /* keep track of input line number */ 509 break; 510 511 case lparen: /* got a '(' or '[' */ 512 ++ps.p_l_follow; /* count parens to make Healy happy */ 513 if (ps.want_blank && *token != '[' && 514 (ps.last_token != ident || proc_calls_space || 515 /* offsetof (1) is never allowed a space; sizeof (2) gets 516 * one iff -bs; all other keywords (>2) always get a space 517 * before lparen */ 518 (ps.keyword + Bill_Shannon > 2))) 519 *e_code++ = ' '; 520 ps.want_blank = false; 521 if (ps.in_decl && !ps.block_init && !ps.dumped_decl_indent && 522 !is_procname) { 523 /* function pointer declarations */ 524 if (troff) { 525 sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token); 526 e_code += strlen(e_code); 527 } 528 else { 529 indent_declaration(dec_ind, tabs_to_var); 530 } 531 ps.dumped_decl_indent = true; 532 } 533 if (!troff) 534 *e_code++ = token[0]; 535 ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code; 536 if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent 537 && ps.paren_indents[0] < 2 * ps.ind_size) 538 ps.paren_indents[0] = 2 * ps.ind_size; 539 if (ps.in_or_st && *token == '(' && ps.tos <= 2) { 540 /* 541 * this is a kluge to make sure that declarations will be 542 * aligned right if proc decl has an explicit type on it, i.e. 543 * "int a(x) {..." 544 */ 545 parse(semicolon); /* I said this was a kluge... */ 546 ps.in_or_st = false; /* turn off flag for structure decl or 547 * initialization */ 548 } 549 /* parenthesized type following sizeof or offsetof is not a cast */ 550 if (ps.keyword == 1 || ps.keyword == 2) 551 ps.not_cast_mask |= 1 << ps.p_l_follow; 552 break; 553 554 case rparen: /* got a ')' or ']' */ 555 rparen_count--; 556 if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.not_cast_mask) { 557 ps.last_u_d = true; 558 ps.cast_mask &= (1 << ps.p_l_follow) - 1; 559 ps.want_blank = space_after_cast; 560 } else 561 ps.want_blank = true; 562 ps.not_cast_mask &= (1 << ps.p_l_follow) - 1; 563 if (--ps.p_l_follow < 0) { 564 ps.p_l_follow = 0; 565 diag3(0, "Extra %c", *token); 566 } 567 if (e_code == s_code) /* if the paren starts the line */ 568 ps.paren_level = ps.p_l_follow; /* then indent it */ 569 570 *e_code++ = token[0]; 571 572 if (sp_sw && (ps.p_l_follow == 0)) { /* check for end of if 573 * (...), or some such */ 574 sp_sw = false; 575 force_nl = true;/* must force newline after if */ 576 ps.last_u_d = true; /* inform lexi that a following 577 * operator is unary */ 578 ps.in_stmt = false; /* dont use stmt continuation 579 * indentation */ 580 581 parse(hd_type); /* let parser worry about if, or whatever */ 582 } 583 ps.search_brace = btype_2; /* this should insure that constructs 584 * such as main(){...} and int[]{...} 585 * have their braces put in the right 586 * place */ 587 break; 588 589 case unary_op: /* this could be any unary operation */ 590 if (!ps.dumped_decl_indent && ps.in_decl && !is_procname && 591 !ps.block_init) { 592 /* pointer declarations */ 593 if (troff) { 594 if (ps.want_blank) 595 *e_code++ = ' '; 596 sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, 597 token); 598 e_code += strlen(e_code); 599 } 600 else { 601 /* if this is a unary op in a declaration, we should 602 * indent this token */ 603 for (i = 0; token[i]; ++i) 604 /* find length of token */; 605 indent_declaration(dec_ind - i, tabs_to_var); 606 } 607 ps.dumped_decl_indent = true; 608 } 609 else if (ps.want_blank) 610 *e_code++ = ' '; 611 { 612 const char *res = token; 613 614 if (troff && token[0] == '-' && token[1] == '>') 615 res = "\\(->"; 616 for (t_ptr = res; *t_ptr; ++t_ptr) { 617 CHECK_SIZE_CODE; 618 *e_code++ = *t_ptr; 619 } 620 } 621 ps.want_blank = false; 622 break; 623 624 case binary_op: /* any binary operation */ 625 if (ps.want_blank) 626 *e_code++ = ' '; 627 { 628 const char *res = token; 629 630 if (troff) 631 switch (token[0]) { 632 case '<': 633 if (token[1] == '=') 634 res = "\\(<="; 635 break; 636 case '>': 637 if (token[1] == '=') 638 res = "\\(>="; 639 break; 640 case '!': 641 if (token[1] == '=') 642 res = "\\(!="; 643 break; 644 case '|': 645 if (token[1] == '|') 646 res = "\\(br\\(br"; 647 else if (token[1] == 0) 648 res = "\\(br"; 649 break; 650 } 651 for (t_ptr = res; *t_ptr; ++t_ptr) { 652 CHECK_SIZE_CODE; 653 *e_code++ = *t_ptr; /* move the operator */ 654 } 655 } 656 ps.want_blank = true; 657 break; 658 659 case postop: /* got a trailing ++ or -- */ 660 *e_code++ = token[0]; 661 *e_code++ = token[1]; 662 ps.want_blank = true; 663 break; 664 665 case question: /* got a ? */ 666 squest++; /* this will be used when a later colon 667 * appears so we can distinguish the 668 * <c>?<n>:<n> construct */ 669 if (ps.want_blank) 670 *e_code++ = ' '; 671 *e_code++ = '?'; 672 ps.want_blank = true; 673 break; 674 675 case casestmt: /* got word 'case' or 'default' */ 676 scase = true; /* so we can process the later colon properly */ 677 goto copy_id; 678 679 case colon: /* got a ':' */ 680 if (squest > 0) { /* it is part of the <c>?<n>: <n> construct */ 681 --squest; 682 if (ps.want_blank) 683 *e_code++ = ' '; 684 *e_code++ = ':'; 685 ps.want_blank = true; 686 break; 687 } 688 if (ps.in_or_st) { 689 *e_code++ = ':'; 690 ps.want_blank = false; 691 break; 692 } 693 ps.in_stmt = false; /* seeing a label does not imply we are in a 694 * stmt */ 695 for (t_ptr = s_code; *t_ptr; ++t_ptr) 696 *e_lab++ = *t_ptr; /* turn everything so far into a label */ 697 e_code = s_code; 698 *e_lab++ = ':'; 699 *e_lab++ = ' '; 700 *e_lab = '\0'; 701 702 force_nl = ps.pcase = scase; /* ps.pcase will be used by 703 * dump_line to decide how to 704 * indent the label. force_nl 705 * will force a case n: to be 706 * on a line by itself */ 707 scase = false; 708 ps.want_blank = false; 709 break; 710 711 case semicolon: /* got a ';' */ 712 if (ps.dec_nest == 0) 713 ps.in_or_st = false;/* we are not in an initialization or 714 * structure declaration */ 715 scase = false; /* these will only need resetting in an error */ 716 squest = 0; 717 if (ps.last_token == rparen && rparen_count == 0) 718 ps.in_parameter_declaration = 0; 719 ps.cast_mask = 0; 720 ps.not_cast_mask = 0; 721 ps.block_init = 0; 722 ps.block_init_level = 0; 723 ps.just_saw_decl--; 724 725 if (ps.in_decl && s_code == e_code && !ps.block_init && 726 !ps.dumped_decl_indent) { 727 /* indent stray semicolons in declarations */ 728 indent_declaration(dec_ind - 1, tabs_to_var); 729 ps.dumped_decl_indent = true; 730 } 731 732 ps.in_decl = (ps.dec_nest > 0); /* if we were in a first level 733 * structure declaration, we 734 * arent any more */ 735 736 if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) { 737 738 /* 739 * This should be true iff there were unbalanced parens in the 740 * stmt. It is a bit complicated, because the semicolon might 741 * be in a for stmt 742 */ 743 diag2(1, "Unbalanced parens"); 744 ps.p_l_follow = 0; 745 if (sp_sw) { /* this is a check for an if, while, etc. with 746 * unbalanced parens */ 747 sp_sw = false; 748 parse(hd_type); /* dont lose the if, or whatever */ 749 } 750 } 751 *e_code++ = ';'; 752 ps.want_blank = true; 753 ps.in_stmt = (ps.p_l_follow > 0); /* we are no longer in the 754 * middle of a stmt */ 755 756 if (!sp_sw) { /* if not if for (;;) */ 757 parse(semicolon); /* let parser know about end of stmt */ 758 force_nl = true;/* force newline after an end of stmt */ 759 } 760 break; 761 762 case lbrace: /* got a '{' */ 763 ps.in_stmt = false; /* dont indent the {} */ 764 if (!ps.block_init) 765 force_nl = true;/* force other stuff on same line as '{' onto 766 * new line */ 767 else if (ps.block_init_level <= 0) 768 ps.block_init_level = 1; 769 else 770 ps.block_init_level++; 771 772 if (s_code != e_code && !ps.block_init) { 773 if (!btype_2) { 774 dump_line(); 775 ps.want_blank = false; 776 } 777 else if (ps.in_parameter_declaration && !ps.in_or_st) { 778 ps.i_l_follow = 0; 779 if (function_brace_split) { /* dump the line prior to the 780 * brace ... */ 781 dump_line(); 782 ps.want_blank = false; 783 } else /* add a space between the decl and brace */ 784 ps.want_blank = true; 785 } 786 } 787 if (ps.in_parameter_declaration) 788 prefix_blankline_requested = 0; 789 790 if (ps.p_l_follow > 0) { /* check for preceding unbalanced 791 * parens */ 792 diag2(1, "Unbalanced parens"); 793 ps.p_l_follow = 0; 794 if (sp_sw) { /* check for unclosed if, for, etc. */ 795 sp_sw = false; 796 parse(hd_type); 797 ps.ind_level = ps.i_l_follow; 798 } 799 } 800 if (s_code == e_code) 801 ps.ind_stmt = false; /* dont put extra indentation on line 802 * with '{' */ 803 if (ps.in_decl && ps.in_or_st) { /* this is either a structure 804 * declaration or an init */ 805 di_stack[ps.dec_nest++] = dec_ind; 806 /* ? dec_ind = 0; */ 807 } 808 else { 809 ps.decl_on_line = false; /* we can't be in the middle of 810 * a declaration, so don't do 811 * special indentation of 812 * comments */ 813 if (blanklines_after_declarations_at_proctop 814 && ps.in_parameter_declaration) 815 postfix_blankline_requested = 1; 816 ps.in_parameter_declaration = 0; 817 } 818 dec_ind = 0; 819 parse(lbrace); /* let parser know about this */ 820 if (ps.want_blank) /* put a blank before '{' if '{' is not at 821 * start of line */ 822 *e_code++ = ' '; 823 ps.want_blank = false; 824 *e_code++ = '{'; 825 ps.just_saw_decl = 0; 826 break; 827 828 case rbrace: /* got a '}' */ 829 if (ps.p_stack[ps.tos] == decl && !ps.block_init) /* semicolons can be 830 * omitted in 831 * declarations */ 832 parse(semicolon); 833 if (ps.p_l_follow) {/* check for unclosed if, for, else. */ 834 diag2(1, "Unbalanced parens"); 835 ps.p_l_follow = 0; 836 sp_sw = false; 837 } 838 ps.just_saw_decl = 0; 839 ps.block_init_level--; 840 if (s_code != e_code && !ps.block_init) { /* '}' must be first on 841 * line */ 842 if (verbose) 843 diag2(0, "Line broken"); 844 dump_line(); 845 } 846 *e_code++ = '}'; 847 ps.want_blank = true; 848 ps.in_stmt = ps.ind_stmt = false; 849 if (ps.dec_nest > 0) { /* we are in multi-level structure 850 * declaration */ 851 dec_ind = di_stack[--ps.dec_nest]; 852 if (ps.dec_nest == 0 && !ps.in_parameter_declaration) 853 ps.just_saw_decl = 2; 854 ps.in_decl = true; 855 } 856 prefix_blankline_requested = 0; 857 parse(rbrace); /* let parser know about this */ 858 ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead 859 && ps.il[ps.tos] >= ps.ind_level; 860 if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0) 861 postfix_blankline_requested = 1; 862 break; 863 864 case swstmt: /* got keyword "switch" */ 865 sp_sw = true; 866 hd_type = swstmt; /* keep this for when we have seen the 867 * expression */ 868 goto copy_id; /* go move the token into buffer */ 869 870 case sp_paren: /* token is if, while, for */ 871 sp_sw = true; /* the interesting stuff is done after the 872 * expression is scanned */ 873 hd_type = (*token == 'i' ? ifstmt : 874 (*token == 'w' ? whilestmt : forstmt)); 875 876 /* 877 * remember the type of header for later use by parser 878 */ 879 goto copy_id; /* copy the token into line */ 880 881 case sp_nparen: /* got else, do */ 882 ps.in_stmt = false; 883 if (*token == 'e') { 884 if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) { 885 if (verbose) 886 diag2(0, "Line broken"); 887 dump_line();/* make sure this starts a line */ 888 ps.want_blank = false; 889 } 890 force_nl = true;/* also, following stuff must go onto new line */ 891 last_else = 1; 892 parse(elselit); 893 } 894 else { 895 if (e_code != s_code) { /* make sure this starts a line */ 896 if (verbose) 897 diag2(0, "Line broken"); 898 dump_line(); 899 ps.want_blank = false; 900 } 901 force_nl = true;/* also, following stuff must go onto new line */ 902 last_else = 0; 903 parse(dolit); 904 } 905 goto copy_id; /* move the token into line */ 906 907 case decl: /* we have a declaration type (int, register, 908 * etc.) */ 909 parse(decl); /* let parser worry about indentation */ 910 if (ps.last_token == rparen && ps.tos <= 1) { 911 ps.in_parameter_declaration = 1; 912 if (s_code != e_code) { 913 dump_line(); 914 ps.want_blank = 0; 915 } 916 } 917 if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) { 918 ps.ind_level = ps.i_l_follow = 1; 919 ps.ind_stmt = 0; 920 } 921 ps.in_or_st = true; /* this might be a structure or initialization 922 * declaration */ 923 ps.in_decl = ps.decl_on_line = true; 924 if ( /* !ps.in_or_st && */ ps.dec_nest <= 0) 925 ps.just_saw_decl = 2; 926 prefix_blankline_requested = 0; 927 for (i = 0; token[i++];); /* get length of token */ 928 929 if (ps.ind_level == 0 || ps.dec_nest > 0) { 930 /* global variable or struct member in local variable */ 931 dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i; 932 tabs_to_var = (use_tabs ? ps.decl_indent > 0 : 0); 933 } else { 934 /* local variable */ 935 dec_ind = ps.local_decl_indent > 0 ? ps.local_decl_indent : i; 936 tabs_to_var = (use_tabs ? ps.local_decl_indent > 0 : 0); 937 } 938 goto copy_id; 939 940 case ident: /* got an identifier or constant */ 941 if (ps.in_decl) { /* if we are in a declaration, we must indent 942 * identifier */ 943 if (is_procname == 0 || !procnames_start_line) { 944 if (!ps.block_init && !ps.dumped_decl_indent) { 945 if (troff) { 946 if (ps.want_blank) 947 *e_code++ = ' '; 948 sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7); 949 e_code += strlen(e_code); 950 } else 951 indent_declaration(dec_ind, tabs_to_var); 952 ps.dumped_decl_indent = true; 953 ps.want_blank = false; 954 } 955 } else { 956 if (ps.want_blank) 957 *e_code++ = ' '; 958 ps.want_blank = false; 959 if (dec_ind && s_code != e_code) { 960 *e_code = '\0'; 961 dump_line(); 962 } 963 dec_ind = 0; 964 } 965 } 966 else if (sp_sw && ps.p_l_follow == 0) { 967 sp_sw = false; 968 force_nl = true; 969 ps.last_u_d = true; 970 ps.in_stmt = false; 971 parse(hd_type); 972 } 973 copy_id: 974 if (ps.want_blank) 975 *e_code++ = ' '; 976 if (troff && ps.keyword) { 977 e_code = chfont(&bodyf, &keywordf, e_code); 978 for (t_ptr = token; *t_ptr; ++t_ptr) { 979 CHECK_SIZE_CODE; 980 *e_code++ = keywordf.allcaps && islower(*t_ptr) 981 ? toupper(*t_ptr) : *t_ptr; 982 } 983 e_code = chfont(&keywordf, &bodyf, e_code); 984 } 985 else 986 for (t_ptr = token; *t_ptr; ++t_ptr) { 987 CHECK_SIZE_CODE; 988 *e_code++ = *t_ptr; 989 } 990 ps.want_blank = true; 991 break; 992 993 case period: /* treat a period kind of like a binary 994 * operation */ 995 *e_code++ = '.'; /* move the period into line */ 996 ps.want_blank = false; /* dont put a blank after a period */ 997 break; 998 999 case comma: 1000 ps.want_blank = (s_code != e_code); /* only put blank after comma 1001 * if comma does not start the 1002 * line */ 1003 if (ps.in_decl && is_procname == 0 && !ps.block_init && 1004 !ps.dumped_decl_indent) { 1005 /* indent leading commas and not the actual identifiers */ 1006 indent_declaration(dec_ind - 1, tabs_to_var); 1007 ps.dumped_decl_indent = true; 1008 } 1009 *e_code++ = ','; 1010 if (ps.p_l_follow == 0) { 1011 if (ps.block_init_level <= 0) 1012 ps.block_init = 0; 1013 if (break_comma && (!ps.leave_comma || compute_code_target() + (e_code - s_code) > max_col - 8)) 1014 force_nl = true; 1015 } 1016 break; 1017 1018 case preesc: /* got the character '#' */ 1019 if ((s_com != e_com) || 1020 (s_lab != e_lab) || 1021 (s_code != e_code)) 1022 dump_line(); 1023 *e_lab++ = '#'; /* move whole line to 'label' buffer */ 1024 { 1025 int in_comment = 0; 1026 int com_start = 0; 1027 char quote = 0; 1028 int com_end = 0; 1029 1030 while (*buf_ptr == ' ' || *buf_ptr == '\t') { 1031 buf_ptr++; 1032 if (buf_ptr >= buf_end) 1033 fill_buffer(); 1034 } 1035 while (*buf_ptr != '\n' || (in_comment && !had_eof)) { 1036 CHECK_SIZE_LAB; 1037 *e_lab = *buf_ptr++; 1038 if (buf_ptr >= buf_end) 1039 fill_buffer(); 1040 switch (*e_lab++) { 1041 case BACKSLASH: 1042 if (troff) 1043 *e_lab++ = BACKSLASH; 1044 if (!in_comment) { 1045 *e_lab++ = *buf_ptr++; 1046 if (buf_ptr >= buf_end) 1047 fill_buffer(); 1048 } 1049 break; 1050 case '/': 1051 if (*buf_ptr == '*' && !in_comment && !quote) { 1052 in_comment = 1; 1053 *e_lab++ = *buf_ptr++; 1054 com_start = e_lab - s_lab - 2; 1055 } 1056 break; 1057 case '"': 1058 if (quote == '"') 1059 quote = 0; 1060 break; 1061 case '\'': 1062 if (quote == '\'') 1063 quote = 0; 1064 break; 1065 case '*': 1066 if (*buf_ptr == '/' && in_comment) { 1067 in_comment = 0; 1068 *e_lab++ = *buf_ptr++; 1069 com_end = e_lab - s_lab; 1070 } 1071 break; 1072 } 1073 } 1074 1075 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) 1076 e_lab--; 1077 if (e_lab - s_lab == com_end && bp_save == NULL) { 1078 /* comment on preprocessor line */ 1079 if (sc_end == NULL) /* if this is the first comment, we 1080 * must set up the buffer */ 1081 sc_end = &(save_com[0]); 1082 else { 1083 *sc_end++ = '\n'; /* add newline between 1084 * comments */ 1085 *sc_end++ = ' '; 1086 --line_no; 1087 } 1088 bcopy(s_lab + com_start, sc_end, com_end - com_start); 1089 sc_end += com_end - com_start; 1090 if (sc_end >= &save_com[sc_size]) 1091 abort(); 1092 e_lab = s_lab + com_start; 1093 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) 1094 e_lab--; 1095 bp_save = buf_ptr; /* save current input buffer */ 1096 be_save = buf_end; 1097 buf_ptr = save_com; /* fix so that subsequent calls to 1098 * lexi will take tokens out of 1099 * save_com */ 1100 *sc_end++ = ' '; /* add trailing blank, just in case */ 1101 buf_end = sc_end; 1102 sc_end = NULL; 1103 } 1104 *e_lab = '\0'; /* null terminate line */ 1105 ps.pcase = false; 1106 } 1107 1108 if (strncmp(s_lab, "#if", 3) == 0) { /* also ifdef, ifndef */ 1109 if ((size_t)ifdef_level < nitems(state_stack)) { 1110 match_state[ifdef_level].tos = -1; 1111 state_stack[ifdef_level++] = ps; 1112 } 1113 else 1114 diag2(1, "#if stack overflow"); 1115 } 1116 else if (strncmp(s_lab, "#el", 3) == 0) { /* else, elif */ 1117 if (ifdef_level <= 0) 1118 diag2(1, s_lab[3] == 'i' ? "Unmatched #elif" : "Unmatched #else"); 1119 else { 1120 match_state[ifdef_level - 1] = ps; 1121 ps = state_stack[ifdef_level - 1]; 1122 } 1123 } 1124 else if (strncmp(s_lab, "#endif", 6) == 0) { 1125 if (ifdef_level <= 0) 1126 diag2(1, "Unmatched #endif"); 1127 else 1128 ifdef_level--; 1129 } else { 1130 struct directives { 1131 int size; 1132 const char *string; 1133 } 1134 recognized[] = { 1135 {7, "include"}, 1136 {6, "define"}, 1137 {5, "undef"}, 1138 {4, "line"}, 1139 {5, "error"}, 1140 {6, "pragma"} 1141 }; 1142 int d = nitems(recognized); 1143 while (--d >= 0) 1144 if (strncmp(s_lab + 1, recognized[d].string, recognized[d].size) == 0) 1145 break; 1146 if (d < 0) { 1147 diag2(1, "Unrecognized cpp directive"); 1148 break; 1149 } 1150 } 1151 if (blanklines_around_conditional_compilation) { 1152 postfix_blankline_requested++; 1153 n_real_blanklines = 0; 1154 } 1155 else { 1156 postfix_blankline_requested = 0; 1157 prefix_blankline_requested = 0; 1158 } 1159 break; /* subsequent processing of the newline 1160 * character will cause the line to be printed */ 1161 1162 case comment: /* we have gotten a / followed by * this is a biggie */ 1163 if (flushed_nl) { /* we should force a broken line here */ 1164 dump_line(); 1165 ps.want_blank = false; /* dont insert blank at line start */ 1166 force_nl = false; 1167 } 1168 pr_comment(); 1169 break; 1170 } /* end of big switch stmt */ 1171 1172 *e_code = '\0'; /* make sure code section is null terminated */ 1173 if (type_code != comment && type_code != newline && type_code != preesc) 1174 ps.last_token = type_code; 1175 } /* end of main while (1) loop */ 1176 } 1177 1178 /* 1179 * copy input file to backup file if in_name is /blah/blah/blah/file, then 1180 * backup file will be ".Bfile" then make the backup file the input and 1181 * original input file the output 1182 */ 1183 static void 1184 bakcopy(void) 1185 { 1186 int n, 1187 bakchn; 1188 char buff[8 * 1024]; 1189 const char *p; 1190 1191 /* construct file name .Bfile */ 1192 for (p = in_name; *p; p++); /* skip to end of string */ 1193 while (p > in_name && *p != '/') /* find last '/' */ 1194 p--; 1195 if (*p == '/') 1196 p++; 1197 sprintf(bakfile, "%s.BAK", p); 1198 1199 /* copy in_name to backup file */ 1200 bakchn = creat(bakfile, 0600); 1201 if (bakchn < 0) 1202 err(1, "%s", bakfile); 1203 while ((n = read(fileno(input), buff, sizeof(buff))) > 0) 1204 if (write(bakchn, buff, n) != n) 1205 err(1, "%s", bakfile); 1206 if (n < 0) 1207 err(1, "%s", in_name); 1208 close(bakchn); 1209 fclose(input); 1210 1211 /* re-open backup file as the input file */ 1212 input = fopen(bakfile, "r"); 1213 if (input == NULL) 1214 err(1, "%s", bakfile); 1215 /* now the original input file will be the output */ 1216 output = fopen(in_name, "w"); 1217 if (output == NULL) { 1218 unlink(bakfile); 1219 err(1, "%s", in_name); 1220 } 1221 } 1222 1223 static void 1224 indent_declaration(int cur_dec_ind, int tabs_to_var) 1225 { 1226 int pos = e_code - s_code; 1227 char *startpos = e_code; 1228 1229 /* 1230 * get the tab math right for indentations that are not multiples of 8 1231 */ 1232 if ((ps.ind_level * ps.ind_size) % 8 != 0) { 1233 pos += (ps.ind_level * ps.ind_size) % 8; 1234 cur_dec_ind += (ps.ind_level * ps.ind_size) % 8; 1235 } 1236 if (tabs_to_var) 1237 while ((pos & ~7) + 8 <= cur_dec_ind) { 1238 CHECK_SIZE_CODE; 1239 *e_code++ = '\t'; 1240 pos = (pos & ~7) + 8; 1241 } 1242 while (pos < cur_dec_ind) { 1243 CHECK_SIZE_CODE; 1244 *e_code++ = ' '; 1245 pos++; 1246 } 1247 if (e_code == startpos && ps.want_blank) { 1248 *e_code++ = ' '; 1249 ps.want_blank = false; 1250 } 1251 } 1252