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