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