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