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