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