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