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