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