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