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