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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * lwlp - Convert ASCII text to PostScript 28 * 29 * Usage: 30 * lwlp [-{2|4|8}] [-p] [-L] [-r] [-n#] [-l#|-w#] [-c#] [-t#] 31 * [-hstring] [-Bstring] [-Istring] [-Xstring] [-Pfile] [file ...] 32 * 33 * Options: 34 * -{1|2|4|8} print multiple logical pages per page 35 * -d debug, don't remove temporary file 36 * -L specify Landscape instead of Portrait 37 * -p filter input through pr 38 * -r toggle page reversal flag (default is off) 39 * -e elide unchanged functions 40 * -n# number with numberwidth digits 41 * -l# specify number of lines/logical page, default 66 42 * -w# specify number of columns 43 * -c# specify number of copies 44 * -t# specify tab spacing 45 * -htext specify header text 46 * -Btext specify bold font selector 47 * -Itext specify italic font selector 48 * -Xtext specify bold-italic font selector 49 * -Gtext specify graying selector 50 * -Pfile specify different Postscript prologue file 51 * 52 * If no files are specified, stdin is used. 53 * Form feeds handled 54 * Backspacing with underlining (or overprinting) works 55 * The output conforms to Adobe 2.0 56 * 57 * Problems: 58 * - assumes fixed-width (non-proportional) font in some places 59 * - can't back up (using backspaces) over tabs 60 * - assumes 8.5 x 11.0 paper 61 * - uses logical page with aspect ratio of 3 * 4 62 * 63 */ 64 65 #define USAGE1 "[-{1|2|4|8}] [-p] [-L] [-r] [-n<numberwidth]" 66 #define USAGE2 "[-l<lines>|-w<columns>] [-c<count>] [-t<tabs>]" 67 #define USAGE3 "[-hstring] [-Bstring] [-Istring] [-Xstring] [-Gstring]" 68 #define USAGE4 "[-Pfile] [file ...]" 69 #define USAGE6 "[-hstring] [-e] [-y comment] oldfile newfile" 70 71 #include <stdio.h> 72 #include <string.h> 73 #include <stdlib.h> 74 #include <sys/file.h> 75 #include <ctype.h> 76 #include <pwd.h> 77 #include <sys/utsname.h> 78 #include <sys/stat.h> 79 #include <unistd.h> 80 #include <sys/types.h> 81 #include <time.h> 82 #include <stdarg.h> 83 84 /* 85 * Configurable... 86 * BUFOUT should be fairly large 87 */ 88 #define BUFIN 1024 /* maximum length of an input line */ 89 #define BUFOUT (BUFIN * 5) 90 #define MAXPAGES 10000 91 #define REVERSE_OFF 0 92 93 #define DEFAULT_PAPER_HEIGHT 11.0 94 #define DEFAULT_PAPER_WIDTH 8.50 95 #define DEFAULT_PAGE_HEIGHT 10.0 96 #define DEFAULT_PAGE_WIDTH 7.50 97 #define DEFAULT_LINES_PER_PAGE 66 98 #define DEFAULT_TAB_SIZE 8 99 static char *default_font = "Courier"; 100 static char *default_font_bold = "Courier-Bold"; 101 static char *default_font_italic = "Courier-Oblique"; 102 static char *default_font_bold_italic = "Courier-BoldOblique"; 103 static char *select_default_font = "FRN"; 104 static char *select_default_font_bold = "FRB"; 105 static char *select_default_font_italic = "FIN"; 106 static char *select_default_font_bold_italic = "FIB"; 107 #define DEFAULT_FONT select_default_font 108 #define DEFAULT_FONT_BOLD select_default_font_bold 109 #define DEFAULT_FONT_ITALIC select_default_font_italic 110 #define DEFAULT_FONT_BOLD_ITALIC select_default_font_bold_italic 111 #define DEFAULT_CHAR_WIDTH (.6) 112 #define DEFAULT_SPACES_AFTER_NUMBER 1 113 #define DEFAULT_DESCENDER_FRACTION 0.3 114 #define LWLP "lwlp" 115 #define CODEREVIEW "codereview" 116 #define END_C_FUNCTION '}' 117 #define END_ASM_FUNCTION "SET_SIZE(" 118 static char *banner = 119 "**********************************************************"; 120 121 /* 122 * PostScript command strings 123 */ 124 #define LINETO "lineto" 125 #define NEWPATH "newpath" 126 #define SETLINEWIDTH "setlinewidth" 127 #define STROKE "stroke" 128 /* 129 * PostScript command strings defined in the prologue file 130 */ 131 #define BACKSPACE "B" 132 #define MOVETO "M" /* x y */ 133 #define SHOW "S" /* string */ 134 #define TAB "T" /* spaces */ 135 #define ZEROMOVETO "Z" /* y */ 136 #define SELECT_FONT "SFT" /* size font */ 137 #define SET_WIDTHS "SWT" 138 #define START_PAGE "SPG" /* angle scale x y */ 139 #define END_PAGE "EPG" 140 #define FLUSH_PAGE "FPG" /* ncopies */ 141 #define SHADE "SHD" /* x0 y0 x1 y1 */ 142 143 /* 144 * Conformance requires that no PostScript line exceed 256 characters 145 */ 146 #define POINTS_PER_INCH 72 147 #define MAX_OUTPUT_LINE_LENGTH 256 148 149 #define START_X 0 /* position of start of each line */ 150 #define THREE_HOLE_X 1.0 /* portrait x offset (inches) 3 hole */ 151 #define THREE_HOLE_Y 0.5 /* landscape y offset (inches) 3 hole */ 152 #define RULE_WIDTH 0.25 /* width in units of paging rules */ 153 154 static struct print_state { 155 int page_count; 156 int logical_page_count; 157 int lineno; 158 long offset; 159 float row; 160 char *font; 161 } current, saved; 162 163 struct format_state { 164 int numberwidth, linenumber, altlinenumber; 165 int makegray; 166 char *font; 167 }; 168 169 static int change_seen, dots_inserted, in_change, old_stuff, makegray; 170 static int lines_per_page; 171 static int columns; 172 static float point_size; 173 static int start_x, start_y, end_x; 174 static int landscape, rot_text; 175 176 static int ncopies; 177 static int tabstop; 178 static int reverse; 179 static int elide; 180 static int usetmp; 181 static int dflag, lflag, pflag, vflag, wflag; 182 static int numberwidth, linenumber, altlinenumber; 183 static int boldlength, itlclength, bitclength, graylength; 184 static char *boldstring, *itlcstring, *bitcstring, *graystring; 185 #define HEADER_EXPLICIT 1 186 #define HEADER_IMPLICIT 2 187 static int header = HEADER_IMPLICIT; 188 static char *headerstring; 189 static char *bannerfile; 190 191 static char bufin[BUFIN]; /* input buffer */ 192 static char bufout[BUFOUT]; /* output buffer */ 193 static long *page_map; /* offset of first byte of each page */ 194 195 static char *username, *hostname, *currentdate; 196 static char *comment; 197 198 static void preamble(void); 199 static void postamble(void); 200 static void setcurrentfont(char *, FILE *); 201 static void savestate(FILE *); 202 static void restorestate(FILE *); 203 static void save_format_state(struct format_state *); 204 static void printfile(FILE *); 205 static int printpage(FILE *, FILE *); 206 static int startpage(FILE *); 207 static void endpage(FILE *); 208 static void copypage(FILE *, long, long); 209 static void process_elide(FILE *); 210 static void setheaderfile(char *); 211 static void restore_format_state(struct format_state *, FILE *); 212 static void flushpage(FILE *); 213 static void setuppage(FILE *); 214 static void reversepages(FILE *); 215 static void proc(char *, FILE *); 216 static void setup(void); 217 static int printbanner(char *, FILE *); 218 static char *fgetline(char *, int, FILE *); 219 static void fatal(char *fmt, ...); 220 221 static char *prologue; 222 static char *progname; 223 static int iscodereview; 224 225 static char *default_prologue[] = { 226 "%%EndComments\n", 227 "%\n", 228 "% PostScript Prologue for lwlp LaserWriter Line Printer\n", 229 "%\n", 230 "/SFT {findfont exch scalefont setfont}bind def\n", 231 "/SWT {( ) stringwidth pop dup /W exch def neg /NW exch def}bind def\n", 232 "/SPG {/SV save def translate dup scale rotate}bind def\n", 233 "/EPG {SV restore}bind def\n", 234 "/FPG {/#copies exch def showpage}bind def\n", 235 "/B {NW 0 rmoveto}def\n", 236 "/M /moveto load def\n", 237 "/T {W mul 0 rmoveto}def\n", 238 "/S /show load def\n", 239 "/Z {0 exch moveto}bind def\n", 240 "/SHD {save 5 1 roll % S x1 y1 x0 y0\n", 241 " 2 copy moveto % S x1 y1 x0 y0\n", 242 " 3 index exch lineto % S x1 y1 x0\n", 243 " 3 -1 roll 2 index lineto % S y1 x0\n", 244 " exch lineto % S\n", 245 " 0.95 setgray fill % S\n", 246 " restore}def\n", 247 "%%EndProlog\n", 248 NULL 249 }; 250 251 struct layout { 252 float scale; 253 int pages, page_rows, page_cols; 254 int rotation; 255 }; 256 static struct layout *layoutp; 257 static struct layout layout1 = { 1.000000, 1, 1, 1, 0 }; 258 static struct layout layout2 = { 0.666666, 2, 2, 1, 90 }; 259 static struct layout layout4 = { 0.500000, 4, 2, 2, 0 }; 260 static struct layout layout8 = { 0.333333, 8, 4, 2, 90 }; 261 262 static int box_width, box_height; 263 static int gap_width, gap_height; 264 static int margin_x, margin_y; 265 266 static struct position { 267 int base_x; 268 int base_y; 269 } positions[8]; 270 271 int 272 main(int argc, char **argv) 273 { 274 int ch, i, j, first_file; 275 char *pc; 276 FILE *infile; 277 278 if ((pc = strrchr(argv[0], '/')) != NULL) 279 progname = pc + 1; 280 else 281 progname = argv[0]; 282 283 lines_per_page = DEFAULT_LINES_PER_PAGE; 284 layoutp = &layout1; 285 tabstop = DEFAULT_TAB_SIZE; 286 current.page_count = 0; 287 ncopies = 1; 288 reverse = REVERSE_OFF; 289 290 /*LINTED*/ 291 if (iscodereview = strncmp(progname, CODEREVIEW, 292 sizeof (CODEREVIEW) - 1) == 0) { 293 layoutp = &layout2; 294 numberwidth = 4; 295 columns = 85; /* extra space for numbering */ 296 wflag = -1; 297 } 298 299 while ((ch = getopt(argc, argv, 300 "1248B:c:deG:h:I:l:Ln:P:prt:vw:X:y:")) != -1) { 301 switch (ch) { 302 case '1': 303 layoutp = &layout1; 304 break; 305 case '2': 306 layoutp = &layout2; 307 break; 308 case '4': 309 layoutp = &layout4; 310 break; 311 case '8': 312 layoutp = &layout8; 313 break; 314 case 'B': 315 boldlength = strlen(optarg); 316 boldstring = malloc((size_t)(boldlength + 1)); 317 (void) strcpy(boldstring, optarg); 318 break; 319 case 'c': 320 ncopies = atof(optarg); 321 if (ncopies <= 0) { 322 fatal("number of copies must be > 0"); 323 /*NOTREACHED*/ 324 } 325 break; 326 case 'd': 327 dflag = 1; 328 break; 329 case 'e': 330 elide = 1; 331 break; 332 case 'G': 333 graylength = strlen(optarg); 334 graystring = malloc((size_t)(graylength + 1)); 335 (void) strcpy(graystring, optarg); 336 break; 337 case 'h': 338 header = HEADER_EXPLICIT; 339 i = strlen(optarg); 340 headerstring = malloc((size_t)(i + 1)); 341 (void) strcpy(headerstring, optarg); 342 if (strcmp(headerstring, "-") == 0) 343 header = HEADER_IMPLICIT; 344 break; 345 case 'I': 346 itlclength = strlen(optarg); 347 itlcstring = malloc((size_t)(itlclength + 1)); 348 (void) strcpy(itlcstring, optarg); 349 break; 350 case 'l': 351 lines_per_page = atoi(optarg); 352 if (lines_per_page < 1) { 353 fatal("invalid number of lines/page"); 354 /*NOTREACHED*/ 355 } 356 lflag = 1; 357 if (wflag > 0) { 358 fatal("can't have both -l and -w"); 359 /*NOTREACHED*/ 360 } 361 wflag = 0; 362 break; 363 case 'L': 364 landscape = 1; 365 break; 366 case 'm': 367 break; 368 case 'n': 369 numberwidth = atoi(optarg); 370 if (numberwidth < 2) { 371 fatal("invalid numbering width"); 372 /*NOTREACHED*/ 373 } 374 break; 375 case 'P': 376 prologue = optarg; 377 break; 378 case 'p': 379 pflag = 1; 380 break; 381 case 'r': 382 reverse = !reverse; 383 break; 384 case 't': 385 tabstop = atoi(optarg); 386 if (tabstop < 1) { 387 fatal("negative tabstop"); 388 /*NOTREACHED*/ 389 } 390 break; 391 case 'v': 392 vflag = 1; 393 break; 394 case 'w': 395 columns = atoi(optarg); 396 if (columns < 1) { 397 fatal("invalid number of columns"); 398 /*NOTREACHED*/ 399 } 400 wflag = 1; 401 if (lflag) { 402 fatal("can't have both -l and -w"); 403 /*NOTREACHED*/ 404 } 405 break; 406 case 'X': 407 bitclength = strlen(optarg); 408 bitcstring = malloc((size_t)(bitclength + 1)); 409 (void) strcpy(bitcstring, optarg); 410 break; 411 case 'y': 412 comment = optarg; 413 break; 414 default: 415 (void) fprintf(stderr, 416 "usage: %s %s\n\t%s\n\t%s\n\t%s\n", 417 iscodereview ? LWLP : progname, 418 USAGE1, USAGE2, USAGE3, USAGE4); 419 if (iscodereview) 420 (void) fprintf(stderr, "\t%s [%s flags] %s\n", 421 CODEREVIEW, LWLP, USAGE6); 422 exit(1); 423 } 424 } 425 426 if (elide && !iscodereview) { 427 fatal("-e option valid only with codereview"); 428 /*NOTREACHED*/ 429 } 430 usetmp = reverse || elide; 431 /* allocate page_map if we need one */ 432 if (reverse) { 433 page_map = malloc((size_t)(MAXPAGES * sizeof (long *))); 434 if (page_map == NULL) { 435 fatal("unable to allocate memory for page reversal"); 436 /*NOTREACHED*/ 437 } 438 } 439 440 /* 441 * Check that all files are readable 442 * This is so that no output at all is produced if any file is not 443 * readable in case the output is being piped to a printer 444 */ 445 first_file = optind; 446 for (j = first_file; j < argc; j++) { 447 if (access(argv[j], R_OK) == -1 && !(iscodereview && 448 strcmp(argv[j], "-") == 0)) { 449 fatal("cannot access %s", argv[j]); 450 /*NOTREACHED*/ 451 } 452 } 453 if (iscodereview && (first_file + 2) != argc) { 454 fatal("codereview: need old and new file"); 455 /*NOTREACHED*/ 456 } 457 458 /* compute logical point size, logical dimensions */ 459 if (!landscape) { 460 rot_text = layoutp->rotation; 461 start_y = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH; 462 start_x = START_X; 463 end_x = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH; 464 if (wflag) { 465 point_size = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH / 466 ((columns + 0.5) * DEFAULT_CHAR_WIDTH); 467 lines_per_page = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / 468 point_size; 469 } else { 470 point_size = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / 471 (lines_per_page + 0.5); 472 columns = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH / 473 (point_size * DEFAULT_CHAR_WIDTH); 474 } 475 } else { 476 rot_text = 90 - layoutp->rotation; 477 start_y = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH; 478 start_x = START_X; 479 end_x = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH; 480 if (wflag) { 481 point_size = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / 482 ((columns + 0.5) * DEFAULT_CHAR_WIDTH); 483 lines_per_page = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH / 484 point_size; 485 } else { 486 point_size = DEFAULT_PAGE_WIDTH * POINTS_PER_INCH / 487 (lines_per_page + 0.5); 488 columns = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / 489 (point_size * DEFAULT_CHAR_WIDTH); 490 } 491 } 492 493 box_height = DEFAULT_PAGE_HEIGHT * POINTS_PER_INCH / layoutp->page_rows; 494 if (layoutp->rotation == 0) 495 box_width = box_height / 496 DEFAULT_PAGE_HEIGHT * DEFAULT_PAGE_WIDTH; 497 else 498 box_width = box_height * 499 DEFAULT_PAGE_HEIGHT / DEFAULT_PAGE_WIDTH; 500 gap_width = DEFAULT_PAPER_WIDTH * POINTS_PER_INCH / 501 layoutp->page_cols - box_width; 502 gap_height = DEFAULT_PAPER_HEIGHT * POINTS_PER_INCH / 503 layoutp->page_rows - box_height; 504 margin_x = gap_width/2; 505 margin_y = gap_height/2; 506 507 columns -= numberwidth + DEFAULT_SPACES_AFTER_NUMBER; 508 if (columns <= 0) { 509 fatal("numbering width exceeds number of columns"); 510 /* NOT REACHED */ 511 } 512 /* compute physical "lower left corner" of each logical page */ 513 for (j = 0; j < layoutp->pages; j++) { 514 int phys_row; /* 0 is bottom row */ 515 int phys_col; /* 0 is left column */ 516 517 if (landscape == (rot_text == 0)) { 518 /* logical pages run physically up and down */ 519 phys_row = j % layoutp->page_rows; 520 phys_col = j / layoutp->page_rows; 521 } else { 522 /* logical pages run physically left to right */ 523 phys_row = j / layoutp->page_cols; 524 phys_col = j % layoutp->page_cols; 525 } 526 if (rot_text == 0) { 527 /* top physical row is logically first */ 528 phys_row = layoutp->page_rows - 1 - phys_row; 529 } 530 531 positions[j].base_x = margin_x + 532 phys_col * (box_width + gap_width); 533 positions[j].base_y = margin_y + 534 phys_row * (box_height + gap_height); 535 if (rot_text != 0) { 536 positions[j].base_x += box_width; 537 } 538 } 539 540 if (vflag) { 541 (void) fprintf(stderr, "%s:\n\n", progname); 542 (void) fprintf(stderr, "Lines/page = %d\n", lines_per_page); 543 (void) fprintf(stderr, "Columns = %d\n", columns); 544 for (j = 0; j < layoutp->pages; j++) { 545 (void) fprintf(stderr, "\tx=%3d, y=%3d\n", 546 positions[j].base_x, positions[j].base_y); 547 } 548 (void) fprintf(stderr, "box_width=%3d, box_height=%3d\n", 549 box_width, box_height); 550 (void) fprintf(stderr, "gap_width=%3d, gap_height=%3d\n", 551 gap_width, gap_height); 552 } 553 554 setup(); 555 preamble(); 556 557 if (iscodereview) { 558 char command[BUFSIZ]; 559 560 (void) snprintf(command, BUFSIZ, "diff -b -D %s %s %s", 561 CODEREVIEW, argv[first_file+1], argv[first_file]); 562 infile = popen(command, "r"); 563 bannerfile = argv[first_file+1]; 564 if (ungetc(getc(infile), infile) == EOF) { 565 (void) pclose(infile); 566 (void) sprintf(command, 567 "echo No differences encountered"); 568 infile = popen(command, "r"); 569 } 570 setheaderfile(bannerfile); 571 printfile(infile); 572 (void) pclose(infile); 573 } else if (first_file == argc) { /* no files on command line */ 574 if (vflag) 575 (void) fprintf(stderr, "\tprinting stdin\n"); 576 setheaderfile("stdin"); 577 printfile(stdin); 578 } else { 579 for (i = first_file; i < argc; i++) { 580 if ((infile = fopen(argv[i], "r")) == (FILE *)NULL) { 581 fatal("can't open %s for reading", argv[i]); 582 /*NOTREACHED*/ 583 } 584 if (pflag) { 585 char cmdbuf[BUFSIZ]; 586 (void) snprintf(cmdbuf, BUFSIZ, "pr %s", 587 argv[i]); 588 (void) fclose(infile); 589 infile = popen(cmdbuf, "r"); 590 } 591 if (vflag) 592 (void) fprintf(stderr, "\tprinting %s\n", 593 argv[i]); 594 setheaderfile(argv[i]); 595 printfile(infile); 596 if (pflag) 597 (void) pclose(infile); 598 else 599 (void) fclose(infile); 600 } 601 } 602 603 postamble(); 604 605 if (fflush(stdout) == EOF) { 606 fatal("write error on stdout"); 607 /*NOTREACHED*/ 608 } 609 exit(0); 610 /*NOTREACHED*/ 611 /*LINTED*/ 612 } 613 614 /* 615 * Initial lines sent to the LaserWriter 616 * Generates the PostScript header and includes the prologue file 617 * There is limited checking for I/O errors here 618 */ 619 void 620 preamble(void) 621 { 622 (void) printf("%%!PS-Adobe-2.0\n"); 623 (void) printf("%%%%Creator: %s on %s\n", progname, hostname); 624 (void) printf("%%%%CreationDate: %s\n", currentdate); 625 (void) printf("%%%%For: %s\n", username); 626 (void) printf("%%%%DocumentFonts: %s %s %s %s\n", 627 default_font, default_font_bold, 628 default_font_italic, default_font_bold_italic); 629 (void) printf("%%%%Pages: (atend)\n"); 630 631 if (prologue == NULL) { 632 char **cpp; 633 for (cpp = default_prologue; *cpp; cpp++) { 634 (void) fputs(*cpp, stdout); 635 } 636 } else { 637 FILE *fp; 638 if ((fp = fopen(prologue, "r")) == NULL) { 639 fatal("can't open prologue file %s", prologue); 640 /*NOTREACHED*/ 641 } 642 while (fgets(bufin, sizeof (bufin), fp) != NULL) 643 (void) fputs(bufin, stdout); 644 (void) fclose(fp); 645 } 646 if (ferror(stdout) || fflush(stdout) == EOF) { 647 fatal("write error on stdout"); 648 /*NOTREACHED*/ 649 } 650 651 (void) printf("/%s {%f /%s %s}bind def\n", DEFAULT_FONT, 652 point_size, default_font, SELECT_FONT); 653 (void) printf("/%s {%f /%s %s}bind def\n", DEFAULT_FONT_BOLD, 654 point_size, default_font_bold, SELECT_FONT); 655 (void) printf("/%s {%f /%s %s}bind def\n", DEFAULT_FONT_ITALIC, 656 point_size, default_font_italic, SELECT_FONT); 657 (void) printf("/%s {%f /%s %s}bind def\n", DEFAULT_FONT_BOLD_ITALIC, 658 point_size, default_font_bold_italic, SELECT_FONT); 659 } 660 661 void 662 postamble(void) 663 { 664 (void) printf("%%%%Trailer\n"); 665 (void) printf("%%%%Pages: %d\n", current.page_count); 666 } 667 668 int 669 printbanner(char *filename, FILE *outfile) 670 { 671 char buffer[BUFSIZ]; 672 struct stat statbuf; 673 struct format_state format_state; 674 int nlines = 0; 675 676 /* we've already verified readability */ 677 (void) stat(filename, &statbuf); 678 679 save_format_state(&format_state); 680 numberwidth = 0; 681 682 setcurrentfont(DEFAULT_FONT_BOLD_ITALIC, outfile); 683 684 current.row -= point_size; 685 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, MOVETO); 686 proc(banner, outfile); 687 nlines++; 688 689 current.row -= point_size; 690 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, MOVETO); 691 (void) snprintf(buffer, BUFSIZ, "%8ld %.24s", statbuf.st_size, 692 ctime(&statbuf.st_mtime)); 693 proc(buffer, outfile); 694 nlines++; 695 696 do { 697 current.row -= point_size; 698 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, 699 MOVETO); 700 filename += sprintf(buffer, "%.*s", columns, filename); 701 proc(buffer, outfile); 702 nlines++; 703 } while (strlen(filename) != 0); 704 705 if (comment != NULL && comment[0] != 0) { 706 const char *cur = comment; 707 const char *endl; 708 int len; 709 710 while (*cur != 0) { 711 current.row -= point_size; 712 (void) fprintf(outfile, "%d %.2f %s\n", start_x, 713 current.row, MOVETO); 714 715 endl = strchr(cur, '\n'); 716 if (endl == NULL) 717 endl = cur + strlen(cur); 718 719 /* truncate to columns */ 720 len = endl - cur; 721 if (len > columns) 722 len = columns; 723 (void) sprintf(buffer, "%.*s", len, cur); 724 proc(buffer, outfile); 725 nlines++; 726 727 if (*endl == 0) 728 break; 729 cur = endl + 1; 730 } 731 } 732 733 current.row -= point_size; 734 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, MOVETO); 735 proc(banner, outfile); 736 nlines++; 737 738 restore_format_state(&format_state, outfile); 739 savestate(outfile); 740 return (nlines); 741 } 742 743 void 744 setcurrentfont(char *newfont, FILE *outfile) 745 { 746 if (current.font != newfont) { 747 if (newfont) 748 current.font = newfont; 749 (void) fprintf(outfile, "%s\n", current.font); 750 } 751 } 752 753 void 754 savestate(FILE *f) 755 { 756 current.offset = ftell(f); 757 saved = current; 758 } 759 760 void 761 restorestate(FILE *f) 762 { 763 char *font; 764 765 font = current.font; 766 (void) fseek(f, saved.offset, 0); 767 current = saved; 768 setcurrentfont(font, f); 769 } 770 771 void 772 save_format_state(struct format_state *fs) 773 { 774 fs->numberwidth = numberwidth; 775 fs->linenumber = linenumber; 776 fs->altlinenumber = altlinenumber; 777 fs->makegray = makegray; 778 fs->font = current.font; 779 } 780 781 void 782 restore_format_state(struct format_state *fs, FILE *outfile) 783 { 784 numberwidth = fs->numberwidth; 785 linenumber = fs->linenumber; 786 altlinenumber = fs->altlinenumber; 787 makegray = fs->makegray; 788 setcurrentfont(fs->font, outfile); 789 } 790 791 /* 792 * Print a file 793 * 794 * The input stream may be stdin, a file, or a pipe 795 */ 796 void 797 printfile(FILE *infile) 798 { 799 int eof; 800 char *p; 801 FILE *outfile; 802 803 if (reverse) 804 page_map[0] = 0L; 805 if (usetmp) { 806 (void) snprintf(bufin, BUFIN, "/tmp/%sXXXXXX", progname); 807 p = mktemp(bufin); 808 if ((outfile = fopen(p, "w+")) == NULL) { 809 fatal("can't open temporary file %s", p); 810 /* NOTREACHED */ 811 } 812 if (!dflag) 813 (void) unlink(p); 814 else 815 (void) fprintf(stderr, "will not unlink %s\n", p); 816 } 817 else 818 outfile = stdout; 819 820 setcurrentfont(DEFAULT_FONT, outfile); 821 change_seen = 0; 822 dots_inserted = 0; 823 in_change = 0; 824 makegray = 0; 825 linenumber = 0; 826 altlinenumber = 0; 827 current.logical_page_count = 0; 828 do { 829 current.row = start_y; 830 eof = printpage(infile, outfile); 831 } while (!eof); 832 833 if (((int)current.row) != start_y) 834 endpage(outfile); 835 if ((current.logical_page_count % layoutp->pages) != 0) 836 flushpage(outfile); 837 if (vflag) 838 (void) fprintf(stderr, "\n"); 839 if (fflush(outfile) == EOF) { 840 fatal("write error while flushing output"); 841 /*NOTREACHED*/ 842 } 843 if (usetmp) { 844 if (reverse) 845 reversepages(outfile); 846 else 847 copypage(outfile, 0L, current.offset); 848 (void) fclose(outfile); 849 } 850 } 851 852 void 853 process_elide(FILE *outfile) 854 { 855 if (!change_seen && !in_change) { 856 /* don't include function in output */ 857 restorestate(outfile); 858 if (!dots_inserted) { 859 struct format_state format_state; 860 861 save_format_state(&format_state); 862 numberwidth = 0; 863 current.lineno++; 864 current.row -= point_size; 865 setcurrentfont(DEFAULT_FONT_BOLD_ITALIC, outfile); 866 proc("______unchanged_portion_omitted_", outfile); 867 restore_format_state(&format_state, outfile); 868 savestate(outfile); 869 dots_inserted = 1; 870 } 871 } else { 872 savestate(outfile); 873 change_seen = in_change; 874 dots_inserted = 0; 875 } 876 } 877 878 /* 879 * Process the next page 880 * Return 1 on EOF, 0 otherwise 881 */ 882 int 883 printpage(FILE *infile, FILE *outfile) 884 { 885 int tmplinenumber; 886 char command[BUFSIZ], flag[BUFSIZ]; 887 888 if (ungetc(getc(infile), infile) == EOF) 889 return (1); 890 891 current.lineno = 0; 892 current.lineno += startpage(outfile); 893 if (bannerfile) { 894 current.lineno += printbanner(bannerfile, outfile); 895 bannerfile = NULL; 896 } 897 for (; current.lineno < lines_per_page; ) { 898 if (fgetline(bufin, sizeof (bufin), infile) == (char *)NULL) { 899 if (elide) 900 process_elide(outfile); 901 return (1); 902 } 903 /* 904 * Allow C comment delimiters around flag; only really applies 905 * to #else and #endif, but we don't expect to see C comments 906 * around flag for #if. Also accept flag with no C comment 907 * delimiters. 908 */ 909 if (iscodereview && 910 (sscanf(bufin, "#%32s /* %80s */", command, flag) == 2 || 911 sscanf(bufin, "#%32s %80s", command, flag) == 2) && 912 strcmp(flag, CODEREVIEW) == 0) { 913 if (strcmp(command, "ifdef") == 0) { 914 change_seen = 1; 915 in_change = 1; 916 makegray = 1; 917 old_stuff = 1; 918 tmplinenumber = linenumber; 919 linenumber = altlinenumber; 920 altlinenumber = tmplinenumber; 921 setcurrentfont(DEFAULT_FONT_ITALIC, outfile); 922 } else if (strcmp(command, "ifndef") == 0) { 923 change_seen = 1; 924 in_change = 1; 925 makegray = 1; 926 old_stuff = 0; 927 setcurrentfont(DEFAULT_FONT_BOLD, outfile); 928 } else if (strcmp(command, "else") == 0) { 929 makegray = 1; 930 old_stuff = !old_stuff; 931 tmplinenumber = linenumber; 932 linenumber = altlinenumber; 933 altlinenumber = tmplinenumber; 934 if (!old_stuff) 935 setcurrentfont(DEFAULT_FONT_BOLD, 936 outfile); 937 else 938 setcurrentfont(DEFAULT_FONT_ITALIC, 939 outfile); 940 } else /* if (strcmp(command, "endif") == 0) */ { 941 in_change = 0; 942 makegray = 0; 943 savestate(outfile); 944 setcurrentfont(DEFAULT_FONT, outfile); 945 if (old_stuff) { 946 tmplinenumber = linenumber; 947 linenumber = altlinenumber; 948 altlinenumber = tmplinenumber; 949 } 950 } 951 continue; 952 } 953 current.lineno++; 954 current.row -= point_size; 955 if (bufin[0] == '\f') 956 break; 957 proc(bufin, outfile); 958 if (elide && (bufin[0] == END_C_FUNCTION || 959 (strstr(bufin, END_ASM_FUNCTION) != NULL))) 960 process_elide(outfile); 961 } 962 endpage(outfile); 963 return (0); 964 } 965 966 /* 967 * Start a new page 968 */ 969 int 970 startpage(FILE *outfile) 971 { 972 int logical_page, lines, buflen; 973 struct format_state format_state; 974 char buf[8]; 975 976 logical_page = current.logical_page_count % layoutp->pages; 977 978 if (logical_page == 0) 979 setuppage(outfile); 980 else 981 setcurrentfont((char *)NULL, outfile); 982 (void) fprintf(outfile, "%s ", SET_WIDTHS); 983 (void) fprintf(outfile, "%d %f %d %d %s\n", 984 rot_text, layoutp->scale, positions[logical_page].base_x, 985 positions[logical_page].base_y, START_PAGE); 986 lines = 0; 987 if (header) { 988 save_format_state(&format_state); 989 setcurrentfont(DEFAULT_FONT_BOLD, outfile); 990 numberwidth = 0; 991 makegray = 0; 992 993 current.row -= point_size; 994 (void) fprintf(outfile, "%d %.2f %s\n", start_x, current.row, 995 MOVETO); 996 proc(headerstring, outfile); 997 (void) snprintf(buf, 8, "%d", current.logical_page_count + 1); 998 buflen = strlen(buf); 999 (void) fprintf(outfile, "%d %.2f %s (%s)%s\n", 1000 (int)(end_x - (buflen + 0.5) * 1001 DEFAULT_CHAR_WIDTH * point_size), 1002 current.row, MOVETO, buf, SHOW); 1003 current.row -= point_size; 1004 restore_format_state(&format_state, outfile); 1005 lines = 2; 1006 } 1007 return (lines); 1008 } 1009 1010 void 1011 setheaderfile(char *filename) 1012 { 1013