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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * lwlp - Convert ASCII text to PostScript
30 * lwlp [-{2|4|8}] [-p] [-L] [-r] [-n#] [-l#|-w#] [-c#] [-t#]
31 * [-hstring] [-Bstring] [-Istring] [-Xstring] [-Pfile] [file ...]
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
52 * If no files are specified, stdin is used.
54 * Backspacing with underlining (or overprinting) works
55 * The output conforms to Adobe 2.0
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
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"
77 #include <sys/utsname.h>
80 #include <sys/types.h>
86 * BUFOUT should be fairly large
88 #define BUFIN 1024 /* maximum length of an input line */
89 #define BUFOUT (BUFIN * 5)
90 #define MAXPAGES 10000
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
115 #define CODEREVIEW "codereview"
116 #define END_C_FUNCTION '}'
117 #define END_ASM_FUNCTION "SET_SIZE("
118 static char *banner
=
119 "**********************************************************";
122 * PostScript command strings
124 #define LINETO "lineto"
125 #define NEWPATH "newpath"
126 #define SETLINEWIDTH "setlinewidth"
127 #define STROKE "stroke"
129 * PostScript command strings defined in the prologue file
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 */
144 * Conformance requires that no PostScript line exceed 256 characters
146 #define POINTS_PER_INCH 72
147 #define MAX_OUTPUT_LINE_LENGTH 256
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 */
154 static struct print_state
{
156 int logical_page_count
;
163 struct format_state
{
164 int numberwidth
, linenumber
, altlinenumber
;
169 static int change_seen
, dots_inserted
, in_change
, old_stuff
, makegray
;
170 static int lines_per_page
;
172 static float point_size
;
173 static int start_x
, start_y
, end_x
;
174 static int landscape
, rot_text
;
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
;
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 */
195 static char *username
, *hostname
, *currentdate
;
196 static char *comment
;
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
, ...);
221 static char *prologue
;
222 static char *progname
;
223 static int iscodereview
;
225 static char *default_prologue
[] = {
228 "% PostScript Prologue for lwlp LaserWriter Line Printer\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",
253 int pages
, page_rows
, page_cols
;
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 };
262 static int box_width
, box_height
;
263 static int gap_width
, gap_height
;
264 static int margin_x
, margin_y
;
266 static struct position
{
272 main(int argc
, char **argv
)
274 int ch
, i
, j
, first_file
;
278 if ((pc
= strrchr(argv
[0], '/')) != NULL
)
283 lines_per_page
= DEFAULT_LINES_PER_PAGE
;
285 tabstop
= DEFAULT_TAB_SIZE
;
286 current
.page_count
= 0;
288 reverse
= REVERSE_OFF
;
291 if (iscodereview
= strncmp(progname
, CODEREVIEW
,
292 sizeof (CODEREVIEW
) - 1) == 0) {
295 columns
= 85; /* extra space for numbering */
299 while ((ch
= getopt(argc
, argv
,
300 "1248B:c:deG:h:I:l:Ln:P:prt:vw:X:y:")) != -1) {
315 boldlength
= strlen(optarg
);
316 boldstring
= malloc((size_t)(boldlength
+ 1));
317 (void) strcpy(boldstring
, optarg
);
320 ncopies
= atof(optarg
);
322 fatal("number of copies must be > 0");
333 graylength
= strlen(optarg
);
334 graystring
= malloc((size_t)(graylength
+ 1));
335 (void) strcpy(graystring
, optarg
);
338 header
= HEADER_EXPLICIT
;
340 headerstring
= malloc((size_t)(i
+ 1));
341 (void) strcpy(headerstring
, optarg
);
342 if (strcmp(headerstring
, "-") == 0)
343 header
= HEADER_IMPLICIT
;
346 itlclength
= strlen(optarg
);
347 itlcstring
= malloc((size_t)(itlclength
+ 1));
348 (void) strcpy(itlcstring
, optarg
);
351 lines_per_page
= atoi(optarg
);
352 if (lines_per_page
< 1) {
353 fatal("invalid number of lines/page");
358 fatal("can't have both -l and -w");
369 numberwidth
= atoi(optarg
);
370 if (numberwidth
< 2) {
371 fatal("invalid numbering width");
385 tabstop
= atoi(optarg
);
387 fatal("negative tabstop");
395 columns
= atoi(optarg
);
397 fatal("invalid number of columns");
402 fatal("can't have both -l and -w");
407 bitclength
= strlen(optarg
);
408 bitcstring
= malloc((size_t)(bitclength
+ 1));
409 (void) strcpy(bitcstring
, optarg
);
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
);
420 (void) fprintf(stderr
, "\t%s [%s flags] %s\n",
421 CODEREVIEW
, LWLP
, USAGE6
);
426 if (elide
&& !iscodereview
) {
427 fatal("-e option valid only with codereview");
430 usetmp
= reverse
|| elide
;
431 /* allocate page_map if we need one */
433 page_map
= malloc((size_t)(MAXPAGES
* sizeof (long *)));
434 if (page_map
== NULL
) {
435 fatal("unable to allocate memory for page reversal");
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
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
]);
453 if (iscodereview
&& (first_file
+ 2) != argc
) {
454 fatal("codereview: need old and new file");
458 /* compute logical point size, logical dimensions */
460 rot_text
= layoutp
->rotation
;
461 start_y
= DEFAULT_PAGE_HEIGHT
* POINTS_PER_INCH
;
463 end_x
= DEFAULT_PAGE_WIDTH
* POINTS_PER_INCH
;
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
/
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
);
476 rot_text
= 90 - layoutp
->rotation
;
477 start_y
= DEFAULT_PAGE_WIDTH
* POINTS_PER_INCH
;
479 end_x
= DEFAULT_PAGE_HEIGHT
* POINTS_PER_INCH
;
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
/
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
);
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
;
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;
507 columns
-= numberwidth
+ DEFAULT_SPACES_AFTER_NUMBER
;
509 fatal("numbering width exceeds number of columns");
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 */
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
;
522 /* logical pages run physically left to right */
523 phys_row
= j
/ layoutp
->page_cols
;
524 phys_col
= j
% layoutp
->page_cols
;
527 /* top physical row is logically first */
528 phys_row
= layoutp
->page_rows
- 1 - phys_row
;
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
);
536 positions
[j
].base_x
+= box_width
;
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
);
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
);
558 char command
[BUFSIZ
];
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");
570 setheaderfile(bannerfile
);
572 (void) pclose(infile
);
573 } else if (first_file
== argc
) { /* no files on command line */
575 (void) fprintf(stderr
, "\tprinting stdin\n");
576 setheaderfile("stdin");
579 for (i
= first_file
; i
< argc
; i
++) {
580 if ((infile
= fopen(argv
[i
], "r")) == NULL
) {
581 fatal("can't open %s for reading", argv
[i
]);
586 (void) snprintf(cmdbuf
, BUFSIZ
, "pr %s",
588 (void) fclose(infile
);
589 infile
= popen(cmdbuf
, "r");
592 (void) fprintf(stderr
, "\tprinting %s\n",
594 setheaderfile(argv
[i
]);
597 (void) pclose(infile
);
599 (void) fclose(infile
);
605 if (fflush(stdout
) == EOF
) {
606 fatal("write error on stdout");
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
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");
631 if (prologue
== NULL
) {
633 for (cpp
= default_prologue
; *cpp
; cpp
++) {
634 (void) fputs(*cpp
, stdout
);
638 if ((fp
= fopen(prologue
, "r")) == NULL
) {
639 fatal("can't open prologue file %s", prologue
);
642 while (fgets(bufin
, sizeof (bufin
), fp
) != NULL
)
643 (void) fputs(bufin
, stdout
);
646 if (ferror(stdout
) || fflush(stdout
) == EOF
) {
647 fatal("write error on stdout");
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
);
664 (void) printf("%%%%Trailer\n");
665 (void) printf("%%%%Pages: %d\n", current
.page_count
);
669 printbanner(char *filename
, FILE *outfile
)
673 struct format_state format_state
;
676 /* we've already verified readability */
677 (void) stat(filename
, &statbuf
);
679 save_format_state(&format_state
);
682 setcurrentfont(DEFAULT_FONT_BOLD_ITALIC
, outfile
);
684 current
.row
-= point_size
;
685 (void) fprintf(outfile
, "%d %.2f %s\n", start_x
, current
.row
, MOVETO
);
686 proc(banner
, outfile
);
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
);
697 current
.row
-= point_size
;
698 (void) fprintf(outfile
, "%d %.2f %s\n", start_x
, current
.row
,
700 filename
+= sprintf(buffer
, "%.*s", columns
, filename
);
701 proc(buffer
, outfile
);
703 } while (strlen(filename
) != 0);
705 if (comment
!= NULL
&& comment
[0] != 0) {
706 const char *cur
= comment
;
711 current
.row
-= point_size
;
712 (void) fprintf(outfile
, "%d %.2f %s\n", start_x
,
713 current
.row
, MOVETO
);
715 endl
= strchr(cur
, '\n');
717 endl
= cur
+ strlen(cur
);
719 /* truncate to columns */
723 (void) sprintf(buffer
, "%.*s", len
, cur
);
724 proc(buffer
, outfile
);
733 current
.row
-= point_size
;
734 (void) fprintf(outfile
, "%d %.2f %s\n", start_x
, current
.row
, MOVETO
);
735 proc(banner
, outfile
);
738 restore_format_state(&format_state
, outfile
);
743 setcurrentfont(char *newfont
, FILE *outfile
)
745 if (current
.font
!= newfont
) {
747 current
.font
= newfont
;
748 (void) fprintf(outfile
, "%s\n", current
.font
);
755 current
.offset
= ftell(f
);
760 restorestate(FILE *f
)
765 (void) fseek(f
, saved
.offset
, 0);
767 setcurrentfont(font
, f
);
771 save_format_state(struct format_state
*fs
)
773 fs
->numberwidth
= numberwidth
;
774 fs
->linenumber
= linenumber
;
775 fs
->altlinenumber
= altlinenumber
;
776 fs
->makegray
= makegray
;
777 fs
->font
= current
.font
;
781 restore_format_state(struct format_state
*fs
, FILE *outfile
)
783 numberwidth
= fs
->numberwidth
;
784 linenumber
= fs
->linenumber
;
785 altlinenumber
= fs
->altlinenumber
;
786 makegray
= fs
->makegray
;
787 setcurrentfont(fs
->font
, outfile
);
793 * The input stream may be stdin, a file, or a pipe
796 printfile(FILE *infile
)
805 (void) snprintf(bufin
, BUFIN
, "/tmp/%sXXXXXX", progname
);
807 if ((outfile
= fopen(p
, "w+")) == NULL
) {
808 fatal("can't open temporary file %s", p
);
814 (void) fprintf(stderr
, "will not unlink %s\n", p
);
819 setcurrentfont(DEFAULT_FONT
, outfile
);
826 current
.logical_page_count
= 0;
828 current
.row
= start_y
;
829 eof
= printpage(infile
, outfile
);
832 if (((int)current
.row
) != start_y
)
834 if ((current
.logical_page_count
% layoutp
->pages
) != 0)
837 (void) fprintf(stderr
, "\n");
838 if (fflush(outfile
) == EOF
) {
839 fatal("write error while flushing output");
844 reversepages(outfile
);
846 copypage(outfile
, 0L, current
.offset
);
847 (void) fclose(outfile
);
852 process_elide(FILE *outfile
)
854 if (!change_seen
&& !in_change
) {
855 /* don't include function in output */
856 restorestate(outfile
);
857 if (!dots_inserted
) {
858 struct format_state format_state
;
860 save_format_state(&format_state
);
863 current
.row
-= point_size
;
864 setcurrentfont(DEFAULT_FONT_BOLD_ITALIC
, outfile
);
865 proc("______unchanged_portion_omitted_", outfile
);
866 restore_format_state(&format_state
, outfile
);
872 change_seen
= in_change
;
878 * Process the next page
879 * Return 1 on EOF, 0 otherwise
882 printpage(FILE *infile
, FILE *outfile
)
885 char command
[BUFSIZ
], flag
[BUFSIZ
];
887 if (ungetc(getc(infile
), infile
) == EOF
)
891 current
.lineno
+= startpage(outfile
);
893 current
.lineno
+= printbanner(bannerfile
, outfile
);
897 for (; current
.lineno
< lines_per_page
; ) {
898 if (fgetline(bufin
, sizeof (bufin
), infile
) == NULL
) {
900 process_elide(outfile
);
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
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) {
918 tmplinenumber
= linenumber
;
919 linenumber
= altlinenumber
;
920 altlinenumber
= tmplinenumber
;
921 setcurrentfont(DEFAULT_FONT_ITALIC
, outfile
);
922 } else if (strcmp(command
, "ifndef") == 0) {
927 setcurrentfont(DEFAULT_FONT_BOLD
, outfile
);
928 } else if (strcmp(command
, "else") == 0) {
930 old_stuff
= !old_stuff
;
931 tmplinenumber
= linenumber
;
932 linenumber
= altlinenumber
;
933 altlinenumber
= tmplinenumber
;
935 setcurrentfont(DEFAULT_FONT_BOLD
,
938 setcurrentfont(DEFAULT_FONT_ITALIC
,
940 } else /* if (strcmp(command, "endif") == 0) */ {
944 setcurrentfont(DEFAULT_FONT
, outfile
);
946 tmplinenumber
= linenumber
;
947 linenumber
= altlinenumber
;
948 altlinenumber
= tmplinenumber
;
954 current
.row
-= point_size
;
955 if (bufin
[0] == '\f')
957 proc(bufin
, outfile
);
958 if (elide
&& (bufin
[0] == END_C_FUNCTION
||
959 (strstr(bufin
, END_ASM_FUNCTION
) != NULL
)))
960 process_elide(outfile
);
970 startpage(FILE *outfile
)
972 int logical_page
, lines
, buflen
;
973 struct format_state format_state
;
976 logical_page
= current
.logical_page_count
% layoutp
->pages
;
978 if (logical_page
== 0)
981 setcurrentfont(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
);
988 save_format_state(&format_state
);
989 setcurrentfont(DEFAULT_FONT_BOLD
, outfile
);
993 current
.row
-= point_size
;
994 (void) fprintf(outfile
, "%d %.2f %s\n", start_x
, current
.row
,
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
);
1011 setheaderfile(char *filename
)
1013 if (header
== HEADER_IMPLICIT
)
1014 headerstring
= filename
;
1021 setuppage(FILE *outfile
)
1024 int begin
, end
, place
;
1026 (void) fprintf(outfile
, "%%%%Page: ? %d\n", current
.page_count
+ 1);
1027 setcurrentfont(NULL
, outfile
);
1028 if (layoutp
->pages
== 1)
1031 (void) fprintf(outfile
, "%f %s %s\n", RULE_WIDTH
, SETLINEWIDTH
,
1033 begin
= 0; end
= DEFAULT_PAPER_WIDTH
* POINTS_PER_INCH
;
1034 for (i
= 1, ilimit
= layoutp
->page_rows
; i
< ilimit
; i
++) {
1035 place
= margin_y
- gap_height
/2 + i
* (box_height
+gap_height
);
1036 (void) fprintf(outfile
, "%d %d %s ", begin
, place
, MOVETO
);
1037 (void) fprintf(outfile
, "%d %d %s\n", end
, place
, LINETO
);
1039 begin
= 0; end
= DEFAULT_PAPER_HEIGHT
* POINTS_PER_INCH
;
1040 for (i
= 1, ilimit
= layoutp
->page_cols
; i
< ilimit
; i
++) {
1041 place
= margin_x
- gap_width
/2 + i
* (box_width
+gap_width
);
1042 (void) fprintf(outfile
, "%d %d %s ", place
, begin
, MOVETO
);
1043 (void) fprintf(outfile
, "%d %d %s\n", place
, end
, LINETO
);
1045 (void) fprintf(outfile
, "%s\n", STROKE
);
1049 * Terminate the logical page and indicate the start of the next
1052 endpage(FILE *outfile
)
1054 (void) fprintf(outfile
, "%s\n", END_PAGE
);
1055 current
.logical_page_count
++;
1057 (void) fprintf(stderr
, "x");
1058 if ((current
.logical_page_count
% layoutp
->pages
) == 0)
1063 * Flush the physical page
1064 * Record the start of the next page
1067 flushpage(FILE *outfile
)
1069 (void) fprintf(outfile
, "%d %s\n", ncopies
, FLUSH_PAGE
);
1070 current
.page_count
++;
1071 current
.offset
= ftell(outfile
);
1073 if (current
.page_count
>= MAXPAGES
) {
1074 fatal("page reversal limit (%d) reached", MAXPAGES
);
1077 page_map
[current
.page_count
] = current
.offset
;
1080 (void) fprintf(stderr
, "|");
1084 * reverse the order of pages
1087 reversepages(FILE *outfile
)
1092 (void) fprintf(stderr
, "\nreversing %d page%s\n",
1093 current
.page_count
, current
.page_count
> 1 ? "s" : "");
1094 for (i
= current
.page_count
- 1; i
>= 0; i
--) {
1095 copypage(outfile
, page_map
[i
], page_map
[i
+1]);
1100 * copy a page (or more) from tempfile to stdout
1103 copypage(FILE *outfile
, long off_beg
, long off_end
)
1105 int bytecount
, nbytes
;
1107 if (fseek(outfile
, off_beg
, 0) == -1L) {
1108 fatal("temporary file seek error");
1111 nbytes
= off_end
- off_beg
;
1112 while (nbytes
> 0) {
1114 if (bytecount
> sizeof (bufout
))
1115 bytecount
= sizeof (bufout
);
1116 bytecount
= fread(bufout
, 1, bytecount
, outfile
);
1117 if (bytecount
<= 0) {
1118 fatal("temporary file read error");
1121 if (fwrite(bufout
, 1, bytecount
, stdout
) != bytecount
) {
1122 fatal("write error during page copy");
1125 nbytes
-= bytecount
;
1130 * Process a line of input, escaping characters when necessary and handling
1133 * The output is improved somewhat by coalescing consecutive tabs and
1134 * backspaces and eliminating tabs at the end of a line
1136 * Overprinting (presumably most often used in underlining) can be far from
1137 * optimal; in particular the way nroff underlines by sequences like
1138 * "_\ba_\bb_\bc" creates a large volume of PostScript. This isn't too
1139 * serious since a lot of nroff underlining is unlikely.
1141 * Since a newline is generated for each call there will be more
1142 * newlines in the output than is necessary
1145 proc(char *in
, FILE *outfile
)
1149 int currentp
, instr
, tabc
, tabto
, grayed
;
1157 altfont
= current
.font
;
1160 altfont
= DEFAULT_FONT
;
1162 /* subtract slop factor */
1163 last
= bufout
+ MAX_OUTPUT_LINE_LENGTH
- 20;
1164 for (;;) { /* check for any special line treatment */
1165 if (graylength
&& strncmp(in
, graystring
, graylength
) == 0) {
1168 } else if (boldlength
&&
1169 strncmp(in
, boldstring
, boldlength
) == 0) {
1170 altfont
= DEFAULT_FONT_BOLD
;
1172 } else if (itlclength
&&
1173 strncmp(in
, itlcstring
, itlclength
) == 0) {
1174 altfont
= DEFAULT_FONT_ITALIC
;
1176 } else if (bitclength
&&
1177 strncmp(in
, bitcstring
, bitclength
) == 0) {
1178 altfont
= DEFAULT_FONT_BOLD_ITALIC
;
1184 (void) fprintf(outfile
, "%d %.2f %d %.2f %s\n",
1186 current
.row
- DEFAULT_DESCENDER_FRACTION
* point_size
,
1189 (1.0 - DEFAULT_DESCENDER_FRACTION
) * point_size
,
1200 (void) fprintf(outfile
, "%d %.2f %s\n",
1201 start_x
, current
.row
, MOVETO
);
1204 (void) fprintf(outfile
, "%.2f %s\n",
1205 current
.row
, ZEROMOVETO
);
1207 setcurrentfont(DEFAULT_FONT
, outfile
);
1208 (void) sprintf(bufout
, "%*d", numberwidth
, linenumber
);
1209 for (q
= bufout
, i
= 0; *q
== ' '; q
++, i
++)
1211 (void) fprintf(outfile
, "%d %s (%s)%s %d %s ",
1212 i
, TAB
, q
, SHOW
, DEFAULT_SPACES_AFTER_NUMBER
, TAB
);
1214 setcurrentfont(altfont
, outfile
);
1218 for (p
= in
; *p
!= '\0'; p
++) {
1222 * Count the number of tabs that immediately follow
1223 * the one we're looking at
1226 while (*(p
+ 1) == '\t') {
1230 if (currentp
> 0) { /* not beginning of line */
1231 i
= tabstop
- (currentp
% tabstop
) +
1235 BUFOUT
- (q
- bufout
), ")%s ",
1242 i
= (tabc
+ 1) * tabstop
;
1247 /* backspacing over tabs doesn't work... */
1249 fatal("attempt to backspace over a tab");
1253 for (i
= 1; *p
== '\b'; p
++)
1256 if (currentp
- i
< 0) {
1257 fatal("too many backspaces");
1262 (void) fprintf(outfile
, "%s)%s\n",
1266 if (currentp
>= columns
)
1267 i
-= currentp
-columns
;
1269 /* backspace in truncated line */
1271 } else if (i
== 1) {
1272 /* frequent case gets special attention */
1273 (void) snprintf(bufout
, BUFOUT
, "%s ",
1276 (void) snprintf(bufout
, BUFOUT
, "-%d %s ", i
,
1278 q
= bufout
+ strlen(bufout
);
1282 tabto
= 0; /* optimizes */
1285 (void) fprintf(outfile
, "%s)%s\n",
1288 (void) fprintf(outfile
, "%s\n", bufout
);
1290 (void) startpage(outfile
);
1291 current
.row
= start_y
;
1292 (void) fprintf(outfile
, "%d %.2f %s\n",
1293 start_x
, current
.row
, MOVETO
);
1295 (void) fprintf(outfile
, "%d %s\n", numberwidth
+
1296 DEFAULT_SPACES_AFTER_NUMBER
, TAB
);
1302 tabto
= 0; /* optimizes */
1305 (void) fprintf(outfile
, "%s)%s\n",
1310 (void) fprintf(outfile
, "%d %.2f %s\n",
1311 start_x
, current
.row
, MOVETO
);
1313 (void) fprintf(outfile
, "%d %s\n", numberwidth
+
1314 DEFAULT_SPACES_AFTER_NUMBER
, TAB
);
1320 if (currentp
< columns
) {
1324 BUFOUT
- (q
- bufout
),
1325 "%d %s ", tabto
, TAB
);
1339 * According to the PostScript Language Manual,
1340 * PostScript files can contain only "the printable
1341 * subset of the ASCII character set (plus the
1347 if (currentp
< columns
) {
1351 BUFOUT
- (q
- bufout
),
1352 "%d %s ", tabto
, TAB
);
1359 if (!isascii(pchar
) || !isprint(pchar
)) {
1360 if (iscntrl(pchar
)) {
1361 if (pchar
== '\177')
1368 *q
++ = '0' + ((pchar
>>6) & 7);
1369 *q
++ = '0' + ((pchar
>>3) & 7);
1370 pchar
= '0' + (pchar
& 7);
1382 (void) fprintf(outfile
, "%s)%s\n", bufout
,
1385 (void) fprintf(outfile
, "%s\n", bufout
);
1391 (void) snprintf(q
, BUFOUT
- (q
- bufout
), ")%s", SHOW
);
1397 fatal("bufout overflow");
1400 if (bufout
[0] != '\0')
1401 (void) fprintf(outfile
, "%s\n", bufout
);
1405 * Initialize globals:
1406 * username - login name of user
1407 * hostname - name of machine on which lwlp is run
1408 * currentdate - what it says
1409 * Possible system dependencies here...
1417 struct utsname utsname
;
1420 if ((p
= getlogin()) == NULL
) {
1421 if ((pw
= getpwuid(getuid())) == NULL
)
1427 username
= strdup(p
);
1429 (void) uname(&utsname
);
1430 hostname
= strdup(utsname
.nodename
);
1432 t
= time((long *)0);
1435 *(p
+ len
- 1) = '\0'; /* zap the newline character */
1436 currentdate
= strdup(p
);
1437 current
.font
= DEFAULT_FONT
;
1441 * Special version of fgets
1442 * Read until a formfeed, newline, or overflow
1443 * If a formfeed is the first character, return it immediately
1444 * If a formfeed is found after the first character, replace it by a newline
1445 * and push the formfeed back onto the input stream
1446 * A special case is a formfeed followed by a newline in which case the
1447 * newline is ignored
1448 * The input buffer will be null-terminated and will *not* end with a newline
1449 * The buffer size n includes the null
1452 fgetline(char *s
, int n
, FILE *iop
)
1458 fatal("fgetline called with bad buffer size!?");
1466 * Check out the special cases
1468 if ((ch
= getc(iop
)) == EOF
)
1471 if ((ch
= getc(iop
)) != '\n') {
1473 * If EOF was just read it will be noticed
1476 if (ungetc(ch
, iop
) == EOF
&& !feof(iop
)) {
1478 * Shouldn't happen since a getc()
1481 fatal("fgetline - ungetc failed");
1491 * Check for "weird" input characters is made in proc()
1494 if (ch
== '\f' || ch
== '\n')
1497 if ((ch
= getc(iop
)) == EOF
)
1501 if (ch
== EOF
&& cs
== s
) /* Nothing was read */
1504 if (ungetc(ch
, iop
) == EOF
)
1505 (void) fprintf(stderr
, "fgetline - can't ungetc??\n");
1506 } else if (ch
!= '\n' && ch
!= EOF
) {
1507 fatal("fgetline - input line too long");
1516 fatal(char *fmt
, ...)
1520 (void) fprintf(stderr
, "%s: ", progname
);
1522 (void) vfprintf(stderr
, fmt
, ap
);
1524 (void) fprintf(stderr
, "\n");