1 /* $NetBSD: io.c,v 1.14 2009/04/12 11:09:49 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 #if 0 69 static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 6/6/93"; 70 #else 71 __RCSID("$NetBSD: io.c,v 1.14 2009/04/12 11:09:49 lukem Exp $"); 72 #endif 73 #endif /* not lint */ 74 75 #include <ctype.h> 76 #include <err.h> 77 #include <stdarg.h> 78 #include <stdio.h> 79 #include <stdlib.h> 80 #include <string.h> 81 #include "indent_globs.h" 82 83 int comment_open; 84 static int paren_target; 85 86 void 87 dump_line(void) 88 { /* dump_line is the routine that actually 89 * effects the printing of the new source. It 90 * prints the label section, followed by the 91 * code section with the appropriate nesting 92 * level, followed by any comments */ 93 int cur_col, target_col; 94 static int not_first_line; 95 96 target_col = 0; 97 if (ps.procname[0]) { 98 if (troff) { 99 if (comment_open) { 100 comment_open = 0; 101 fprintf(output, ".*/\n"); 102 } 103 fprintf(output, ".Pr \"%s\"\n", ps.procname); 104 } 105 ps.ind_level = 0; 106 ps.procname[0] = 0; 107 } 108 if (s_code == e_code && s_lab == e_lab && s_com == e_com) { 109 if (suppress_blanklines > 0) 110 suppress_blanklines--; 111 else { 112 ps.bl_line = true; 113 n_real_blanklines++; 114 } 115 } else 116 if (!inhibit_formatting) { 117 suppress_blanklines = 0; 118 ps.bl_line = false; 119 if (prefix_blankline_requested && not_first_line) { 120 if (swallow_optional_blanklines) { 121 if (n_real_blanklines == 1) 122 n_real_blanklines = 0; 123 } else { 124 if (n_real_blanklines == 0) 125 n_real_blanklines = 1; 126 } 127 } 128 while (--n_real_blanklines >= 0) 129 putc('\n', output); 130 n_real_blanklines = 0; 131 if (ps.ind_level == 0) 132 ps.ind_stmt = 0; /* this is a class A 133 * kludge. dont do 134 * additional statement 135 * indentation if we are 136 * at bracket level 0 */ 137 138 if (e_lab != s_lab || e_code != s_code) 139 ++code_lines; /* keep count of lines with 140 * code */ 141 142 143 if (e_lab != s_lab) { /* print lab, if any */ 144 if (comment_open) { 145 comment_open = 0; 146 fprintf(output, ".*/\n"); 147 } 148 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) 149 e_lab--; 150 cur_col = pad_output(1, compute_label_target()); 151 if (s_lab[0] == '#' && (strncmp(s_lab, "#else", 5) == 0 152 || strncmp(s_lab, "#endif", 6) == 0)) { 153 char *s = s_lab; 154 if (e_lab[-1] == '\n') 155 e_lab--; 156 do 157 putc(*s++, output); 158 while (s < e_lab && 'a' <= *s && *s <= 'z'); 159 while ((*s == ' ' || *s == '\t') && s < e_lab) 160 s++; 161 if (s < e_lab) 162 fprintf(output, s[0] == '/' && s[1] == '*' ? "\t%.*s" : "\t/* %.*s */", 163 (int)(e_lab - s), s); 164 } else 165 fprintf(output, "%.*s", (int)(e_lab - s_lab), s_lab); 166 cur_col = count_spaces(cur_col, s_lab); 167 } else 168 cur_col = 1; /* there is no label section */ 169 170 ps.pcase = false; 171 172 if (s_code != e_code) { /* print code section, if any */ 173 char *p; 174 175 if (comment_open) { 176 comment_open = 0; 177 fprintf(output, ".*/\n"); 178 } 179 target_col = compute_code_target(); 180 { 181 int i; 182 183 for (i = 0; i < ps.p_l_follow; i++) 184 if (ps.paren_indents[i] >= 0) 185 ps.paren_indents[i] = -(ps.paren_indents[i] + target_col); 186 } 187 cur_col = pad_output(cur_col, target_col); 188 for (p = s_code; p < e_code; p++) 189 if (*p == (char) 0200) 190 fprintf(output, "%d", target_col * 7); 191 else 192 putc(*p, output); 193 cur_col = count_spaces(cur_col, s_code); 194 } 195 if (s_com != e_com) { 196 if (troff) { 197 int all_here = 0; 198 char *p; 199 200 if (e_com[-1] == '/' && e_com[-2] == '*') 201 e_com -= 2, all_here++; 202 while (e_com > s_com && e_com[-1] == ' ') 203 e_com--; 204 *e_com = 0; 205 p = s_com; 206 while (*p == ' ') 207 p++; 208 if (p[0] == '/' && p[1] == '*') 209 p += 2, all_here++; 210 else 211 if (p[0] == '*') 212 p += p[1] == '/' ? 2 : 1; 213 while (*p == ' ') 214 p++; 215 if (*p == 0) 216 goto inhibit_newline; 217 if (comment_open < 2 && ps.box_com) { 218 comment_open = 0; 219 fprintf(output, ".*/\n"); 220 } 221 if (comment_open == 0) { 222 if ('a' <= *p && *p <= 'z') 223 *p = *p + 'A' - 'a'; 224 if (e_com - p < 50 && all_here == 2) { 225 char *follow = p; 226 fprintf(output, "\n.nr C! \\w\1"); 227 while (follow < e_com) { 228 switch (*follow) { 229 case '\n': 230 putc(' ', output); 231 case 1: 232 break; 233 case '\\': 234 putc('\\', output); 235 default: 236 putc(*follow, output); 237 } 238 follow++; 239 } 240 putc(1, output); 241 } 242 fprintf(output, "\n./* %dp %d %dp\n", 243 ps.com_col * 7, 244 (s_code != e_code || s_lab != e_lab) - ps.box_com, 245 target_col * 7); 246 } 247 comment_open = 1 + ps.box_com; 248 while (*p) { 249 if (*p == BACKSLASH) 250 putc(BACKSLASH, output); 251 putc(*p++, output); 252 } 253 } else { /* print comment, if any */ 254 int target = ps.com_col; 255 char *com_st = s_com; 256 257 target += ps.comment_delta; 258 while (*com_st == '\t') 259 com_st++, target += 8; /* ? */ 260 while (target <= 0) 261 if (*com_st == ' ') 262 target++, com_st++; 263 else 264 if (*com_st == '\t') 265 target = ((target - 1) & ~7) + 9, com_st++; 266 else 267 target = 1; 268 if (cur_col > target) { /* if comment cant fit 269 * on this line, put it 270 * on next line */ 271 putc('\n', output); 272 cur_col = 1; 273 ++ps.out_lines; 274 } 275 while (e_com > com_st 276 && isspace((unsigned char)e_com[-1])) 277 e_com--; 278 cur_col = pad_output(cur_col, target); 279 if (!ps.box_com) { 280 if (star_comment_cont 281 && (com_st[1] != '*' 282 || e_com <= com_st + 1)) { 283 if (com_st[1] == ' ' 284 && com_st[0] == ' ' 285 && e_com > com_st + 1) 286 com_st[1] = '*'; 287 else 288 fwrite(" * ", 289 com_st[0] == '\t' 290 ? 2 291 : com_st[0]=='*' 292 ? 1 293 : 3, 1, output); 294 } 295 } 296 fwrite(com_st, 297 e_com - com_st, 1, output); 298 ps.comment_delta = ps.n_comment_delta; 299 cur_col = count_spaces(cur_col, com_st); 300 ++ps.com_lines; /* count lines with 301 * comments */ 302 } 303 } 304 if (ps.use_ff) 305 putc('\014', output); 306 else 307 putc('\n', output); 308 inhibit_newline: 309 ++ps.out_lines; 310 if (ps.just_saw_decl == 1 && blanklines_after_declarations) { 311 prefix_blankline_requested = 1; 312 ps.just_saw_decl = 0; 313 } else 314 prefix_blankline_requested = postfix_blankline_requested; 315 postfix_blankline_requested = 0; 316 } 317 ps.decl_on_line = ps.in_decl; /* if we are in the middle of a 318 * declaration, remember that fact for 319 * proper comment indentation */ 320 ps.ind_stmt = ps.in_stmt & ~ps.in_decl; /* next line should be 321 * indented if we have not 322 * completed this stmt and if 323 * we are not in the middle of 324 * a declaration */ 325 ps.use_ff = false; 326 ps.dumped_decl_indent = 0; 327 *(e_lab = s_lab) = '\0';/* reset buffers */ 328 *(e_code = s_code) = '\0'; 329 *(e_com = s_com) = '\0'; 330 ps.ind_level = ps.i_l_follow; 331 ps.paren_level = ps.p_l_follow; 332 paren_target = -ps.paren_indents[ps.paren_level - 1]; 333 not_first_line = 1; 334 } 335 336 int 337 compute_code_target(void) 338 { 339 int target_col = ps.ind_size * ps.ind_level + 1; 340 341 if (ps.paren_level) { 342 if (!lineup_to_parens) 343 target_col += continuation_indent * ps.paren_level; 344 else { 345 int w; 346 int t = paren_target; 347 348 if ((w = count_spaces(t, s_code) - max_col) > 0 349 && count_spaces(target_col, s_code) <= max_col) { 350 t -= w + 1; 351 if (t > target_col) 352 target_col = t; 353 } else 354 target_col = t; 355 } 356 } else 357 if (ps.ind_stmt) 358 target_col += continuation_indent; 359 return target_col; 360 } 361 362 int 363 compute_label_target(void) 364 { 365 return 366 ps.pcase ? (int) (case_ind * ps.ind_size) + 1 367 : *s_lab == '#' ? 1 368 : ps.ind_size * (ps.ind_level - label_offset) + 1; 369 } 370 371 372 /* 373 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois 374 * 375 * All rights reserved 376 * 377 * 378 * NAME: fill_buffer 379 * 380 * FUNCTION: Reads one block of input into input_buffer 381 * 382 * HISTORY: initial coding November 1976 D A Willcox of CAC 1/7/77 A 383 * Willcox of CAC Added check for switch back to partly full input 384 * buffer from temporary buffer 385 * 386 */ 387 void 388 fill_buffer(void) 389 { /* this routine reads stuff from the input */ 390 char *p; 391 int i; 392 FILE *f = input; 393 char *n; 394 395 if (bp_save != 0) { /* there is a partly filled input buffer left */ 396 buf_ptr = bp_save; /* dont read anything, just switch 397 * buffers */ 398 buf_end = be_save; 399 bp_save = be_save = 0; 400 if (buf_ptr < buf_end) 401 return; /* only return if there is really something in 402 * this buffer */ 403 } 404 for (p = in_buffer;;) { 405 if (p >= in_buffer_limit) { 406 int size = (in_buffer_limit - in_buffer) * 2 + 10; 407 int offset = p - in_buffer; 408 n = (char *) realloc(in_buffer, size); 409 if (n == 0) 410 errx(1, "input line too long"); 411 in_buffer = n; 412 p = in_buffer + offset; 413 in_buffer_limit = in_buffer + size - 2; 414 } 415 if ((i = getc(f)) == EOF) { 416 *p++ = ' '; 417 *p++ = '\n'; 418 had_eof = true; 419 break; 420 } 421 *p++ = i; 422 if (i == '\n') 423 break; 424 } 425 buf_ptr = in_buffer; 426 buf_end = p; 427 if (p[-2] == '/' && p[-3] == '*') { 428 if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0) 429 fill_buffer(); /* flush indent error message */ 430 else { 431 int com = 0; 432 433 p = in_buffer; 434 while (*p == ' ' || *p == '\t') 435 p++; 436 if (*p == '/' && p[1] == '*') { 437 p += 2; 438 while (*p == ' ' || *p == '\t') 439 p++; 440 if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E' 441 && p[4] == 'N' && p[5] == 'T') { 442 p += 6; 443 while (*p == ' ' || *p == '\t') 444 p++; 445 if (*p == '*') 446 com = 1; 447 else { 448 if (*p == 'O') { 449 if (*++p == 'N') 450 p++, com = 1; 451 else 452 if (*p == 'F' && *++p == 'F') 453 p++, com = 2; 454 } 455 } 456 while (*p == ' ' || *p == '\t') 457 p++; 458 if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) { 459 if (s_com != e_com || s_lab != e_lab || s_code != e_code) 460 dump_line(); 461 if (!(inhibit_formatting = com - 1)) { 462 n_real_blanklines = 0; 463 postfix_blankline_requested = 0; 464 prefix_blankline_requested = 0; 465 suppress_blanklines = 1; 466 } 467 } 468 } 469 } 470 } 471 } 472 if (inhibit_formatting) { 473 p = in_buffer; 474 do 475 putc(*p, output); 476 while (*p++ != '\n'); 477 } 478 } 479 /* 480 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois 481 * 482 * All rights reserved 483 * 484 * 485 * NAME: pad_output 486 * 487 * FUNCTION: Writes tabs and spaces to move the current column up to the desired 488 * position. 489 * 490 * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf. 491 * 492 * PARAMETERS: current integer The current column target 493 * target integer The desired column 494 * 495 * RETURNS: Integer value of the new column. (If current >= target, no action is 496 * taken, and current is returned. 497 * 498 * GLOBALS: None 499 * 500 * CALLS: write (sys) 501 * 502 * CALLED BY: dump_line 503 * 504 * HISTORY: initial coding November 1976 D A Willcox of CAC 505 * 506 */ 507 int 508 pad_output(int current, int target) 509 { 510 int curr; /* internal column pointer */ 511 int tcur; 512 513 if (troff) 514 fprintf(output, "\\h'|%dp'", (target - 1) * 7); 515 else { 516 if (current >= target) 517 return (current); /* line is already long enough */ 518 curr = current; 519 while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) { 520 putc('\t', output); 521 curr = tcur; 522 } 523 while (curr++ < target) 524 putc(' ', output); /* pad with final blanks */ 525 } 526 return (target); 527 } 528 /* 529 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois 530 * 531 * All rights reserved 532 * 533 * 534 * NAME: count_spaces 535 * 536 * FUNCTION: Find out where printing of a given string will leave the current 537 * character position on output. 538 * 539 * ALGORITHM: Run thru input string and add appropriate values to current 540 * position. 541 * 542 * RETURNS: Integer value of position after printing "buffer" starting in column 543 * "current". 544 * 545 * HISTORY: initial coding November 1976 D A Willcox of CAC 546 * 547 */ 548 int 549 count_spaces(int current, char *buffer) 550 /* 551 * this routine figures out where the character position will be after 552 * printing the text in buffer starting at column "current" 553 */ 554 { 555 char *buf; /* used to look thru buffer */ 556 int cur; /* current character counter */ 557 558 cur = current; 559 560 for (buf = buffer; *buf != '\0'; ++buf) { 561 switch (*buf) { 562 563 case '\n': 564 case 014: /* form feed */ 565 cur = 1; 566 break; 567 568 case '\t': 569 cur = ((cur - 1) & tabmask) + tabsize + 1; 570 break; 571 572 case 010: /* backspace */ 573 --cur; 574 break; 575 576 default: 577 ++cur; 578 break; 579 } /* end of switch */ 580 } /* end of for loop */ 581 return (cur); 582 } 583 584 585 int found_err; 586 587 void 588 diag(int level, const char *msg, ...) 589 { 590 va_list ap; 591 592 va_start(ap, msg); 593 594 if (level) 595 found_err = 1; 596 if (output == stdout) { 597 fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no); 598 vfprintf(stdout, msg, ap); 599 fprintf(stdout, " */\n"); 600 } else { 601 fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no); 602 vfprintf(stdout, msg, ap); 603 fprintf(stderr, "\n"); 604 } 605 va_end(ap); 606 } 607 608 void 609 writefdef(struct fstate *f, int nm) 610 { 611 fprintf(output, ".ds f%c %s\n.nr s%c %d\n", 612 nm, f->font, nm, f->size); 613 } 614 615 char * 616 chfont(struct fstate *of, struct fstate *nf, char *s) 617 { 618 if (of->font[0] != nf->font[0] 619 || of->font[1] != nf->font[1]) { 620 *s++ = '\\'; 621 *s++ = 'f'; 622 if (nf->font[1]) { 623 *s++ = '('; 624 *s++ = nf->font[0]; 625 *s++ = nf->font[1]; 626 } else 627 *s++ = nf->font[0]; 628 } 629 if (nf->size != of->size) { 630 *s++ = '\\'; 631 *s++ = 's'; 632 if (nf->size < of->size) { 633 *s++ = '-'; 634 *s++ = '0' + of->size - nf->size; 635 } else { 636 *s++ = '+'; 637 *s++ = '0' + nf->size - of->size; 638 } 639 } 640 return s; 641 } 642 643 644 void 645 parsefont(struct fstate *f, const char *s0) 646 { 647 const char *s = s0; 648 int sizedelta = 0; 649 memset(f, 0, sizeof *f); 650 while (*s) { 651 if (isdigit((unsigned char)*s)) 652 f->size = f->size * 10 + *s - '0'; 653 else 654 if (isupper((unsigned char)*s)) { 655 if (f->font[0]) 656 f->font[1] = *s; 657 else 658 f->font[0] = *s; 659 } else 660 if (*s == 'c') 661 f->allcaps = 1; 662 else 663 if (*s == '+') 664 sizedelta++; 665 else 666 if (*s == '-') 667 sizedelta--; 668 else { 669 fprintf(stderr, "indent: bad font specification: %s\n", s0); 670 exit(1); 671 } 672 s++; 673 } 674 if (f->font[0] == 0) 675 f->font[0] = 'R'; 676 if (bodyf.size == 0) 677 bodyf.size = 11; 678 if (f->size == 0) 679 f->size = bodyf.size + sizedelta; 680 else 681 if (sizedelta > 0) 682 f->size += bodyf.size; 683 else 684 f->size = bodyf.size - f->size; 685 } 686