1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 static char sccsid[] = "%Z%%M% %I% %E% SMI"; 30 31 /* 32 * lwlp - Convert ASCII text to PostScript 33 * 34 * Usage: 35 * lwlp [-{2|4|8}] [-p] [-L] [-r] [-n#] [-l#|-w#] [-c#] [-t#] 36 * [-hstring] [-Bstring] [-Istring] [-Xstring] [-Pfile] [file ...] 37 * 38 * Options: 39 * -{1|2|4|8} print multiple logical pages per page 40 * -d debug, don't remove temporary file 41 * -L specify Landscape instead of Portrait 42 * -p filter input through pr 43 * -r toggle page reversal flag (default is off) 44 * -e elide unchanged functions 45 * -n# number with numberwidth digits 46 * -l# specify number of lines/logical page, default 66 47 * -w# specify number of columns 48 * -c# specify number of copies 49 * -t# specify tab spacing 50 * -htext specify header text 51 * -Btext specify bold font selector 52 * -Itext specify italic font selector 53 * -Xtext specify bold-italic font selector 54 * -Gtext specify graying selector 55 * -Pfile specify different Postscript prologue file 56 * 57 * If no files are specified, stdin is used. 58 * Form feeds handled 59 * Backspacing with underlining (or overprinting) works 60 * The output conforms to Adobe 2.0 61 * 62 * Problems: 63 * - assumes fixed-width (non-proportional) font in some places 64 * - can't back up (using backspaces) over tabs 65 * - assumes 8.5 x 11.0 paper 66 * - uses logical page with aspect ratio of 3 * 4 67 * 68 */ 69 70 #define USAGE1 "[-{1|2|4|8}] [-p] [-L] [-r] [-n<numberwidth]" 71 #define USAGE2 "[-l<lines>|-w<columns>] [-c<count>] [-t<tabs>]" 72 #define USAGE3 "[-hstring] [-Bstring] [-Istring] [-Xstring] [-Gstring]" 73 #define USAGE4 "[-Pfile] [file ...]" 74 #define USAGE6 "[-hstring] [-e] oldfile newfile" 75 76 #include <stdio.h> 77 #include <string.h> 78 #include <stdlib.h> 79 #include <sys/file.h> 80 #include <ctype.h> 81 #include <pwd.h> 82 #include <sys/utsname.h> 83 #include <sys/stat.h> 84 #include <unistd.h> 85 #include <sys/types.h> 86 #include <time.h> 87 #include <stdarg.h> 88 89 /* 90 * Configurable... 91 * BUFOUT should be fairly large 92 */ 93 #define BUFIN 1024 /* maximum length of an input line */ 94 #define BUFOUT (BUFIN * 5) 95 #define MAXPAGES 10000 96 #define REVERSE_OFF 0 97 98 #define DEFAULT_PAPER_HEIGHT 11.0 99 #define DEFAULT_PAPER_WIDTH 8.50 100 #define DEFAULT_PAGE_HEIGHT 10.0 101 #define DEFAULT_PAGE_WIDTH 7.50 102 #define DEFAULT_LINES_PER_PAGE 66 103 #define DEFAULT_TAB_SIZE 8 104 static char *default_font = "Courier"; 105 static char *default_font_bold = "Courier-Bold"; 106 static char *default_font_italic = "Courier-Oblique"; 107 static char *default_font_bold_italic = "Courier-BoldOblique"; 108 static char *select_default_font = "FRN"; 109 static char *select_default_font_bold = "FRB"; 110 static char *select_default_font_italic = "FIN"; 111 static char *select_default_font_bold_italic = "FIB"; 112 #define DEFAULT_FONT select_default_font 113 #define DEFAULT_FONT_BOLD select_default_font_bold 114 #define DEFAULT_FONT_ITALIC select_default_font_italic 115 #define DEFAULT_FONT_BOLD_ITALIC select_default_font_bold_italic 116 #define DEFAULT_CHAR_WIDTH (.6) 117 #define DEFAULT_SPACES_AFTER_NUMBER 1 118 #define DEFAULT_DESCENDER_FRACTION 0.3 119 #define LWLP "lwlp" 120 #define CODEREVIEW "codereview" 121 #define END_C_FUNCTION '}' 122 #define END_ASM_FUNCTION "SET_SIZE(" 123 static char *banner = 124 "**********************************************************"; 125 126 /* 127 * PostScript command strings 128 */ 129 #define LINETO "lineto" 130 #define NEWPATH "newpath" 131 #define SETLINEWIDTH "setlinewidth" 132 #define STROKE "stroke" 133 /* 134 * PostScript command strings defined in the prologue file 135 */ 136 #define BACKSPACE "B" 137 #define MOVETO "M" /* x y */ 138 #define SHOW "S" /* string */ 139 #define TAB "T" /* spaces */ 140 #define ZEROMOVETO "Z" /* y */ 141 #define SELECT_FONT "SFT" /* size font */ 142 #define SET_WIDTHS "SWT" 143 #define START_PAGE "SPG" /* angle scale x y */ 144 #define END_PAGE "EPG" 145 #define FLUSH_PAGE "FPG" /* ncopies */ 146 #define SHADE "SHD" /* x0 y0 x1 y1 */ 147 148 /* 149 * Conformance requires that no PostScript line exceed 256 characters 150 */ 151 #define POINTS_PER_INCH 72 152 #define MAX_OUTPUT_LINE_LENGTH 256 153 154 #define START_X 0 /* position of start of each line */ 155 #define THREE_HOLE_X 1.0 /* portrait x offset (inches) 3 hole */ 156 #define THREE_HOLE_Y 0.5 /* landscape y offset (inches) 3 hole */ 157 #define RULE_WIDTH 0.25 /* width in units of paging rules */ 158 159 static struct print_state { 160 int page_count; 161 int logical_page_count; 162 int lineno; 163 long offset; 164 float row; 165 char *font; 166 } current, saved; 167 168 struct format_state { 169 int numberwidth, linenumber, altlinenumber; 170 int makegray; 171 char *font; 172 }; 173 174 static int change_seen, dots_inserted, in_change, old_stuff, makegray; 175 static int lines_per_page; 176 static int columns; 177 static float point_size; 178 static int start_x, start_y, end_x; 179 static int landscape, rot_text; 180 181 static int ncopies; 182 static int tabstop; 183 static int reverse; 184 static int elide; 185 static int usetmp; 186 static int dflag, lflag, pflag, vflag, wflag; 187 static int numberwidth, linenumber, altlinenumber; 188 static int boldlength, itlclength, bitclength, graylength; 189 static char *boldstring, *itlcstring, *bitcstring, *graystring; 190 #define HEADER_EXPLICIT 1 191 #define HEADER_IMPLICIT 2 192 static int header = HEADER_IMPLICIT; 193 static char *headerstring; 194 static char *bannerfile; 195 196 static char bufin[BUFIN]; /* input buffer */ 197 static char bufout[BUFOUT]; /* output buffer */ 198 static long *page_map; /* offset of first byte of each page */ 199 200 static char *username, *hostname, *currentdate; 201 202 static void preamble(void); 203 static void postamble(void); 204 static void setcurrentfont(char *, FILE *); 205 static void savestate(FILE *); 206 static void restorestate(FILE *); 207 static void save_format_state(struct format_state *); 208 static void printfile(FILE *); 209 static int printpage(FILE *, FILE *); 210 static int startpage(FILE *); 211 static void endpage(FILE *); 212 static void copypage(FILE *, long, long); 213 static void process_elide(FILE *); 214 static void setheaderfile(char *); 215 static void restore_format_state(struct format_state *, FILE *); 216 static void flushpage(FILE *); 217 static void setuppage(FILE *); 218 static void reversepages(FILE *); 219 static void proc(char *, FILE *); 220 static void setup(void); 221 static int printbanner(char *, FILE *); 222 static char *fgetline(char *, int, FILE *); 223 static void fatal(char *fmt, ...); 224 225 static char *prologue; 226 static char *progname; 227 static int iscodereview; 228 229 static char *default_prologue[] = { 230 "%%EndComments\n", 231 "%\n", 232 "% PostScript Prologue for lwlp LaserWriter Line Printer\n", 233 "%\n", 234 "/SFT {findfont exch scalefont setfont}bind def\n", 235 "/SWT {( ) stringwidth pop dup /W exch def neg /NW exch def}bind def\n", 236 "/SPG {/SV save def translate dup scale rotate}bind def\n", 237 "/EPG {SV restore}bind def\n", 238 "/FPG {/#copies exch def showpage}bind def\n", 239 "/B {NW 0 rmoveto}def\n", 240 "/M /moveto load def\n", 241 "/T {W mul 0 rmoveto}def\n", 242 "/S /show load def\n", 243 "/Z {0 exch moveto}bind def\n", 244 "/SHD {save 5 1 roll % S x1 y1 x0 y0\n", 245 " 2 copy moveto % S x1 y1 x0 y0\n", 246 " 3 index exch lineto % S x1 y1 x0\n", 247 " 3 -1 roll 2 index lineto % S y1 x0\n", 248 " exch lineto % S\n", 249 " 0.95 setgray fill % S\n", 250 " restore}def\n", 251 "%%EndProlog\n", 252 NULL 253 }; 254 255 struct layout { 256 float scale; 257 int pages, page_rows, page_cols; 258 int rotation; 259 }; 260 static struct layout *layoutp; 261 static struct layout layout1 = { 1.000000, 1, 1, 1, 0 }; 262 static struct layout layout2 = { 0.666666, 2, 2, 1, 90 }; 263 static struct layout layout4 = { 0.500000, 4, 2, 2, 0 }; 264 static struct layout layout8 = { 0.333333, 8, 4, 2, 90 }; 265 266 static int box_width, box_height; 267 static int gap_width, gap_height; 268 static int margin_x, margin_y; 269 270 static struct position { 271 int base_x; 272 int base_y; 273 } positions[8]; 274 275 int 276 main(int argc, char **argv) 277 { 278 int ch, i, j, first_file; 279 char *pc; 280 FILE *infile; 281 282 if ((pc = strrchr(argv[0], '/')) != NULL) 283 progname = pc + 1; 284 else 285 progname = argv[0]; 286 287 lines_per_page = DEFAULT_LINES_PER_PAGE; 288 layoutp = &layout1; 289 tabstop = DEFAULT_TAB_SIZE; 290 current.page_count = 0; 291 ncopies = 1; 292 reverse = REVERSE_OFF; 293 294 /*LINTED*/ 295 if (iscodereview = strncmp(progname, CODEREVIEW, 296 sizeof (CODEREVIEW) - 1) == 0) { 297 layoutp = &layout2; 298 numberwidth = 4; 299 columns = 85; /* extra space for numbering */ 300 wflag = -1; 301 } 302 303 while ((ch = getopt(argc, argv, 304 "1248B:c:deG:h:I:l:Ln:P:prt:vw:X:")) != -1) { 305 switch (ch) { 306 case '1': 307 layoutp = &layout1; 308 break; 309 case '2': 310 layoutp = &layout2; 311 break; 312 case '4': 313 layoutp = &layout4; 314 break; 315 case '8': 316 layoutp = &layout8; 317 break; 318 case 'B': 319 boldlength = strlen(optarg); 320 boldstring = malloc((size_t)(boldlength + 1)); 321 (void) strcpy(boldstring, optarg); 322 break; 323 case 'c': 324 ncopies = atof(optarg); 325 if (ncopies <= 0) { 326 fatal("number of copies must be > 0"); 327 /*NOTREACHED*/ 328 } 329 break; 330 case 'd': 331 dflag = 1; 332 break; 333 case 'e': 334 elide = 1; 335 break; 336 case 'G': 337 graylength = strlen(optarg); 338 graystring = malloc((size_t)(graylength + 1)); 339 (void) strcpy(graystring, optarg); 340 break; 341 case 'h': 342 header = HEADER_EXPLICIT; 343 i = strlen(optarg); 344 headerstring = malloc((size_t)(i + 1)); 345 (void) strcpy(headerstring, optarg); 346 if (strcmp(headerstring, "-") == 0) 347 header = HEADER_IMPLICIT; 348 break; 349 case 'I': 350 itlclength = strlen(optarg); 351 itlcstring = malloc((size_t)(itlclength + 1)); 352 (void) strcpy(itlcstring, optarg); 353 break; 354 case 'l': 355 lines_per_page = atoi(optarg); 356 if (lines_per_page < 1) { 357 fatal("invalid number of lines/page"); 358 /*NOTREACHED*/ 359 } 360 lflag = 1; 361 if (wflag > 0) { 362 fatal("can't have both -l and -w"); 363 /*NOTREACHED*/ 364 } 365 wflag = 0; 366 break; 367 case 'L': 368 landscape = 1; 369 break; 370 case 'm': 371 break; 372 case 'n': 373 numberwidth = atoi(optarg); 374 if (numberwidth < 2) { 375 fatal("invalid numbering width"); 376 /*NOTREACHED*/ 377 } 378 break; 379 case 'P': 380 prologue = optarg; 381 break; 382 case 'p': 383 pflag = 1; 384 break; 385 case 'r': 386 reverse = !reverse; 387 break; 388 case 't': 389 tabstop = atoi(optarg); 390 if (tabstop < 1) { 391 fatal("negative tabstop"); 392 /*NOTREACHED*/ 393 } 394 break; 395 case 'v': 396 vflag = 1; 397 break; 398 case 'w': 399 columns = atoi(optarg); 400 if (columns < 1) { 401 fatal("invalid number of columns"); 402 /*NOTREACHED*/ 403 } 404 wflag = 1; 405 if (lflag) { 406 fatal("can't have both -l and -w"); 407 /*NOTREACHED*/ 408 } 409 break; 410 case 'X': 411 bitclength = strlen(optarg); 412 bitcstring = malloc((size_t)(bitclength + 1)); 413 (void) strcpy(bitcstring, optarg); 414 break; 415 default: 416 (void) fprintf(stderr, 417 "usage: %s %s\n\t%s\n\t%s\n\t%s\n", 418 iscodereview ? LWLP : progname, 419 USAGE1, USAGE2, USAGE3, USAGE4); 420 if (iscodereview) 421 (void) fprintf(stderr, "\t%s [%s flags] %s\n", 422 CODEREVIEW, LWLP, USAGE6); 423 exit(1); 424 } 425 } 426 427 if (elide && !iscodereview) { 428 fatal("-e option valid only with codereview"); 429 /*NOTREACHED*/ 430 } 431 usetmp = reverse || elide; 432 /* allocate page_map if we need one */ 433 if (reverse) { 434 page_map = malloc((size_t)(MAXPAGES * sizeof (long *))); 435 if (page_map == NULL) { 436 fatal("unable to allocate memory for page reversal"); 437 /*NOTREACHED*/ 438 } 439 } 440 441 /* 442 * Check that all files are readable 443 * This is so that no output at all is produced if any file is not 444 * readable in case the output is being piped to a printer 445 */ 446 first_file = optind; 447 for (j = first_file; j < argc; j++) { 448 if (access(argv[j], R_OK) == -1 && !(iscodereview && 449 strcmp(argv[j], "-") == 0)) { 450 fatal("cannot access %s", argv[j]); 451 /*NOTREACHED*/ 452 } 453 } 454 if (iscodereview && (first_file + 2) != argc) { 455 fatal("codereview: need old and new file"); 456 /*NOTREACHED*/ 457 } 458 459 /* compute logical point size, logical dimensions */ 460 if (!landscape) { 461 rot_text = layoutp->rotation; 462 start_y = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH; 463 start_x = START_X; 464 end_x = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH; 465 if (wflag) { 466 point_size = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH / 467 ((columns + 0.5) * DEFAULT_CHAR_WIDTH); 468 lines_per_page = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / 469 point_size; 470 } else { 471 point_size = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / 472 (lines_per_page + 0.5); 473 columns = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH / 474 (point_size * DEFAULT_CHAR_WIDTH); 475 } 476 } else { 477 rot_text = 90 - layoutp->rotation; 478 start_y = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH; 479 start_x = START_X; 480 end_x = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH; 481 if (wflag) { 482 point_size = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / 483 ((columns + 0.5) * DEFAULT_CHAR_WIDTH); 484 lines_per_page = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH / 485 point_size; 486 } else { 487 point_size = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH / 488 (lines_per_page + 0.5); 489 columns = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / 490 (point_size * DEFAULT_CHAR_WIDTH); 491 } 492 } 493 494 box_height = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / layoutp->page_rows; 495 if (layoutp->rotation == 0) 496 box_width = box_height / 497 DEFAULT_PAGE_HEIGHT * DEFAULT_PAGE_WIDTH; 498 else 499 box_width = box_height * 500 DEFAULT_PAGE_HEIGHT / DEFAULT_PAGE_WIDTH; 501 gap_width = DEFAULT_PAPER_WIDTH * POINTS_PER_INCH / 502 layoutp->page_cols - box_width; 503 gap_height = DEFAULT_PAPER_HEIGHT * POINTS_PER_INCH / 504 layoutp->page_rows - box_height; 505 margin_x = gap_width/2; 506 margin_y = gap_height/2; 507 508 columns -= numberwidth + DEFAULT_SPACES_AFTER_NUMBER; 509 if (columns <= 0) { 510 fatal("numbering width exceeds number of columns"); 511 /* NOT REACHED */ 512 } 513 /* compute physical "lower left corner" of each logical page */ 514 for (j = 0; j < layoutp->pages; j++) { 515 int phys_row; /* 0 is bottom row */ 516 int phys_col; /* 0 is left column */ 517 518 if (landscape == (rot_text == 0)) { 519 /* logical pages run physically up and down */ 520 phys_row = j % layoutp->page_rows; 521 phys_col = j / layoutp->page_rows; 522 } else { 523 /* logical pages run physically left to right */ 524 phys_row = j / layoutp->page_cols; 525 phys_col = j % layoutp->page_cols; 526 } 527 if (rot_text == 0) { 528 /* top physical row is logically first */ 529 phys_row = layoutp->page_rows - 1 - phys_row; 530 } 531 532 positions[j].base_x = margin_x + 533 phys_col * (box_width + gap_width); 534 positions[j].base_y = margin_y + 535 phys_row * (box_height + gap_height); 536 if (rot_text != 0) { 537 positions[j].base_x += box_width; 538 } 539 } 540 541 if (vflag) { 542 (void) fprintf(stderr, "%s: %s\n\n", progname, sccsid); 543 (void) fprintf(stderr, "Lines/page = %d\n", lines_per_page); 544 (void) fprintf(stderr, "Columns = %d\n", columns); 545 for (j = 0; j < layoutp->pages; j++) { 546 (void) fprintf(stderr, "\tx=%3d, y=%3d\n", 547 positions[j].base_x, 548 positions[j].base_y); 549 } 550 (void) fprintf(stderr, "box_width=%3d, box_height=%3d\n", 551 box_width, box_height); 552 (void) fprintf(stderr, "gap_width=%3d, gap_height=%3d\n", 553 gap_width, gap_height); 554 } 555 556 setup(); 557 preamble(); 558 559 if (iscodereview) { 560 char command[BUFSIZ]; 561 562 (void) snprintf(command, BUFSIZ, "diff -b -D %s %s %s", 563 CODEREVIEW, argv[first_file+1], argv[first_file]); 564 infile = popen(command, "r"); 565 bannerfile = argv[first_file+1]; 566 if (ungetc(getc(infile), infile) == EOF) { 567 (void) pclose(infile); 568 (void) sprintf(command, 569 "echo No differences encountered"); 570 infile = popen(command, "r"); 571 } 572 setheaderfile(bannerfile); 573 printfile(infile); 574 (void) pclose(infile); 575 } else if (first_file == argc) { /* no files on command line */ 576 if (vflag) 577 (void) fprintf(stderr, "\tprinting stdin\n"); 578 setheaderfile("stdin"); 579 printfile(stdin); 580 } else { 581 for (i = first_file; i < argc; i++) { 582 if ((infile = fopen(argv[i], "r")) == (FILE *)NULL) { 583 fatal("can't open %s for reading", argv[i]); 584 /*NOTREACHED*/ 585 } 586 if (pflag) { 587 char cmdbuf[BUFSIZ]; 588 (void) snprintf(cmdbuf, BUFSIZ, "pr %s", 589 argv[i]); 590 (void) fclose(infile); 591 infile = popen(cmdbuf, "r"); 592 } 593 if (vflag) 594 (void) fprintf(stderr, "\tprinting %s\n", 595 argv[i]); 596 setheaderfile(argv[i]); 597 printfile(infile); 598 if (pflag) 599 (void) pclose(infile); 600 else 601 (void) fclose(infile); 602 } 603 } 604 605 postamble(); 606 607 if (fflush(stdout) == EOF) { 608 fatal("write error on stdout"); 609 /*NOTREACHED*/ 610 } 611 exit(0); 612 /*NOTREACHED*/ 613 /*LINTED*/ 614 } 615 616 /* 617 * Initial lines sent to the LaserWriter 618 * Generates the PostScript header and includes the prologue file 619 * There is limited checking for I/O errors here 620 */ 621 void 622 preamble(void) 623 { 624 (void) printf("%%!PS-Adobe-2.0\n"); 625 (void) printf("%%%%Creator: %s on %s\n", progname, hostname); 626 (void) printf("%%%%CreationDate: %s\n", currentdate); 627 (void) printf("%%%%For: %s\n", username); 628 (void) printf("%%%%DocumentFonts: %s %s %s %s\n", 629 default_font, default_font_bold, 630 default_font_italic, default_font_bold_italic); 631 (void) printf("%%%%Pages: (atend)\n"); 632 633 if (prologue == NULL) { 634 char **cpp; 635 for (cpp = default_prologue; *cpp; cpp++) { 636 (void) fputs(*cpp, stdout); 637 } 638 } else { 639 FILE *fp; 640 if ((fp = fopen(prologue, "r")) == NULL) { 641 fatal("can't open prologue file %s", prologue); 642 /*NOTREACHED*/ 643 } 644 while (fgets(bufin, sizeof (bufin), fp) != NULL) 645 (void) fputs(bufin, stdout); 646 (void) fclose(fp); 647 } 648 if (ferror(stdout) || fflush(stdout) == EOF) { 649 fatal("write error on stdout"); 650 /*NOTREACHED*/ 651 } 652 653 (void) printf("/%s {%f /%s %s}bind def\n", DEFAULT_FONT, 654 point_size, default_font, SELECT_FONT); 655 (void) printf("/%s {%f /%s %s}bind def\n", DEFAULT_FONT_BOLD, 656 point_size, default_font_bold, SELECT_FONT); 657 (void) printf("/%s {%f /%s %s}bind def\n", DEFAULT_FONT_ITALIC, 658 point_size, default_font_italic, SELECT_FONT); 659 (void) printf("/%s {%f /%s %s}bind def\n", DEFAULT_FONT_BOLD_ITALIC, 660 point_size, default_font_bold_italic, SELECT_FONT); 661 } 662 663 void 664 postamble(void) 665 { 666 (void) printf("%%%%Trailer\n"); 667 (void) printf("%%%%Pages: %d\n", current.page_count); 668 } 669 670 int 671 printbanner(char *filename, FILE *outfile) 672 { 673 char buffer[BUFSIZ]; 674 struct stat statbuf; 675 struct format_state format_state; 676 int nlines = 0; 677 678 /* we've already verified readability */ 679 (void) stat(filename, &statbuf); 680 681 save_format_state(&format_state); 682 numberwidth = 0; 683 684 setcurrentfont(DEFAULT_FONT_BOLD_ITALIC, outfile); 685 686 current.row -= point_size; 687 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, MOVETO); 688 proc(banner, outfile); 689 nlines++; 690 691 current.row -= point_size; 692 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, MOVETO); 693 (void) snprintf(buffer, BUFSIZ, "%8ld %.24s", statbuf.st_size, 694 ctime(&statbuf.st_mtime)); 695 proc(buffer, outfile); 696 nlines++; 697 698 do { 699 current.row -= point_size; 700 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, 701 MOVETO); 702 filename += sprintf(buffer, "%.*s", columns, filename); 703 proc(buffer, outfile); 704 nlines++; 705 } while (strlen(filename) != 0); 706 707 current.row -= point_size; 708 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, MOVETO); 709 proc(banner, outfile); 710 nlines++; 711 712 restore_format_state(&format_state, outfile); 713 savestate(outfile); 714 return (nlines); 715 } 716 717 void 718 setcurrentfont(char *newfont, FILE *outfile) 719 { 720 if (current.font != newfont) { 721 if (newfont) 722 current.font = newfont; 723 (void) fprintf(outfile, "%s\n", current.font); 724 } 725 } 726 727 void 728 savestate(FILE *f) 729 { 730 current.offset = ftell(f); 731 saved = current; 732 } 733 734 void 735 restorestate(FILE *f) 736 { 737 char *font; 738 739 font = current.font; 740 (void) fseek(f, saved.offset, 0); 741 current = saved; 742 setcurrentfont(font, f); 743 } 744 745 void 746 save_format_state(struct format_state *fs) 747 { 748 fs->numberwidth = numberwidth; 749 fs->linenumber = linenumber; 750 fs->altlinenumber = altlinenumber; 751 fs->makegray = makegray; 752 fs->font = current.font; 753 } 754 755 void 756 restore_format_state(struct format_state *fs, FILE *outfile) 757 { 758 numberwidth = fs->numberwidth; 759 linenumber = fs->linenumber; 760 altlinenumber = fs->altlinenumber; 761 makegray = fs->makegray; 762 setcurrentfont(fs->font, outfile); 763 } 764 765 /* 766 * Print a file 767 * 768 * The input stream may be stdin, a file, or a pipe 769 */ 770 void 771 printfile(FILE *infile) 772 { 773 int eof; 774 char *p; 775 FILE *outfile; 776 777 if (reverse) 778 page_map[0] = 0L; 779 if (usetmp) { 780 (void) snprintf(bufin, BUFIN, "/tmp/%sXXXXXX", progname); 781 p = mktemp(bufin); 782 if ((outfile = fopen(p, "w+")) == NULL) { 783 fatal("can't open temporary file %s", p); 784 /* NOTREACHED */ 785 } 786 if (!dflag) 787 (void) unlink(p); 788 else 789 (void) fprintf(stderr, "will not unlink %s\n", p); 790 } 791 else 792 outfile = stdout; 793 794 setcurrentfont(DEFAULT_FONT, outfile); 795 change_seen = 0; 796 dots_inserted = 0; 797 in_change = 0; 798 makegray = 0; 799 linenumber = 0; 800 altlinenumber = 0; 801 current.logical_page_count = 0; 802 do { 803 current.row = start_y; 804 eof = printpage(infile, outfile); 805 } while (!eof); 806 807 if (((int)current.row) != start_y) 808 endpage(outfile); 809 if ((current.logical_page_count % layoutp->pages) != 0) 810 flushpage(outfile); 811 if (vflag) 812 (void) fprintf(stderr, "\n"); 813 if (fflush(outfile) == EOF) { 814 fatal("write error while flushing output"); 815 /*NOTREACHED*/ 816 } 817 if (usetmp) { 818 if (reverse) 819 reversepages(outfile); 820 else 821 copypage(outfile, 0L, current.offset); 822 (void) fclose(outfile); 823 } 824 } 825 826 void 827 process_elide(FILE *outfile) 828 { 829 if (!change_seen && !in_change) { 830 /* don't include function in output */ 831 restorestate(outfile); 832 if (!dots_inserted) { 833 struct format_state format_state; 834 835 save_format_state(&format_state); 836 numberwidth = 0; 837 current.lineno++; 838 current.row -= point_size; 839 setcurrentfont(DEFAULT_FONT_BOLD_ITALIC, 840 outfile); 841 proc("______unchanged_portion_omitted_", 842 outfile); 843 restore_format_state(&format_state, 844 outfile); 845 savestate(outfile); 846 dots_inserted = 1; 847 } 848 } else { 849 savestate(outfile); 850 change_seen = in_change; 851 dots_inserted = 0; 852 } 853 } 854 855 /* 856 * Process the next page 857 * Return 1 on EOF, 0 otherwise 858 */ 859 int 860 printpage(FILE *infile, FILE *outfile) 861 { 862 int tmplinenumber; 863 char command[BUFSIZ], flag[BUFSIZ]; 864 865 if (ungetc(getc(infile), infile) == EOF) 866 return (1); 867 868 current.lineno = 0; 869 current.lineno += startpage(outfile); 870 if (bannerfile) { 871 current.lineno += printbanner(bannerfile, outfile); 872 bannerfile = NULL; 873 } 874 for (; current.lineno < lines_per_page; ) { 875 if (fgetline(bufin, sizeof (bufin), infile) == (char *)NULL) { 876 if (elide) 877 process_elide(outfile); 878 return (1); 879 } 880 /* 881 * Allow C comment delimiters around flag; only really applies 882 * to #else and #endif, but we don't expect to see C comments 883 * around flag for #if. Also accept flag with no C comment 884 * delimiters. 885 */ 886 if (iscodereview && 887 (sscanf(bufin, "#%32s /* %80s */", command, flag) == 2 || 888 sscanf(bufin, "#%32s %80s", command, flag) == 2) && 889 strcmp(flag, CODEREVIEW) == 0) { 890 if (strcmp(command, "ifdef") == 0) { 891 change_seen = 1; 892 in_change = 1; 893 makegray = 1; 894 old_stuff = 1; 895 tmplinenumber = linenumber; 896 linenumber = altlinenumber; 897 altlinenumber = tmplinenumber; 898 setcurrentfont(DEFAULT_FONT_ITALIC, outfile); 899 } else if (strcmp(command, "ifndef") == 0) { 900 change_seen = 1; 901 in_change = 1; 902 makegray = 1; 903 old_stuff = 0; 904 setcurrentfont(DEFAULT_FONT_BOLD, outfile); 905 } else if (strcmp(command, "else") == 0) { 906 makegray = 1; 907 old_stuff = !old_stuff; 908 tmplinenumber = linenumber; 909 linenumber = altlinenumber; 910 altlinenumber = tmplinenumber; 911 if (!old_stuff) 912 setcurrentfont(DEFAULT_FONT_BOLD, 913 outfile); 914 else 915 setcurrentfont(DEFAULT_FONT_ITALIC, 916 outfile); 917 } else /* if (strcmp(command, "endif") == 0) */ { 918 in_change = 0; 919 makegray = 0; 920 savestate(outfile); 921 setcurrentfont(DEFAULT_FONT, outfile); 922 if (old_stuff) { 923 tmplinenumber = linenumber; 924 linenumber = altlinenumber; 925 altlinenumber = tmplinenumber; 926 } 927 } 928 continue; 929 } 930 current.lineno++; 931 current.row -= point_size; 932 if (bufin[0] == '\f') 933 break; 934 proc(bufin, outfile); 935 if (elide && (bufin[0] == END_C_FUNCTION || 936 (strstr(bufin, END_ASM_FUNCTION) != NULL))) 937 process_elide(outfile); 938 } 939 endpage(outfile); 940 return (0); 941 } 942 943 /* 944 * Start a new page 945 */ 946 int 947 startpage(FILE *outfile) 948 { 949 int logical_page, lines, buflen; 950 struct format_state format_state; 951 char buf[8]; 952 953 logical_page = current.logical_page_count % layoutp->pages; 954 955 if (logical_page == 0) 956 setuppage(outfile); 957 else 958 setcurrentfont((char *)NULL, outfile); 959 (void) fprintf(outfile, "%s ", SET_WIDTHS); 960 (void) fprintf(outfile, "%d %f %d %d %s\n", 961 rot_text, layoutp->scale, 962 positions[logical_page].base_x, 963 positions[logical_page].base_y, 964 START_PAGE); 965 lines = 0; 966 if (header) { 967 save_format_state(&format_state); 968 setcurrentfont(DEFAULT_FONT_BOLD, outfile); 969 numberwidth = 0; 970 makegray = 0; 971 972 current.row -= point_size; 973 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, 974 MOVETO); 975 proc(headerstring, outfile); 976 (void) snprintf(buf, 8, "%d", current.logical_page_count + 1); 977 buflen = strlen(buf); 978 (void) fprintf(outfile, "%d %.2f %s (%s)%s\n", 979 (int)(end_x - (buflen + 0.5) * 980 DEFAULT_CHAR_WIDTH * point_size), 981 current.row, MOVETO, buf, SHOW); 982 current.row -= point_size; 983 restore_format_state(&format_state, outfile); 984 lines = 2; 985 } 986 return (lines); 987 } 988 989 void 990 setheaderfile(char *filename) 991 { 992 if (header == HEADER_IMPLICIT) 993 headerstring = filename; 994 } 995 996 /* 997 * Setup page 998 */ 999 void 1000 setuppage(FILE *outfile) 1001 { 1002 int i, ilimit; 1003 int begin, end, place; 1004 1005 (void) fprintf(outfile, "%%%%Page: ? %d\n", current.page_count + 1); 1006 setcurrentfont((char *)NULL, outfile); 1007 if (layoutp->pages == 1) 1008 return; 1009 1010 (void) fprintf(outfile, "%f %s %s\n", 1011 RULE_WIDTH, SETLINEWIDTH, NEWPATH); 1012 begin = 0; end = DEFAULT_PAPER_WIDTH * POINTS_PER_INCH; 1013 for (i = 1, ilimit = layoutp->page_rows; i < ilimit; i++) { 1014 place = margin_y - gap_height/2 + i * (box_height+gap_height); 1015 (void) fprintf(outfile, "%d %d %s ", begin, place, MOVETO); 1016 (void) fprintf(outfile, "%d %d %s\n", end, place, LINETO); 1017 } 1018 begin = 0; end = DEFAULT_PAPER_HEIGHT * POINTS_PER_INCH; 1019 for (i = 1, ilimit = layoutp->page_cols; i < ilimit; i++) { 1020 place = margin_x - gap_width/2 + i * (box_width+gap_width); 1021 (void) fprintf(outfile, "%d %d %s ", place, begin, MOVETO); 1022 (void) fprintf(outfile, "%d %d %s\n", place, end, LINETO); 1023 } 1024 (void) fprintf(outfile, "%s\n", STROKE); 1025 } 1026 1027 /* 1028 * Terminate the logical page and indicate the start of the next 1029 */ 1030 void 1031 endpage(FILE *outfile) 1032 { 1033 (void) fprintf(outfile, "%s\n", END_PAGE); 1034 current.logical_page_count++; 1035 if (vflag) 1036 (void) fprintf(stderr, "x"); 1037 if ((current.logical_page_count % layoutp->pages) == 0) 1038 flushpage(outfile); 1039 } 1040 1041 /* 1042 * Flush the physical page 1043 * Record the start of the next page 1044 */ 1045 void 1046 flushpage(FILE *outfile) 1047 { 1048 (void) fprintf(outfile, "%d %s\n", ncopies, FLUSH_PAGE); 1049 current.page_count++; 1050 current.offset = ftell(outfile); 1051 if (reverse) { 1052 if (current.page_count >= MAXPAGES) { 1053 fatal("page reversal limit (%d) reached", MAXPAGES); 1054 /* NOTREACHED */ 1055 } 1056 page_map[current.page_count] = current.offset; 1057 } 1058 if (vflag) 1059 (void) fprintf(stderr, "|"); 1060 } 1061 1062 /* 1063 * reverse the order of pages 1064 */ 1065 void 1066 reversepages(FILE *outfile) 1067 { 1068 int i; 1069 1070 if (vflag) 1071 (void) fprintf(stderr, "\nreversing %d page%s\n", 1072 current.page_count, 1073 current.page_count > 1 ? "s" : ""); 1074 for (i = current.page_count - 1; i >= 0; i--) { 1075 copypage(outfile, page_map[i], page_map[i+1]); 1076 } 1077 } 1078 1079 /* 1080 * copy a page (or more) from tempfile to stdout 1081 */ 1082 void 1083 copypage(FILE *outfile, long off_beg, long off_end) 1084 { 1085 int bytecount, nbytes; 1086 1087 if (fseek(outfile, off_beg, 0) == -1L) { 1088 fatal("temporary file seek error"); 1089 /* NOTREACHED */ 1090 } 1091 nbytes = off_end - off_beg; 1092 while (nbytes > 0) { 1093 bytecount = nbytes; 1094 if (bytecount > sizeof (bufout)) 1095 bytecount = sizeof (bufout); 1096 bytecount = fread(bufout, 1, bytecount, outfile); 1097 if (bytecount <= 0) { 1098 fatal("temporary file read error"); 1099 /* NOTREACHED */ 1100 } 1101 if (fwrite(bufout, 1, bytecount, stdout) != bytecount) { 1102 fatal("write error during page copy"); 1103 /* NOTREACHED */ 1104 } 1105 nbytes -= bytecount; 1106 } 1107 } 1108 1109 /* 1110 * Process a line of input, escaping characters when necessary and handling 1111 * tabs 1112 * 1113 * The output is improved somewhat by coalescing consecutive tabs and 1114 * backspaces and eliminating tabs at the end of a line 1115 * 1116 * Overprinting (presumably most often used in underlining) can be far from 1117 * optimal; in particular the way nroff underlines by sequences like 1118 * "_\ba_\bb_\bc" creates a large volume of PostScript. This isn't too 1119 * serious since a lot of nroff underlining is unlikely. 1120 * 1121 * Since a newline is generated for each call there will be more 1122 * newlines in the output than is necessary 1123 */ 1124 void 1125 proc(char *in, FILE *outfile) 1126 { 1127 int i; 1128 char *last, *p, *q; 1129 int currentp, instr, tabc, tabto, grayed; 1130 char *altfont; 1131 1132 currentp = 0; 1133 instr = 0; 1134 tabto = 0; 1135 if (iscodereview) { 1136 grayed = makegray; 1137 altfont = current.font; 1138 } else { 1139 grayed = 0; 1140 altfont = DEFAULT_FONT; 1141 } 1142 /* subtract slop factor */ 1143 last = bufout + MAX_OUTPUT_LINE_LENGTH - 20; 1144 for (;;) { /* check for any special line treatment */ 1145 if (graylength && strncmp(in, graystring, graylength) == 0) { 1146 grayed++; 1147 in += graylength; 1148 } else if (boldlength && 1149 strncmp(in, boldstring, boldlength) == 0) { 1150 altfont = DEFAULT_FONT_BOLD; 1151 in += boldlength; 1152 } else if (itlclength && 1153 strncmp(in, itlcstring, itlclength) == 0) { 1154 altfont = DEFAULT_FONT_ITALIC; 1155 in += itlclength; 1156 } else if (bitclength && 1157 strncmp(in, bitcstring, bitclength) == 0) { 1158 altfont = DEFAULT_FONT_BOLD_ITALIC; 1159 in += bitclength; 1160 } else 1161 break; 1162 } 1163 if (grayed) { 1164 (void) fprintf(outfile, "%d %.2f %d %.2f %s\n", 1165 start_x, current.row - 1166 DEFAULT_DESCENDER_FRACTION * point_size, 1167 end_x, current.row + 1168 (1.0 - DEFAULT_DESCENDER_FRACTION) * point_size, 1169 SHADE); 1170 } 1171 1172 linenumber++; 1173 if (!in_change) 1174 altlinenumber++; 1175 if (*in == '\0') 1176 return; 1177 1178 if (start_x != 0) { 1179 (void) fprintf(outfile, "%d %.2f %s\n", 1180 start_x, current.row, MOVETO); 1181 } 1182 else 1183 (void) fprintf(outfile, "%.2f %s\n", 1184 current.row, ZEROMOVETO); 1185 if (numberwidth) { 1186 setcurrentfont(DEFAULT_FONT, outfile); 1187 (void) sprintf(bufout, "%*d", numberwidth, linenumber); 1188 for (q = bufout, i = 0; *q == ' '; q++, i++) 1189 ; 1190 (void) fprintf(outfile, "%d %s (%s)%s %d %s ", 1191 i, TAB, q, SHOW, DEFAULT_SPACES_AFTER_NUMBER, TAB); 1192 } 1193 setcurrentfont(altfont, outfile); 1194 1195 q = bufout; 1196 *q = '\0'; 1197 for (p = in; *p != '\0'; p++) { 1198 switch (*p) { 1199 case '\t': 1200 /* 1201 * Count the number of tabs that immediately follow 1202 * the one we're looking at 1203 */ 1204 tabc = 0; 1205 while (*(p + 1) == '\t') { 1206 p++; 1207 tabc++; 1208 } 1209 if (currentp > 0) { /* not beginning of line */ 1210 i = tabstop - (currentp % tabstop) + 1211 tabc * tabstop; 1212 if (instr) { 1213 (void) snprintf(q, 1214 BUFOUT - (q - bufout), ")%s ", 1215 SHOW); 1216 q += strlen(q); 1217 instr = 0; 1218 } 1219 } 1220 else 1221 i = (tabc + 1) * tabstop; 1222 tabto += i; 1223 currentp += i; 1224 break; 1225 case '\b': 1226 /* backspacing over tabs doesn't work... */ 1227 if (tabto != 0) { 1228 fatal("attempt to backspace over a tab"); 1229 /*NOTREACHED*/ 1230 } 1231 p++; 1232 for (i = 1; *p == '\b'; p++) 1233 i++; 1234 p--; 1235 if (currentp - i < 0) { 1236 fatal("too many backspaces"); 1237 /*NOTREACHED*/ 1238 } 1239 if (instr) { 1240 *q = '\0'; 1241 (void) fprintf(outfile, "%s)%s\n", 1242 bufout, SHOW); 1243 } 1244 instr = 0; 1245 if (currentp >= columns) 1246 i -= currentp-columns; 1247 if (i <= 0) { 1248 /* backspace in truncated line */ 1249 bufout[0] = '\0'; 1250 } else if (i == 1) { 1251 /* frequent case gets special attention */ 1252 (void) snprintf(bufout, BUFOUT, "%s ", 1253 BACKSPACE); 1254 } else 1255 (void) snprintf(bufout, BUFOUT, "-%d %s ", i, 1256 TAB); 1257 q = bufout + strlen(bufout); 1258 currentp -= i; 1259 break; 1260 case '\f': 1261 tabto = 0; /* optimizes */ 1262 *q = '\0'; 1263 if (instr) 1264 (void) fprintf(outfile, "%s)%s\n", 1265 bufout, SHOW); 1266 else 1267 (void) fprintf(outfile, "%s\n", bufout); 1268 endpage(outfile); 1269 (void) startpage(outfile); 1270 current.row = start_y; 1271 (void) fprintf(outfile, "%d %.2f %s\n", 1272 start_x, current.row, MOVETO); 1273 if (numberwidth) 1274 (void) fprintf(outfile, "%d %s\n", numberwidth + 1275 DEFAULT_SPACES_AFTER_NUMBER, TAB); 1276 q = bufout; 1277 currentp = 0; 1278 instr = 0; 1279 break; 1280 case '\r': 1281 tabto = 0; /* optimizes */ 1282 if (instr) { 1283 *q = '\0'; 1284 (void) fprintf(outfile, "%s)%s\n", 1285 bufout, SHOW); 1286 instr = 0; 1287 q = bufout; 1288 } 1289 (void) fprintf(outfile, "%d %.2f %s\n", 1290 start_x, current.row, MOVETO); 1291 if (numberwidth) 1292 (void) fprintf(outfile, "%d %s\n", numberwidth + 1293 DEFAULT_SPACES_AFTER_NUMBER, TAB); 1294 currentp = 0; 1295 break; 1296 case '\\': 1297 case '(': 1298 case ')': 1299 if (currentp < columns) { 1300 if (!instr) { 1301 if (tabto) { 1302 (void) snprintf(q, 1303 BUFOUT - (q - bufout), 1304 "%d %s ", tabto, TAB); 1305 q += strlen(q); 1306 tabto = 0; 1307 } 1308 *q++ = '('; 1309 instr = 1; 1310 } 1311 *q++ = '\\'; 1312 *q++ = *p; 1313 } 1314 currentp++; 1315 break; 1316 default: { 1317 /* 1318 * According to the PostScript Language Manual, 1319 * PostScript files can contain only "the printable 1320 * subset of the ASCII character set (plus the 1321 * newline marker)". 1322 */ 1323 char pchar; 1324 1325 pchar = *p; 1326 if (currentp < columns) { 1327 if (!instr) { 1328 if (tabto) { 1329 (void) snprintf(q, 1330 BUFOUT - (q - bufout), 1331 "%d %s ", tabto, TAB); 1332 q += strlen(q); 1333 tabto = 0; 1334 } 1335 *q++ = '('; 1336 instr = 1; 1337 } 1338 if (!isascii(pchar) || !isprint(pchar)) { 1339 if (iscntrl(pchar)) { 1340 if (pchar == '\177') 1341 pchar = '_'; 1342 else 1343 pchar += '@'; 1344 *q++ = '^'; 1345 } else { 1346 *q++ = '\\'; 1347 *q++ = '0' + ((pchar>>6) & 7); 1348 *q++ = '0' + ((pchar>>3) & 7); 1349 pchar = '0' + (pchar & 7); 1350 } 1351 } 1352 *q++ = pchar; 1353 } 1354 currentp++; 1355 break; 1356 } 1357 } 1358 if (q >= last) { 1359 *q = '\0'; 1360 if (instr) 1361 (void) fprintf(outfile, "%s)%s\n", bufout, 1362 SHOW); 1363 else 1364 (void) fprintf(outfile, "%s\n", bufout); 1365 q = bufout; 1366 instr = 0; 1367 } 1368 } 1369 if (instr) { 1370 (void) snprintf(q, BUFOUT - (q - bufout), ")%s", SHOW); 1371 q += strlen(q); 1372 } 1373 else 1374 *q = '\0'; 1375 if (q >= last) { 1376 fatal("bufout overflow"); 1377 /*NOTREACHED*/ 1378 } 1379 if (bufout[0] != '\0') 1380 (void) fprintf(outfile, "%s\n", bufout); 1381 } 1382 1383 /* 1384 * Initialize globals: 1385 * username - login name of user 1386 * hostname - name of machine on which lwlp is run 1387 * currentdate - what it says 1388 * Possible system dependencies here... 1389 */ 1390 void 1391 setup(void) 1392 { 1393 int len; 1394 char *p; 1395 long t; 1396 struct utsname utsname; 1397 struct passwd *pw; 1398 1399 if ((p = getlogin()) == (char *)NULL) { 1400 if ((pw = getpwuid(getuid())) == (struct passwd *)NULL) 1401 p = "Whoknows"; 1402 else 1403 p = pw->pw_name; 1404 endpwent(); 1405 } 1406 username = strdup(p); 1407 1408 (void) uname(&utsname); 1409 hostname = strdup(utsname.nodename); 1410 1411 t = time((long *)0); 1412 p = ctime(&t); 1413 len = strlen(p); 1414 *(p + len - 1) = '\0'; /* zap the newline character */ 1415 currentdate = strdup(p); 1416 current.font = DEFAULT_FONT; 1417 } 1418 1419 /* 1420 * Special version of fgets 1421 * Read until a formfeed, newline, or overflow 1422 * If a formfeed is the first character, return it immediately 1423 * If a formfeed is found after the first character, replace it by a newline 1424 * and push the formfeed back onto the input stream 1425 * A special case is a formfeed followed by a newline in which case the 1426 * newline is ignored 1427 * The input buffer will be null-terminated and will *not* end with a newline 1428 * The buffer size n includes the null 1429 */ 1430 char * 1431 fgetline(char *s, int n, FILE *iop) 1432 { 1433 int ch; 1434 char *cs; 1435 1436 if (n < 2) { 1437 fatal("fgetline called with bad buffer size!?"); 1438 /*NOTREACHED*/ 1439 } 1440 1441 cs = s; 1442 n--; /* the null */ 1443 1444 /* 1445 * Check out the special cases 1446 */ 1447 if ((ch = getc(iop)) == EOF) 1448 return ((char *)NULL); 1449 if (ch == '\f') { 1450 if ((ch = getc(iop)) != '\n') { 1451 /* 1452 * If EOF was just read it will be noticed 1453 * next time through 1454 */ 1455 if (ungetc(ch, iop) == EOF && !feof(iop)) { 1456 /* 1457 * Shouldn't happen since a getc() 1458 * was just done 1459 */ 1460 fatal("fgetline - ungetc failed"); 1461 /*NOTREACHED*/ 1462 } 1463 } 1464 *cs++ = '\f'; 1465 *cs = '\0'; 1466 return (s); 1467 } 1468 1469 /* 1470 * Check for "weird" input characters is made in proc() 1471 */ 1472 while (n-- > 0) { 1473 if (ch == '\f' || ch == '\n') 1474 break; 1475 *cs++ = ch; 1476 if ((ch = getc(iop)) == EOF) 1477 break; 1478 } 1479 1480 if (ch == EOF && cs == s) /* Nothing was read */ 1481 return ((char *)NULL); 1482 if (ch == '\f') { 1483 if (ungetc(ch, iop) == EOF) 1484 (void) fprintf(stderr, "fgetline - can't ungetc??\n"); 1485 } else if (ch != '\n' && ch != EOF) { 1486 fatal("fgetline - input line too long"); 1487 /*NOTREACHED*/ 1488 } 1489 *cs = '\0'; 1490 return (s); 1491 } 1492 1493 /*PRINTFLIKE1*/ 1494 void 1495 fatal(char *fmt, ...) 1496 { 1497 va_list ap; 1498 1499 (void) fprintf(stderr, "%s: ", progname); 1500 va_start(ap, fmt); 1501 (void) vfprintf(stderr, fmt, ap); 1502 va_end(ap); 1503 (void) fprintf(stderr, "\n"); 1504 exit(1); 1505 /*NOTREACHED*/ 1506 } 1507