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  * Copyright (c) 2016 by Delphix. All rights reserved.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 /*
32  *
33  * dpost - troff post-processor for PostScript printers.
34  *
35  * A program that translates output generated by the device independent troff
36  * into PostScript. Much was borrowed from dimpress and dps (formally dlzw),
37  * and even though the code has been changed, credit has to be given to Richard
38  * Flood for his early work on the PostScript driver.
39  *
40  * Among the most interesting new features are color support (see devcntrl() and
41  * file color.c) and code to handle complex paths pieced together using any of the
42  * standard drawing commands (see devcntrl() and file draw.c). Reverse video mode
43  * has also been included as a special case of the color support. Two encoding
44  * schemes based on widthshow are also new additions. The safe one is obtained when
45  * you set encoding to 2 (eg. using the -e2 option). The slightly faster method
46  * is obtained by setting encoding to 3 (eg. using the -e3 option), although it's
47  * not recommended. Rounding errors in character widths can accumulate and become
48  * quite noticeable by the time you get to the right margin. More often than not
49  * you end up getting a ragged right margin.
50  *
51  * The program handles files formatted for any device, although the best and
52  * most efficient output is generated when the font and description files match
53  * PostScript's resident fonts. Device emulation is relatively expensive, and
54  * can produce output files that are more than twice the size of the input files.
55  * In most cases output files will be smaller than input files, perhaps by up to
56  * 40 percent, although the results you get depend on what you're doing and the
57  * text encoding you're using. You'll get the worst results if you're emulating
58  * another device, using special bitmap characters, like the logo, or doing lots
59  * of vertical motion or drawing.
60  *
61  * PostScript fonts don't support all of troff's characters, so some have to
62  * be built by special PostScript procedures. Those routines can be found in
63  * *fontdir/devpost/charlib, and are only used when we try to print a character
64  * that has been assigned a code less than 32. Definitions are only made the
65  * first time each character is used. Subsequent requests to print the character
66  * only generate a call to the PostScript procedure that's been copied to the
67  * output file. For example you'll find a file called sq in directory
68  * *fontdir/devpost/charlib. It defines a PostScript procedure called build_sq
69  * that's called whenever we need to print a square. Special characters that
70  * have been assigned a code of 2 are expected to come in two pieces. The
71  * definition part and bitmap part (or whatever). The definition is only made
72  * once, but the contents of the character's .map file are copied to the output
73  * file each time, immediately after charlib() generates the call to the
74  * PostScript procedure (build_?? ) that builds the character. That's typically
75  * how logos built from bitmaps would be handled.
76  *
77  * Several different methods can be used to encode lines of text. What's done
78  * depends on the value assigned to encoding. Print time should decrease as
79  * encoding increases (up to MAXENCODING). Setting encoding to 0, which should
80  * probably be the default, produces output essentially identical to the original
81  * version of dpost. It's the slowest but most stable method of encoding lines of
82  * text, and won't be bothered by rounding errors in the font width tables that
83  * could become noticeable by the time you get to the end of a line. Other schemes
84  * seem to work, but aren't well tested and are not guaranteed for all possible
85  * jobs. encoding can be changed on the command line using the -e option. Part of
86  * the support for different encoding schemes was to move control of all text
87  * related output to separate routines. It makes dpost work harder, but changing
88  * things is easy. For example adding stuff to support widthshow took less than
89  * an hour.
90  *
91  * According to Adobe's structuring conventions, the output produced by dpost is
92  * still nonconforming. Global definitions that are occasionally made in individual
93  * pages are the primary problem. Among other things they handle downloading host
94  * resident fonts and defining special characters not generally available on
95  * PostScript printers. The approach used here works on a demand basis and violates
96  * page independence. A definition is made once in the first page that needs it
97  * and is bracketed by PostScript code that ensures the definition is exported to
98  * the global environment where it will be available for use by all the pages that
99  * follow.  Simple changes, like downloading definitions the first time they're
100  * used in each page, restores page independence but wouldn't be an efficient
101  * solution. Other approaches are also available, but every one I've considered
102  * sacrifices much in efficiency - just to maintain page independence. I'll leave
103  * things be for now. Global definitions made in individual pages are bracketed
104  * by %%BeginGlobal and %%EndGlobal comments and can easily be pulled out of
105  * individual pages and put in the prologue by utility programs like postreverse.
106  *
107  * I've also added code that handles the DOCUMENTFONTS comment, although it's
108  * only produced for those fonts in directory /usr/lib/font/devpost that have an
109  * associated .name file. The first string in a .name file should be the (long)
110  * PostScript name (eg. Times-Roman in R.name). For now everything else in the
111  * .name file is ignored, although that may also change. You'll find .name files
112  * for all the supported fonts in the devpost source directory, although they may
113  * not be installed in /usr/lib/font/devpost.
114  *
115  * The PostScript prologue is copied from *prologue before any of the input files
116  * are translated. The program expects the following procedures are avaliable:
117  *
118  *	setup
119  *
120  *	  mark ... setup -
121  *
122  *	    Handles special initialization stuff that depends on how the program
123  *	    was called. Expects to find a mark followed by key/value pairs on the
124  *	    stack. The def operator is applied to each pair up to the mark, then
125  *	    the default state is set up. An 'x res' command must preceed the
126  *	    'x init' command!
127  *
128  *	pagesetup
129  *
130  *	  page pagesetup -
131  *
132  *	    Called at the start of each page, immediately after the page level
133  *	    save, to do special initialization on a per page basis. Right now the
134  *	    only argument is the current page number, and actually nothing of any
135  *	    importance is currently done.
136  *
137  *	setdecoding
138  *
139  *	  num setdecoding -
140  *
141  *	    Selects the text decoding procedure (ie. what's assigned to PostScript
142  *	    procedure t) from the decodingdefs array defined in the prologue. num
143  *	    should be the value assigned to variable encoding (in dpost) and will
144  *	    remain constant throughout a job, unless special features, like reverse
145  *	    video printing, are requested. The text encoding scheme can be set on
146  *	    the command line using the -e option. Print time and the size of the
147  *	    output file will usually decrease as the value assigned to encoding
148  *	    increases.
149  *
150  *	f
151  *
152  *	  size font f -
153  *
154  *	    Selects the size and font to be used for character imaging. Font names
155  *	    are defined, in *prologue, so they agree with the one or two character
156  *	    names used by troff.
157  *
158  *	m
159  *
160  *	  x y m -
161  *
162  *	    Moves to point (x, y). Normally only used when the vertical position
163  *	    changes. Horizontal positioning between words (or letters) is handled
164  *	    in procedure t (below).
165  *
166  *	t
167  *
168  *	  mark text t mark
169  *
170  *	    Processes everything on the stack, up to the mark, as a single line
171  *	    of text to be printed at a fixed vertical position. What's put out as
172  *	    text depends on the encoding scheme. Setting encoding to 0 produces
173  *	    output essentially identical to the original version of dpost. In that
174  *	    case everything on the stack, up to a mark, is interpreted (from top
175  *	    down) as an absolute horizontal position and a string to be printed at
176  *	    that point. For example the stack might look like,
177  *
178  *		mark(this)1000(is)1100(an)1200(example)1300 t
179  *
180  *	    Procedure t would go through the stack, up to the mark, adjusting the
181  *	    horizontal position before printing each string. In other encoding
182  *	    schemes, like the one based on widthshow, strings containing several
183  *	    space separated words would appear on the stack, and each one would be
184  *	    preceeded by a number that's expected to be added to the width of a
185  *	    space. For example we might have,
186  *
187  *		mark(an example)30(this is)40 2 1000 2000 t
188  *
189  *	    where (1000, 2000) is where the first string starts and 2 is the repeat
190  *	    count (ie. number of string and space pairs on the stack).
191  *
192  *	w
193  *
194  *	  string x y w -
195  *
196  *	    Prints a single word starting at position (x, y). Only used in the more
197  *	    complicated encoding schemes (eg. the ones based on widthshow).
198  *
199  *	done
200  *
201  *	    Makes sure the last page is printed. Only needed when we're printing
202  *	    more than one page on each sheet of paper.
203  *
204  * The PostScript procedures that support troff's drawing commands have been moved
205  * out of *prologue and put in a separate file (ie. DRAW as defined in path.h).
206  * The procedures are used by the routines in file draw.c, and are copied to the
207  * output file at most once and only when needed. Yet another convenient violation
208  * of page independence. If you don't approve append *drawfile to *prologue and
209  * make sure *drawfile can't be read when DPOST runs.
210  *
211  * Many default values, like the magnification and orientation, are defined in
212  * the prologue, which is where they belong. If they're changed (by options), an
213  * appropriate definition is made after the prologue is added to the output file.
214  * The -P option passes arbitrary PostScript through to the output file. Among
215  * other things it can be used to set (or change) values that can't be accessed by
216  * other options.
217  *
218  *
219  * output language from troff:
220  * all numbers are character strings
221  *
222  * sn	size in points
223  * fn	font as number from 1-n
224  * cx	ascii character x
225  * Cxyz	funny char xyz. terminated by white space
226  * Hn	go to absolute horizontal position n
227  * Vn	go to absolute vertical position n (down is positive)
228  * hn	go n units horizontally (relative)
229  * vn	ditto vertically
230  * nnc	move right nn, then print c (exactly 2 digits!)
231  * 		(this wart is an optimization that shrinks output file size
232  * 		 about 35% and run-time about 15% while preserving ascii-ness)
233  * Dt ...\n	draw operation 't':
234  * 	Dl x y		line from here by x,y
235  * 	Dc d		circle of diameter d with left side here
236  * 	De x y		ellipse of axes x,y with left side here
237  *	Da x1 y1 x2 y2	arc counter-clockwise from current point (x, y) to
238  *			(x + x1 + x2, y + y1 + y2)
239  * 	D~ x y x y ...	wiggly line by x,y then x,y ...
240  * nb a	end of line (information only -- no action needed)
241  * 	b = space before line, a = after
242  * p	new page begins -- set v to 0
243  * #...\n	comment
244  * x ...\n	device control functions:
245  * 	x i	init
246  * 	x T s	name of device is s
247  * 	x r n h v	resolution is n/inch
248  * 		h = min horizontal motion, v = min vert
249  * 	x p	pause (can restart)
250  * 	x s	stop -- done forever
251  * 	x t	generate trailer
252  * 	x f n s	font position n contains font s
253  * 	x H n	set character height to n
254  * 	x S n	set slant to N
255  *
256  * 	Subcommands like "i" are often spelled out like "init".
257  *
258  */
259 
260 
261 #include	<stdio.h>
262 #include	<fcntl.h>
263 #include	<signal.h>
264 #include	<math.h>
265 #include	<ctype.h>
266 #include	<time.h>
267 
268 #include	"comments.h"		/* PostScript file structuring comments */
269 #include	"gen.h"			/* general purpose definitions */
270 #include	"path.h"		/* for the prologue and a few other files */
271 #include	"ext.h"			/* external variable definitions */
272 #include	"dev.h"			/* typesetter and font descriptions */
273 #include	"dpost.h"		/* a few definitions just used here */
274 
275 
276 char		*prologue = DPOST;	/* the basic PostScript prologue */
277 char		*colorfile = COLOR;	/* things needed for color support */
278 char		*drawfile = DRAW;	/* and drawing */
279 char		*formfile = FORMFILE;	/* stuff for multiple pages per sheet */
280 char		*baselinefile = BASELINE;
281 
282 char		*fontdir = FONTDIR;	/* binary device directories found here */
283 char		*hostfontdir = NULL;	/* host resident font directory */
284 
285 int		formsperpage = 1;	/* page images on each piece of paper */
286 int		copies = 1;		/* and this many copies of each sheet */
287 int		picflag = ON;		/* enable/disable picture inclusion */
288 
289 
290 /*
291  *
292  * encoding selects the encoding scheme used to output lines of text. Change it
293  * to something other than 0 at your own risk. The other methods seem to work but
294  * aren't well tested and are not guaranteed. Some special features, like reverse
295  * video, may temporarily change the encoding scheme and reset it to realencoding
296  * when done.
297  *
298  */
299 
300 
301 int		encoding = DFLTENCODING;
302 int		realencoding = DFLTENCODING;
303 int		maxencoding = MAXENCODING;
304 
305 
306 /*
307  *
308  * seenfonts[] keeps track of the fonts we've used, based on internal numbers. It
309  * helps manage host resident fonts and the DOCUMENTFONTS comment, but only works
310  * if all fonts have internal numbers less than MAXINTERNAL. *docfonts counts the
311  * number of font names we've recorded in *temp_file. If it's positive routine
312  * done() adds *temp_file to the output file before quitting.
313  *
314  */
315 
316 
317 char		seenfonts[MAXINTERNAL+1];
318 int		docfonts = 0;
319 
320 
321 /*
322  *
323  * devname[] is the device troff used when the job was formatted, while *realdev
324  * is combined with *fontdir and used to locate the font and device tables that
325  * that control the translation of the input files into PostScript. *realdev can
326  * be changed using the -T option, but if you do you may end up getting garbage.
327  * The character code field must agree with PostScript's font encoding and font
328  * names must be properly mapped into PostScript font names in the prologue.
329  *
330  */
331 
332 
333 char		devname[20] = "";	/* job is formatted for this printer */
334 char		*realdev = DEVNAME;	/* a good description of target printer */
335 
336 
337 /*
338  *
339  * Standard things that come from binary font and description files for *realdev.
340  * Most are initialized in fontinit() or loadfont().
341  *
342  */
343 
344 
345 struct dev	dev;			/* DESC.out starts this way */
346 struct Font	*fontbase[NFONT+1];	/* FONT.out files begin this way */
347 short		*pstab;			/* list of available sizes */
348 int		nsizes = 1;		/* and the number of sizes in that list */
349 int		smnt;			/* index of first special font */
350 int		nchtab;			/* number of special character names */
351 int		fsize;			/* max size of a font files in bytes */
352 int		unitwidth;		/* set to dev.unitwidth */
353 char		*chname;		/* special character strings */
354 short		*chtab;			/* used to locate character names */
355 char		*fitab[NFONT+1];	/* locates char info on each font */
356 char		*widthtab[NFONT+1];	/* character width data for each font */
357 char		*codetab[NFONT+1];	/* and codes to get characters printed */
358 
359 
360 /*
361  *
362  * Special characters missing from standard PostScript fonts are defined by files
363  * in directory *fontdir/devpost/charlib. Files have the same names as the troff
364  * special character names (for now at least) and each one defines a PostScript
365  * procedure that begins with the prefix build_ and ends with the character's
366  * name.
367  *
368  * For example, the routine used to build character \(12, would be build_12.
369  * downloaded[] points to an array, allocated in fontinit(), that keeps track of
370  * the characters that have already been defined - so we only do it once.
371  *
372  */
373 
374 
375 char		*downloaded;		/* nonzero means it's been downloaded */
376 
377 
378 /*
379  *
380  * Variables that keep track of troff's requests. All are set from values in the
381  * input files. nfonts is adjusted in t_fp() as new fonts are mounted.
382  *
383  */
384 
385 
386 int		nfonts = 0;		/* number of font positions */
387 int		size = 1;		/* current size - internal value */
388 int		font = 0;		/* font position we're using now */
389 int		hpos = 0;		/* where troff wants to be - horizontally */
390 int		vpos = 0;		/* same but vertically */
391 float		lastw = 0;		/* width of the last input character */
392 int		lastc = 0;		/* and its name (or index) */
393 
394 int		fontheight = 0;		/* points from x H ... */
395 int		fontslant = 0;		/* angle from x S ... */
396 
397 int		res;			/* resolution assumed in input file */
398 float		widthfac = 1.0;		/* for emulation = res/dev.res */
399 
400 
401 /*
402  *
403  * Remember some of the same things, but this time for the printer. lastend is only
404  * used when we're doing reverse video, and is where the last character on the
405  * current line was printed.
406  *
407  */
408 
409 
410 int		lastsize = -1;		/* last internal size we used */
411 int		lastfont = -1;		/* last font we told printer about */
412 float		lastx = -1;		/* printer's current position */
413 int		lasty = -1;
414 int		lastend;		/* where last character on this line was */
415 
416 
417 /*
418  *
419  * fontname[] keeps track of the mounted fonts. Filled in (by t_fp()) from data
420  * in the binary font files.
421  *
422  */
423 
424 
425 struct  {
426 
427 	char	*name;			/* name of the font loaded here */
428 	int	number;			/* its internal number */
429 
430 } fontname[NFONT+1] = {NULL, 0};
431 
432 
433 /*
434  *
435  * All the special fonts will be mounted after the last legitimate font position.
436  * It helps when we're translating files prepared for devices, like the 202, that
437  * have a different set of special fonts. The set of special fonts needed when
438  * *realdev's tables are used may not get mounted when we're emulating another
439  * device. gotspecial keeps track of whether we've done it yet. seenpage is set
440  * to TRUE after we've seen the first page command in the input file. It controls
441  * what's done in t_font() and is needed because nfonts is no longer set when the
442  * DESC.out file is read, but rather is updated from "x font" commands in the
443  * input files.
444  *
445  */
446 
447 
448 int		gotspecial = FALSE;
449 int		seenpage = FALSE;
450 
451 
452 /*
453  *
454  * The amount of horizontal positioning error we accept controls both the size
455  * of the output file and the appearance of the printed text. It's probably most
456  * important when we're emulating other devices, like the APS-5. The error can be
457  * set using the -S option. It's converted from points to machine units in t_init()
458  * after the resolution is known. rvslop is also set in t_init() and only used to
459  * adjust the width of the box that's drawn around text when we're printing in
460  * reverse video mode.
461  *
462  */
463 
464 
465 float		pointslop = SLOP;	/* horizontal error in points */
466 int		slop;			/* and machine units */
467 int		rvslop;			/* to extend box in reverse video mode */
468 
469 
470 /*
471  *
472  * Characters are accumulated and saved in PostScript strings that are eventually
473  * processed by making a single call to procedure t. textcount counts the number
474  * of individual strings collected but not yet processed, and is primarily used to
475  * make sure PostScript's stack doesn't get too big. When textcount is positive
476  * we've started accumulating strings and need to generate a call to PostScript
477  * procedure t to process the text before anything else (like a font change) is
478  * done.
479  *
480  */
481 
482 
483 int		textcount = 0;		/* strings accumulated so far */
484 int		stringstart = 0;	/* where the next one starts */
485 int		spacecount = 0;		/* spaces seen so far on current line */
486 
487 
488 /*
489  *
490  * Things that can be used by text line encoding schemes that need to read and
491  * remember an entire line before doing any output. The strings that make up the
492  * line can be saved in array strings[] and accessed by fields in line[]. *strptr
493  * points to the next free slot in strings[].
494  *
495  */
496 
497 
498 char		strings[STRINGSPACE];
499 char		*strptr;
500 Line		line[MAXSTACK+3];
501 
502 
503 /*
504  *
505  * When we're emulating another device we may want to map font name requests that
506  * come in as "x font pos name" commands into some other font name before anything
507  * else is done (ie. calling loadfont()). Font names can collide or we may just
508  * want to a mapping that depends on the device troff used to format the input
509  * files. devfontmap points to a structure that's filled in by getdevmap() if the
510  * mapping file /usr/lib/font/dev*realdev/fontmaps/devname exists. mapdevfont()
511  * then uses that table to translate font name requests into something else before
512  * loadfont() gets called.
513  *
514  * fontmap[] provides a simple minded translation that maps an unrecognized font
515  * name (in loadfont()) into another font name that we know will be available. It
516  * doesn't provide the fine control available with *devfontmap, but should be good
517  * enough for most jobs. Both structures are only needed when emulating another
518  * device using *realdev's font tables.
519  *
520  */
521 
522 
523 Devfontmap	*devfontmap = NULL;	/* device level */
524 Fontmap		fontmap[] = FONTMAP;	/* and general mapping tables - emulation */
525 
526 
527 /*
528  *
529  * A few variables that are really only used if we're doing accounting. Designed
530  * for our use at Murray Hill and probably won't suit your needs. Changes should
531  * be easy and can be made in routine account().
532  *
533  */
534 
535 
536 int		printed = 0;		/* charge for this many pages */
537 
538 
539 /*
540  *
541  * Output and accounting file definitions. The PostScript output always goes to
542  * stdout or /dev/null, while the accounting file can be selected using the -A
543  * option.
544  *
545  */
546 
547 
548 FILE		*tf = NULL;		/* PostScript output goes here */
549 FILE		*fp_acct = NULL;	/* accounting stuff written here */
550 
551 
552 /*
553  *
554  * Need the list of valid options in header() and options(), so I've moved the
555  * definition here.
556  *
557  */
558 
559 
560 char		*optnames = "a:c:e:m:n:o:p:tw:x:y:A:C:J:F:H:L:OP:R:S:T:DI";
561 
562 
563 /*
564  *
565  * Very temporary space that can be used to do things like building up pathnames
566  * immediately before opening a file. Contents may not be preserved across calls
567  * to subroutines defined in this file, so it probably should only be used in low
568  * level subroutines like loadfont() or fontinit() and nowhere else.
569  *
570  */
571 
572 
573 char		temp[150];
574 
575 static void account(void);
576 static void addchar(int);
577 static void addoctal(int);
578 static void arguments(void);
579 static void charlib(int);
580 static void conv(FILE *);
581 static void devcntrl(FILE *);
582 static void documentfonts(void);
583 static void done(void);
584 static void endline(void);
585 static void endstring(void);
586 void endtext(void);
587 static void fontinit(void);
588 static void fontprint(int);
589 static void getdevmap(void);
590 static void header(void);
591 void hgoto(int);
592 static void hmot(int);
593 static void init_signals(void);
594 static void loaddefault(void);
595 static void loadfont(int, char *, char *);
596 static void loadspecial(void);
597 static void options(void);
598 static void oput(int);
599 static void put1(int);
600 static void put1s(char *);
601 static void redirect(int);
602 void reset(void);
603 void resetpos(void);
604 static void setfont(int);
605 static void setpaths(char *);
606 static void setsize(int);
607 static void setup(void);
608 static void starttext(void);
609 static void t_charht(int);
610 static void t_fp(int, char *, char *);
611 static void t_init(void);
612 static void t_newline(void);
613 static void t_page(int);
614 static void t_reset(int);
615 void t_sf(void);
616 static void t_slant(int);
617 static void t_trailer(void);
618 void vgoto(int);
619 static void vmot(int);
620 
621 
622 /*****************************************************************************/
623 
624 
625 int
main(int agc,char * agv[])626 main(int agc, char *agv[])
627 {
628 
629 /*
630  *
631  * A program that translates troff output into PostScript. All the input files
632  * must have been formatted for the same device, which doesn't necessarily have to
633  * be *realdev. If there's more than one input file, each begins on a new page.
634  *
635  */
636 
637 
638     argc = agc;				/* global so everyone can use them */
639     argv = agv;
640 
641     prog_name = argv[0];		/* just for error messages */
642 
643     init_signals();			/* sets up interrupt handling */
644     header();				/* PostScript file structuring comments */
645     options();				/* command line options */
646     arguments();			/* translate all the input files */
647     done();				/* add trailing comments etc. */
648     account();				/* job accounting data */
649 
650     return (x_stat);			/* everything probably went OK */
651 
652 }   /* End of main */
653 
654 
655 /*****************************************************************************/
656 
657 
658 static void
init_signals(void)659 init_signals(void)
660 {
661     void	interrupt();		/* signal handler */
662 
663 /*
664  *
665  * Make sure we handle interrupts.
666  *
667  */
668 
669 
670     if ( signal(SIGINT, interrupt) == SIG_IGN )  {
671 	signal(SIGINT, SIG_IGN);
672 	signal(SIGQUIT, SIG_IGN);
673 	signal(SIGHUP, SIG_IGN);
674     } else {
675 	signal(SIGHUP, interrupt);
676 	signal(SIGQUIT, interrupt);
677     }   /* End else */
678 
679     signal(SIGTERM, interrupt);
680 
681 }   /* End of init_signals */
682 
683 
684 /*****************************************************************************/
685 
686 static void
header(void)687 header(void)
688 {
689 
690 
691     int		ch;			/* return value from getopt() */
692     int		old_optind = optind;	/* for restoring optind - should be 1 */
693 
694 
695 /*
696  *
697  * Scans the option list looking for things, like the prologue file, that we need
698  * right away but could be changed from the default. Doing things this way is an
699  * attempt to conform to Adobe's latest file structuring conventions. In particular
700  * they now say there should be nothing executed in the prologue, and they have
701  * added two new comments that delimit global initialization calls. Once we know
702  * where things really are we write out the job header, follow it by the prologue,
703  * and then add the ENDPROLOG and BEGINSETUP comments.
704  *
705  */
706 
707 
708     while ( (ch = getopt(argc, argv, optnames)) != EOF )
709 	if ( ch == 'L' )
710 	    setpaths(optarg);
711 	else if ( ch == '?' )
712 	    error(FATAL, "");
713 
714     optind = old_optind;		/* get ready for option scanning */
715 
716     fprintf(stdout, "%s", NONCONFORMING);
717     fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
718     fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
719     fprintf(stdout, "%s %s\n", PAGES, ATEND);
720     fprintf(stdout, "%s", ENDCOMMENTS);
721 
722     if ( cat(prologue) == FALSE )
723 	error(FATAL, "can't read %s", prologue);
724 
725     fprintf(stdout, "%s", ENDPROLOG);
726     fprintf(stdout, "%s", BEGINSETUP);
727     fprintf(stdout, "mark\n");
728 
729 }   /* End of header */
730 
731 
732 /*****************************************************************************/
733 
734 
735 static void
options(void)736 options(void)
737 {
738     int		ch;			/* name returned by getopt() */
739 
740     extern char	*optarg;		/* option argument set by getopt() */
741     extern int	optind;
742 
743 /*
744  *
745  * Reads and processes the command line options. There are, without a doubt, too
746  * many options!
747  *
748  */
749 
750 
751     while ( (ch = getopt(argc, argv, optnames)) != EOF )  {
752 
753 	switch ( ch )  {
754 
755 	    case 'a':			/* aspect ratio */
756 		    fprintf(stdout, "/aspectratio %s def\n", optarg);
757 		    break;
758 
759 	    case 'c':			/* number of copies */
760 		    copies = atoi(optarg);
761 		    fprintf(stdout, "/#copies %s store\n", optarg);
762 		    break;
763 
764 	    case 'e':			/* change the encoding scheme */
765 		    if ( (encoding = atoi(optarg)) < 0 || encoding > MAXENCODING )
766 			encoding = DFLTENCODING;
767 		    realencoding = encoding;
768 		    break;
769 
770 	    case 'm':			/* magnification */
771 		    fprintf(stdout, "/magnification %s def\n", optarg);
772 		    break;
773 
774 	    case 'n':			/* forms per page */
775 		    formsperpage = atoi(optarg);
776 		    fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
777 		    fprintf(stdout, "/formsperpage %s def\n", optarg);
778 		    break;
779 
780 	    case 'o':			/* output page list */
781 		    out_list(optarg);
782 		    break;
783 
784 	    case 'p':			/* landscape or portrait mode */
785 		    if ( *optarg == 'l' )
786 			fprintf(stdout, "/landscape true def\n");
787 		    else fprintf(stdout, "/landscape false def\n");
788 		    break;
789 
790 	    case 't':			/* just for compatibility */
791 		    break;
792 
793 	    case 'w':			/* line width for drawing */
794 		    fprintf(stdout, "/linewidth %s def\n", optarg);
795 		    break;
796 
797 	    case 'x':			/* shift horizontally */
798 		    fprintf(stdout, "/xoffset %s def\n", optarg);
799 		    break;
800 
801 	    case 'y':			/* and vertically on the page */
802 		    fprintf(stdout, "/yoffset %s def\n", optarg);
803 		    break;
804 
805 	    case 'A':			/* force job accounting */
806 	    case 'J':
807 		    if ( (fp_acct = fopen(optarg, "a")) == NULL )
808 			error(FATAL, "can't open accounting file %s", optarg);
809 		    break;
810 
811 	    case 'C':			/* copy file to straight to output */
812 		    if ( cat(optarg) == FALSE )
813 			error(FATAL, "can't read %s", optarg);
814 		    break;
815 
816 	    case 'F':			/* font table directory */
817 		    fontdir = optarg;
818 		    break;
819 
820 	    case 'H':			/* host resident font directory */
821 		    hostfontdir = optarg;
822 		    break;
823 
824 	    case 'L':			/* PostScript prologue file */
825 		    setpaths(optarg);	/* already been done in header() */
826 		    break;
827 
828 	    case 'O':			/* turn picture inclusion off */
829 		    picflag = OFF;
830 		    break;
831 
832 	    case 'P':			/* PostScript pass through */
833 		    fprintf(stdout, "%s\n", optarg);
834 		    break;
835 
836 	    case 'R':			/* special global or page level request */
837 		    saverequest(optarg);
838 		    break;
839 
840 	    case 'S':			/* horizontal position error */
841 		    if ( (pointslop = atof(optarg)) < 0 )
842 			pointslop = 0;
843 		    break;
844 
845 	    case 'T':			/* target printer */
846 		    realdev = optarg;
847 		    break;
848 
849 	    case 'D':			/* debug flag */
850 		    debug = ON;
851 		    tf = stdout;
852 		    break;
853 
854 	    case 'I':			/* ignore FATAL errors */
855 		    ignore = ON;
856 		    break;
857 
858 	    case '?':			/* don't know the option */
859 		    error(FATAL, "");
860 		    break;
861 
862 	    default:
863 		    error(FATAL, "missing case for option %c", ch);
864 		    break;
865 
866 	}   /* End switch */
867     }	/* End while */
868 
869     argc -= optind;			/* get ready for non-options args */
870     argv += optind;
871 
872 }   /* End of options */
873 
874 
875 /*****************************************************************************/
876 
877 
878 static void
setpaths(char * name)879 setpaths(char *name)
880     /* string that followed the -L option */
881 {
882     char	*path;			/* start of the pathname */
883 
884 /*
885  *
886  * Extends the -L option to permit run time modification of pathnames that were
887  * fixed or didn't exist in previous versions of dpost. For example, the PostScript
888  * drawing procedures have been moved out of *prologue and put in *drawfile. The
889  * new syntax can be either -Lfile or -Lname:file. If the "name:" prefix is omitted
890  * file will be used as the prologue, otherwise name should be one of "prologue",
891  * "font", "draw", "color", or "form" and is used to select the pointer that gets
892  * set to string "file".
893  *
894  */
895 
896 
897     for ( path = name; *path; path++ )
898 	if ( *path == ':' || *path == ' ' )  {
899 	    while ( *path == ':' || *path == ' ' ) path++;
900 	    break;
901 	}   /* End if */
902 
903     if ( *path == '\0' )		/* didn't find a "name:" prefix */
904 	path = name;
905 
906     if ( path == name || strncmp(name, "prologue", strlen("prologue")) == 0 )
907 	prologue = path;
908     else if ( strncmp(name, "draw", strlen("draw")) == 0 )
909 	drawfile = path;
910     else if ( strncmp(name, "color", strlen("color")) == 0 )
911 	colorfile = path;
912     else if ( strncmp(name, "form", strlen("form")) == 0 )
913 	formfile = path;
914     else if ( strncmp(name, "baseline", strlen("baseline")) == 0 )
915 	baselinefile = path;
916 
917 }   /* End of setpaths */
918 
919 
920 /*****************************************************************************/
921 
922 
923 static void
setup(void)924 setup(void)
925 {
926 
927 /*
928  * Handles things that must be done after the options are read but before the
929  * input files are processed. Called from t_init() after an "x init" command is
930  * read, because we need the resolution before we can generate the call to the
931  * setup procedure defined in *prologue. Only allowing one call to setup assumes
932  * all the input files have been prepared for the same device.
933  *
934  */
935 
936 
937     writerequest(0, stdout);		/* global requests eg. manual feed */
938     fprintf(stdout, "/resolution %d def\n", res);
939     fprintf(stdout, "setup\n");
940     fprintf(stdout, "%d setdecoding\n", encoding);
941 
942     if ( formsperpage > 1 )  {		/* followed by stuff for multiple pages */
943 	if ( cat(formfile) == FALSE )
944 	    error(FATAL, "can't read %s", formfile);
945 	fprintf(stdout, "%d setupforms\n", formsperpage);
946     }	/* End if */
947 
948     fprintf(stdout, "%s", ENDSETUP);
949 
950 }   /* End of setup */
951 
952 
953 /*****************************************************************************/
954 
955 
956 static void
arguments(void)957 arguments(void)
958 {
959     FILE	*fp;			/* next input file */
960 
961 /*
962  *
963  * Makes sure all the non-option command line arguments are processed. If we get
964  * here and there aren't any arguments left, or if '-' is one of the input files
965  * we'll translate stdin.
966  *
967  */
968 
969 
970     if ( argc < 1 )
971 	conv(stdin);
972     else
973 	while ( argc > 0 ) {
974 	    if ( strcmp(*argv, "-") == 0 )
975 		fp = stdin;
976 	    else if ( (fp = fopen(*argv, "r")) == NULL )
977 		error(FATAL, "can't open %s", *argv);
978 	    conv(fp);
979 	    if ( fp != stdin )
980 		fclose(fp);
981 	    argc--;
982 	    argv++;
983 	}   /* End while */
984 
985 }   /* End of arguments */
986 
987 
988 /*****************************************************************************/
989 
990 
991 static void
done(void)992 done(void)
993 {
994 
995 /*
996  *
997  * Finished with all the input files, so mark the end of the pages with a TRAILER
998  * comment, make sure the last page prints, and add things like the DOCUMENTFONTS
999  * and PAGES comments that can only be determined after all the input files have
1000  * been read.
1001  *
1002  */
1003 
1004 
1005     fprintf(stdout, "%s", TRAILER);
1006     fprintf(stdout, "done\n");
1007 
1008     if ( temp_file != NULL )  {
1009 	if ( docfonts > 0 )  {
1010 	    cat(temp_file);
1011 	    putc('\n', stdout);
1012 	}   /* End if */
1013 	unlink(temp_file);
1014     }	/* End if */
1015 
1016     fprintf(stdout, "%s %d\n", PAGES, printed);
1017 
1018 }   /* End of done */
1019 
1020 
1021 /*****************************************************************************/
1022 
1023 
1024 static void
account(void)1025 account(void)
1026 {
1027 
1028 /*
1029  *
1030  * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is
1031  * requested using the -A or -J options.
1032  *
1033  */
1034 
1035     if ( fp_acct != NULL )
1036 	fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
1037 
1038 }   /* End of account */
1039 
1040 
1041 /*****************************************************************************/
1042 
1043 
1044 static void
conv(FILE * fp)1045 conv(FILE *fp)
1046     /* next input file */
1047 {
1048     int			c;		/* usually first char in next command */
1049     int			m, n, n1, m1;	/* when we need to read integers */
1050     char		str[50];	/* for special chars and font numbers */
1051 
1052 
1053 /*
1054  *
1055  * Controls the translation of troff's device independent output language into
1056  * PostScript. The call to t_page() that prints the last page is made when we
1057  * exit the loop, but probably belongs in t_trailer().
1058  *
1059  */
1060 
1061 
1062     redirect(-1);			/* only do output after a page command */
1063     lineno = 1;				/* line in current file */
1064 
1065     while ((c = getc(fp)) != EOF)  {
1066 
1067 	switch (c)  {
1068 
1069 	    case '\n':			/* just count this line */
1070 		    lineno++;
1071 		    break;
1072 
1073 	    case ' ':			/* when input is text */
1074 	    case 0:			/* occasional noise creeps in */
1075 		    break;
1076 
1077 	    case '0': case '1': case '2': case '3': case '4':
1078 	    case '5': case '6': case '7': case '8': case '9':
1079 		    /* two motion digits plus a character */
1080 		    hmot((c-'0')*10 + getc(fp)-'0');
1081 		    put1(getc(fp));
1082 		    break;
1083 
1084 	    case 'c':			/* single ascii character */
1085 		    put1(getc(fp));
1086 		    break;
1087 
1088 	    case 'C':			/* special character */
1089 		    fscanf(fp, "%s", str);
1090 		    put1s(str);
1091 		    break;
1092 
1093 	    case 'N':			/* character at position n */
1094 		    fscanf(fp, "%d", &m);
1095 		    endtext();
1096 		    oput(m);
1097 		    break;
1098 
1099 	    case 'D':			/* drawing functions */
1100 		    endtext();
1101 		    getdraw();
1102 		    if ( size != lastsize )
1103 			t_sf();
1104 		    switch ((c=getc(fp))) {
1105 			case 'p':	/* draw a path */
1106 			    while (fscanf(fp, "%d %d", &n, &m) == 2)
1107 				drawline(n, m);
1108 			    lineno++;
1109 			    break;
1110 
1111 			case 'l':	/* draw a line */
1112 			    fscanf(fp, "%d %d %c", &n, &m, &n1);
1113 			    drawline(n, m);
1114 			    break;
1115 
1116 			case 'c':	/* circle */
1117 			    fscanf(fp, "%d", &n);
1118 			    drawcirc(n);
1119 			    break;
1120 
1121 			case 'e':	/* ellipse */
1122 			    fscanf(fp, "%d %d", &m, &n);
1123 			    drawellip(m, n);
1124 			    break;
1125 
1126 			case 'a':	/* counter-clockwise arc */
1127 			case 'A':	/* clockwise arc */
1128 			    fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1);
1129 			    drawarc(n, m, n1, m1, c);
1130 			    break;
1131 
1132 			case 'q':	/* spline without end points */
1133 			    drawspline(fp, 1);
1134 			    lineno++;
1135 			    break;
1136 
1137 			case '~':	/* wiggly line */
1138 			    drawspline(fp, 2);
1139 			    lineno++;
1140 			    break;
1141 
1142 			default:
1143 			    error(FATAL, "unknown drawing function %c", c);
1144 			    break;
1145 		    }	/* End switch */
1146 		    break;
1147 
1148 	    case 's':			/* use this point size */
1149 		    fscanf(fp, "%d", &n);	/* ignore fractional sizes */
1150 		    setsize(t_size(n));
1151 		    break;
1152 
1153 	    case 'f':			/* use font mounted here */
1154 		    fscanf(fp, "%s", str);
1155 		    setfont(t_font(str));
1156 		    break;
1157 
1158 	    case 'H':			/* absolute horizontal motion */
1159 		    fscanf(fp, "%d", &n);
1160 		    hgoto(n);
1161 		    break;
1162 
1163 	    case 'h':			/* relative horizontal motion */
1164 		    fscanf(fp, "%d", &n);
1165 		    hmot(n);
1166 		    break;
1167 
1168 	    case 'w':			/* word space */
1169 		    break;
1170 
1171 	    case 'V':			/* absolute vertical position */
1172 		    fscanf(fp, "%d", &n);
1173 		    vgoto(n);
1174 		    break;
1175 
1176 	    case 'v':			/* relative vertical motion */
1177 		    fscanf(fp, "%d", &n);
1178 		    vmot(n);
1179 		    break;
1180 
1181 	    case 'p':			/* new page */
1182 		    fscanf(fp, "%d", &n);
1183 		    t_page(n);
1184 		    break;
1185 
1186 	    case 'n':			/* end of line */
1187 		    while ( (c = getc(fp)) != '\n'  &&  c != EOF ) ;
1188 		    t_newline();
1189 		    lineno++;
1190 		    break;
1191 
1192 	    case '#':			/* comment */
1193 		    while ( (c = getc(fp)) != '\n'  &&  c != EOF ) ;
1194 		    lineno++;
1195 		    break;
1196 
1197 	    case 'x':			/* device control function */
1198 		    devcntrl(fp);
1199 		    lineno++;
1200 		    break;
1201 
1202 	    default:
1203 		    error(FATAL, "unknown input character %o %c", c, c);
1204 		    done();
1205 
1206 	}   /* End switch */
1207 
1208     }	/* End while */
1209 
1210     t_page(-1);				/* print the last page */
1211     endtext();
1212 
1213 }   /* End of conv */
1214 
1215 
1216 /*****************************************************************************/
1217 
1218 
1219 static void
devcntrl(FILE * fp)1220 devcntrl(FILE *fp)
1221     /* current input file */
1222 {
1223 
1224 
1225     char	str[50], buf[256], str1[50];
1226     int		c, n;
1227 
1228 
1229 /*
1230  *
1231  * Called from conv() to process the rest of a device control function. There's
1232  * a whole family of them and they all start with the string "x ", which we've
1233  * already read. The "x X ..." commands are an extensible (and device dependent)
1234  * family that we use here for things like picture inclusion. Unrecognized device
1235  * control commands are ignored.
1236  *
1237  */
1238 
1239 
1240     fscanf(fp, "%s", str);		/* get the control function name */
1241 
1242     switch ( str[0] )  {		/* only the first character counts */
1243 
1244 	case 'i':			/* initialize */
1245 		t_init();
1246 		break;
1247 
1248 	case 'T':			/* device name */
1249 		fscanf(fp, "%s", devname);
1250 		getdevmap();
1251 		strcpy(devname, realdev);
1252 		break;
1253 
1254 	case 't':			/* trailer */
1255 		t_trailer();
1256 		break;
1257 
1258 	case 'p':			/* pause -- can restart */
1259 		t_reset('p');
1260 		break;
1261 
1262 	case 's':			/* stop */
1263 		t_reset('s');
1264 		break;
1265 
1266 	case 'r':			/* resolution assumed when prepared */
1267 		fscanf(fp, "%d", &res);
1268 		break;
1269 
1270 	case 'f':			/* load font in a position */
1271 		fscanf(fp, "%d %s", &n, str);
1272 		fgets(buf, sizeof buf, fp);	/* in case there's a filename */
1273 		ungetc('\n', fp);	/* fgets() goes too far */
1274 		str1[0] = '\0';		/* in case there's nothing to come in */
1275 		sscanf(buf, "%s", str1);
1276 		loadfont(n, mapdevfont(str), str1);
1277 		break;
1278 
1279 	/* these don't belong here... */
1280 	case 'H':			/* char height */
1281 		fscanf(fp, "%d", &n);
1282 		t_charht(n);
1283 		break;
1284 
1285 	case 'S':			/* slant */
1286 		fscanf(fp, "%d", &n);
1287 		t_slant(n);
1288 		break;
1289 
1290 	case 'X':			/* copy through - from troff */
1291 		fscanf(fp, " %[^: \n]:", str);
1292 		fgets(buf, sizeof(buf), fp);
1293 		ungetc('\n', fp);
1294 		if ( strcmp(str, "PI") == 0 || strcmp(str, "PictureInclusion") == 0 )
1295 		    picture(buf);
1296 		else if ( strcmp(str, "InlinePicture") == 0 )
1297 		    inlinepic(fp, buf);
1298 		else if ( strcmp(str, "BeginPath") == 0 )
1299 		    beginpath(buf, FALSE);
1300 		else if ( strcmp(str, "DrawPath") == 0 )
1301 		    drawpath(buf, FALSE);
1302 		else if ( strcmp(str, "BeginObject") == 0 )
1303 		    beginpath(buf, TRUE);
1304 		else if ( strcmp(str, "EndObject") == 0 )
1305 		    drawpath(buf, TRUE);
1306 		else if ( strcmp(str, "NewBaseline") == 0 )
1307 		    newbaseline(buf);
1308 		else if ( strcmp(str, "DrawText") == 0 )
1309 		    drawtext(buf);
1310 		else if ( strcmp(str, "SetText") == 0 )
1311 		    settext(buf);
1312 		else if ( strcmp(str, "SetColor") == 0 )  {
1313 		    newcolor(buf);
1314 		    setcolor();
1315 		} else if ( strcmp(str, "PS") == 0 || strcmp(str, "PostScript") == 0 )  {
1316 		    endtext();
1317 		    /* xymove(hpos, vpos); ul90-22006 */
1318 		    fprintf(tf, "%s", buf);
1319 		}   /* End else */
1320 		break;
1321     }	/* End switch */
1322 
1323     while ( (c = getc(fp)) != '\n'  &&  c != EOF ) ;
1324 
1325 }   /* End of devcntrl */
1326 
1327 
1328 /*****************************************************************************/
1329 
1330 
1331 static void
fontinit(void)1332 fontinit(void)
1333 {
1334     int		fin;			/* for reading the DESC.out file */
1335     char	*filebase;		/* the whole thing goes here */
1336     int		i;			/* loop index */
1337 
1338 
1339 /*
1340  *
1341  * Reads *realdev's DESC.out file and uses what's there to initialize things like
1342  * the list of available point sizes. Old versions of the program used *devname's
1343  * DESC.out file to initialize nfonts, but that meant we needed to have *devname's
1344  * binary font files available for emulation. That restriction has been removed
1345  * and we now set nfonts using the "x font" commands in the input file, so by the
1346  * time we get here all we really need is *realdev. In fact devcntrl() reads the
1347  * device name from the "x T ..." command, but almost immediately replaces it with
1348  * string *realdev so we end up using *realdev's DESC.out file. Later on (in
1349  * t_font()) we mount all of *realdev's special fonts after the last legitimate
1350  * font position, just to be sure device emulation works reasonably well - there's
1351  * no guarantee *devname's special fonts match what's needed when *realdev's tables
1352  * are used.
1353  *
1354  */
1355 
1356 
1357     sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname);
1358     if ( (fin = open(temp, 0)) < 0 )
1359 	error(FATAL, "can't open tables for %s", temp);
1360 
1361     read(fin, &dev, sizeof(struct dev));
1362 
1363     nfonts = 0;				/* was dev.nfonts - now set in t_fp() */
1364     nsizes = dev.nsizes;
1365     nchtab = dev.nchtab;
1366     unitwidth = dev.unitwidth;
1367 
1368     if ( (filebase = malloc(dev.filesize)) == NULL )
1369 	error(FATAL, "no memory for description file");
1370 
1371     read(fin, filebase, dev.filesize);	/* all at once */
1372     close(fin);
1373 
1374     pstab = (short *) filebase;
1375     chtab = pstab + nsizes + 1;
1376     chname = (char *) (chtab + nchtab);
1377     fsize = 3 * 255 + nchtab + 128 - 32 + sizeof(struct Font);
1378 
1379     for ( i = 1; i <= NFONT; i++ )  {	/* so loadfont() knows nothing's there */
1380 	fontbase[i] = NULL;
1381 	widthtab[i] = codetab[i] = fitab[i] = NULL;
1382     }	/* End for */
1383 
1384     if ( (downloaded = (char *) calloc(nchtab + 128, sizeof(char))) == NULL )
1385 	error(FATAL, "no memory");
1386 
1387 }   /* End of fontinit */
1388 
1389 
1390 /*****************************************************************************/
1391 
1392 
1393 static void
loadfont(int n,char * s,char * s1)1394 loadfont(int n, char *s, char *s1)
1395     /* n - load this font position */
1396     /* s - with the .out file for this font */
1397     /* s1 - taken from here - possibly */
1398 {
1399     int		fin;			/* for reading *s.out file */
1400     int		nw;			/* number of width table entries */
1401 
1402 
1403 /*
1404  *
1405  * Loads font position n with the binary font file for *s.out provided it's not
1406  * already there. If *s1 is NULL or points to the empty string we read files from
1407  * directory *fontdir/dev*devname, otherwise directory *s1 is used. If the first
1408  * open fails we try to map font *s into one we expect will be available, and then
1409  * we try again.
1410  *
1411  */
1412 
1413 
1414     if ( n < 0  ||  n > NFONT )		/* make sure it's a legal position */
1415 	error(FATAL, "illegal fp command %d %s", n, s);
1416 
1417     if ( fontbase[n] != NULL && strcmp(s, fontbase[n]->namefont) == 0 )
1418 	return;
1419 
1420     if ( s1 == NULL || s1[0] == '\0' )
1421 	sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, s);
1422     else sprintf(temp, "%s/%s.out", s1, s);
1423 
1424     if ( (fin = open(temp, 0)) < 0 )  {
1425 	sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, mapfont(s));
1426 	if ( (fin = open(temp, 0)) < 0 )
1427 	    error(FATAL, "can't open font table %s", temp);
1428     }	/* End if */
1429 
1430     if ( fontbase[n] != NULL )		/* something's already there */
1431 	free(fontbase[n]);		/* so release the memory first */
1432 
1433     fontbase[n] = (struct Font *) malloc(fsize);
1434     if ( fontbase[n] == NULL )
1435 	error(FATAL, "Out of space in loadfont %s", s);
1436 
1437     read(fin, fontbase[n], fsize);
1438     close(fin);
1439 
1440     if ( smnt == 0 && fontbase[n]->specfont == 1 )
1441 	smnt = n;
1442 
1443     nw = fontbase[n]->nwfont & BMASK;
1444     widthtab[n] = (char *) fontbase[n] + sizeof(struct Font);
1445     codetab[n] = (char *) widthtab[n] + 2 * nw;
1446     fitab[n] = (char *) widthtab[n] + 3 * nw;
1447 
1448     t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
1449 
1450     if ( debug == ON )
1451 	fontprint(n);
1452 
1453 }   /* End of loadfont */
1454 
1455 
1456 /*****************************************************************************/
1457 
1458 
1459 static void
loadspecial(void)1460 loadspecial(void)
1461 {
1462     char	*p;			/* for next binary font file */
1463     int		nw;			/* width entries in next font */
1464     int		i;			/* loop index */
1465 
1466 
1467 /*
1468  *
1469  * Loads all the special fonts after the last legal font position. Mostly used
1470  * for device emulation, but we'll do it no matter what. Needed because there's
1471  * no consistency in special fonts across different devices, and relying on having
1472  * them mounted in the input file doesn't guarantee the whole collection will be
1473  * there. The special fonts are determined and mounted using the copy of the
1474  * DESC.out file that's been read into memory. Initially had this stuff at the
1475  * end of fontinit(), but we now don't know nfonts until much later.
1476  *
1477  */
1478 
1479 
1480     if ( gotspecial == FALSE )
1481 	for ( i = 1, p = chname + dev.lchname; i <= dev.nfonts; i++ )  {
1482 	    nw = *p & BMASK;
1483 	    if ( ((struct Font *) p)->specfont == 1 )
1484 		loadfont(++nfonts, ((struct Font *)p)->namefont, NULL);
1485 	    p += 3 * nw + dev.nchtab + 128 - 32 + sizeof(struct Font);
1486 	}   /* End for */
1487 
1488     gotspecial = TRUE;
1489 
1490 }   /* End of loadspecial */
1491 
1492 
1493 /*****************************************************************************/
1494 char *defaultFonts[] =
1495 	{ "R", "I", "B", "BI", "CW", "H", "HB", "HX", "S1", "S", NULL };
1496 
1497 static void
loaddefault(void)1498 loaddefault(void)
1499 {
1500   int i;
1501 
1502   for (i = 0; defaultFonts[i] != NULL ; i++)
1503     loadfont(++nfonts, defaultFonts[i], NULL);
1504 }
1505 
1506 
1507 static void
fontprint(int i)1508 fontprint(int i)
1509     /* font's index in fontbase[] */
1510 {
1511     int		j, n;
1512     char	*p;
1513 
1514 
1515 /*
1516  *
1517  * Debugging routine that dumps data about the font mounted in position i.
1518  *
1519  */
1520 
1521 
1522     fprintf(tf, "font %d:\n", i);
1523 
1524     p = (char *) fontbase[i];
1525     n = fontbase[i]->nwfont & BMASK;
1526 
1527     fprintf(tf, "base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",
1528 	    p, n, fontbase[i]->specfont, fontbase[i]->namefont, widthtab[i], fitab[i]);
1529 
1530     fprintf(tf, "widths:\n");
1531     for ( j = 0; j <= n; j++ )  {
1532 	fprintf(tf, " %2d", widthtab[i][j] & BMASK);
1533 	if ( j % 20 == 19 ) putc('\n', tf);
1534     }	/* End for */
1535 
1536     fprintf(tf, "\ncodetab:\n");
1537     for ( j = 0; j <= n; j++ )  {
1538 	fprintf(tf, " %2d", codetab[i][j] & BMASK);
1539 	if ( j % 20 == 19 ) putc('\n', tf);
1540     }	/* End for */
1541 
1542     fprintf(tf, "\nfitab:\n");
1543     for ( j = 0; j <= dev.nchtab + 128-32; j++ )  {
1544 	fprintf(tf, " %2d", fitab[i][j] & BMASK);
1545 	if ( j % 20 == 19 ) putc('\n', tf);
1546     }	/* End for */
1547 
1548     putc('\n', tf);
1549 
1550 }   /* End of fontprint */
1551 
1552 
1553 /*****************************************************************************/
1554 
1555 
1556 char *
mapfont(char * name)1557 mapfont(char *name)
1558     /* troff wanted this font */
1559 {
1560     int		i;			/* loop index */
1561 
1562 
1563 /*
1564  *
1565  * If loadfont() can't find font *name we map it into something else that should
1566  * be available and return a pointer to the new name. Used mostly for emulating
1567  * devices like the APS-5.
1568  *
1569  */
1570 
1571 
1572     for ( i = 0; fontmap[i].name != NULL; i++ )
1573 	if ( strcmp(name, fontmap[i].name) == 0 )
1574 	    return(fontmap[i].use);
1575 
1576     switch ( *++name )  {
1577 	case 'I':
1578 		return("I");
1579 
1580 	case 'B':
1581 		return("B");
1582 
1583 	case 'X':
1584 		return("BI");
1585 
1586 	default:
1587 		return("R");
1588     }	/* End switch */
1589 
1590 }   /* End of mapfont */
1591 
1592 
1593 /*****************************************************************************/
1594 
1595 
1596 static void
getdevmap(void)1597 getdevmap(void)
1598 {
1599 
1600 
1601     FILE	*fp;			/* for reading the device fontmap file */
1602     int		i = 0;			/* number of mapping pairs we've read */
1603     int		c;			/* for skipping lines */
1604 
1605 
1606 /*
1607  *
1608  * Looks for the device font mapping file *fontdir/dev*realdev/fontmaps/devname.
1609  * The file, if it exists, should be an ASCII file containing pairs of one or two
1610  * character font names per line. The first name is the font troff will be asking
1611  * for and the second is the one we'll use. Comments are lines that begin with
1612  * a '#' as the first non-white space character on a line. The devfontmap list
1613  * ends with a member that has the empty string in the name field.
1614  *
1615  */
1616 
1617 
1618     sprintf(temp, "%s/dev%s/fontmaps/%s", fontdir, realdev, devname);
1619 
1620     if ( devfontmap == NULL && (fp = fopen(temp, "r")) != NULL )  {
1621 	devfontmap = (Devfontmap *) malloc(10 * sizeof(Devfontmap));
1622 
1623 	while ( fscanf(fp, "%s", temp) != EOF )  {
1624 	    if ( temp[0] != '#' && strlen(temp) < 3 )
1625 		if ( fscanf(fp, "%s", &temp[3]) == 1 && strlen(&temp[3]) < 3 )  {
1626 		    strcpy((devfontmap + i)->name, temp);
1627 		    strcpy((devfontmap + i)->use, &temp[3]);
1628 		    if ( ++i % 10 == 0 )
1629 			devfontmap = (Devfontmap *) realloc(devfontmap, (i + 10) * sizeof(Devfontmap));
1630 		}   /* End if */
1631 	    while ( (c = getc(fp)) != '\n' && c != EOF ) ;
1632 	}   /* End while */
1633 
1634 	(devfontmap + i)->name[0] = '\0';	/* end the list we just read */
1635 	fclose(fp);
1636     }	/* End if */
1637 
1638 }   /* End of getdevmap */
1639 
1640 
1641 /*****************************************************************************/
1642 
1643 
1644 char *
mapdevfont(char * str)1645 mapdevfont(char *str)
1646 {
1647     int		i;
1648 
1649 
1650 /*
1651  *
1652  * Called immediately before loadfont() after an 'x font' command is recognized.
1653  * Takes the font name that troff asked for, looks it up in the devfontmap list,
1654  * and returns the mapped name to the caller. No mapping is done if the devfontmap
1655  * list is empty or font *str isn't found in the list.
1656  *
1657  */
1658 
1659 
1660     if ( devfontmap != NULL )
1661 	for ( i = 0; (devfontmap + i)->name[0] != '\0'; i++ )
1662 	    if ( strcmp((devfontmap + i)->name, str) == 0 )
1663 		return((devfontmap + i)->use);
1664 
1665     return(str);
1666 
1667 }   /* End of mapdevfont */
1668 
1669 
1670 /*****************************************************************************/
1671 
1672 
1673 void
reset(void)1674 reset(void)
1675 {
1676 
1677 /*
1678  *
1679  * Resets the variables that keep track of the printer's current position, font,
1680  * and size. Typically used after a restore/save pair (eg. when we finish with a
1681  * page) to make sure we force the printer back into sync (in terms of the font
1682  * and current point) before text is printed.
1683  *
1684  */
1685 
1686 
1687     lastx = -(slop + 1);
1688     lasty = -1;
1689     lastfont = lastsize = -1;
1690 
1691 }   /* End of reset */
1692 
1693 
1694 /*****************************************************************************/
1695 
1696 
1697 void
resetpos(void)1698 resetpos(void)
1699 {
1700 
1701 
1702 /*
1703  *
1704  * Resets the variables that keep track of the printer's current position. Used
1705  * when there's a chance we've lost track of the printer's current position or
1706  * done something that may have wiped it out, and we want to force dpost to set
1707  * the printer's position before printing text or whatever. For example stroke or
1708  * fill implicitly do a newpath, and that wipes out the current point, unless the
1709  * calls were bracketed by a gsave/grestore pair.
1710  *
1711  */
1712 
1713 
1714     lastx = -(slop + 1);
1715     lasty = -1;
1716 
1717 }   /* End of resetpos */
1718 
1719 
1720 /*****************************************************************************/
1721 
1722 
1723 static void
t_init(void)1724 t_init(void)
1725 {
1726     static int	initialized = FALSE;	/* only do most things once */
1727 
1728 
1729 /*
1730  *
1731  * Called from devcntrl() after an "x init" command is read. Things only work if
1732  * we've already seen the "x res" command, and much of the stuff, including the
1733  * call to setup, should only be done once. Restricting everything to one call of
1734  * setup (ie. the one in the prologue) means all the input files must have been
1735  * formatted for the same device.
1736  *
1737  */
1738 
1739 
1740     endtext();				/* moved  - for cat'ed troff files */
1741 
1742     if ( initialized == FALSE )  {	/* only do this stuff once per job */
1743 	fontinit();
1744 	gotspecial = FALSE;
1745 	widthfac = (float) res /dev.res;
1746 	slop = pointslop * res / POINTS + .5;
1747 	rvslop = res * .025;
1748 	setup();
1749 	initialized = TRUE;
1750     }	/* End if */
1751 
1752     hpos = vpos = 0;			/* upper left corner */
1753     setsize(t_size(10));		/* start somewhere */
1754     reset();				/* force position and font stuff - later */
1755 
1756 }   /* End of t_init */
1757 
1758 
1759 /*****************************************************************************/
1760 
1761 
1762 static void
t_page(int pg)1763 t_page(int pg)
1764     /* troff's current page number */
1765 {
1766     static int	lastpg = 0;		/* last one we started - for ENDPAGE */
1767 
1768 
1769 /*
1770  *
1771  * Called whenever we've finished the last page and want to get ready for the
1772  * next one. Also used at the end of each input file, so we have to be careful
1773  * about what's done. The first time through (up to the redirect(pg) call) output
1774  * goes to /dev/null because of the redirect(-1) call made in conv().
1775  *
1776  * Adobe now recommends that the showpage operator occur after the page level
1777  * restore so it can be easily redefined to have side-effects in the printer's VM.
1778  * Although it seems reasonable I haven't implemented it, because it makes other
1779  * things, like selectively setting manual feed or choosing an alternate paper
1780  * tray, clumsy - at least on a per page basis.
1781  *
1782  */
1783 
1784 
1785     if ( tf == stdout )			/* count the last page */
1786 	printed++;
1787 
1788     endtext();				/* print the last line? */
1789 
1790     fprintf(tf, "cleartomark\n");
1791     fprintf(tf, "showpage\n");
1792     fprintf(tf, "restore\n");
1793     fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed);
1794 
1795     redirect(pg);
1796 
1797     fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1);
1798     fprintf(tf, "save\n");
1799     fprintf(tf, "mark\n");
1800     writerequest(printed+1, tf);
1801     fprintf(tf, "%d pagesetup\n", printed+1);
1802     setcolor();
1803 
1804     lastpg = pg;			/* for the next ENDPAGE comment */
1805     hpos = vpos = 0;			/* get ready for the next page */
1806     reset();				/* force position and font stuff - later */
1807 
1808     seenpage = TRUE;
1809 
1810 }   /* End of t_page */
1811 
1812 
1813 /*****************************************************************************/
1814 
1815 
1816 static void
t_newline(void)1817 t_newline(void)
1818 {
1819 
1820 
1821 /*
1822  *
1823  * Just finished the last line. All we do is set the horizontal position to 0,
1824  * although even that probably isn't necessary.
1825  *
1826  */
1827 
1828 
1829     hpos = 0;
1830 
1831 }   /* End of t_newline */
1832 
1833 
1834 /*****************************************************************************/
1835 
1836 
1837 int
t_size(int n)1838 t_size(int n)
1839     /* convert this to an internal size */
1840 {
1841     int		i;			/* loop index */
1842 
1843 
1844 /*
1845  *
1846  * Converts a point size into an internal size that can be used as an index into
1847  * pstab[]. The internal size is one plus the index of the least upper bound of
1848  * n in pstab[], or nsizes if n is larger than all the listed sizes.
1849  *
1850  */
1851 
1852 
1853     if ( n <= pstab[0] )
1854 	return(1);
1855     else if (n >= pstab[nsizes-1])
1856 	return(nsizes);
1857 
1858     for ( i = 0; n > pstab[i]; i++ ) ;
1859 
1860     return(i+1);
1861 
1862 }   /* End of t_size */
1863 
1864 
1865 /*****************************************************************************/
1866 
1867 
1868 static void
setsize(int n)1869 setsize(int n)
1870     /* new internal size */
1871 {
1872 
1873 
1874 /*
1875  *
1876  * Now using internal size n, where pstab[n-1] is the best available approximation
1877  * to the size troff asked for.
1878  *
1879  */
1880 
1881 
1882     size = n;
1883 
1884 }   /* End of setsize */
1885 
1886 
1887 /*****************************************************************************/
1888 
1889 
1890 static void
t_fp(int n,char * s,char * si)1891 t_fp(int n, char *s, char *si)
1892     /* n - this position */
1893     /* s - now has this font mounted */
1894     /* si - its internal number */
1895 
1896 
1897 {
1898 
1899 
1900 /*
1901  *
1902  * Updates nfonts and the array that keeps track of the mounted fonts. Called from
1903  * loadfont() after an "x font pos font" command is read, and if pos is larger than
1904  * the current value assigned to nfonts we set gotspecial to FALSE to make sure
1905  * t_font() loads all the special fonts after the last legitimate font position.
1906  *
1907  */
1908 
1909 
1910     fontname[n].name = s;
1911     fontname[n].number = atoi(si);
1912 
1913     if ( n == lastfont )		/* force a call to t_sf() */
1914 	lastfont = -1;
1915 
1916     if ( n > nfonts )  {		/* got more positions */
1917 	nfonts = n;
1918 	gotspecial = FALSE;
1919     }	/* End if */
1920 
1921 }   /* End of t_fp */
1922 
1923 
1924 /*****************************************************************************/
1925 
1926 int
t_font(char * s)1927 t_font(char *s)
1928     /* use font in this position next */
1929 {
1930     int		n;
1931 
1932 
1933 /*
1934  *
1935  * Converts the string *s into an integer and checks to make sure it's a legal
1936  * font position. Also arranges to mount all the special fonts after the last
1937  * legitimate font (by calling loadspecial()), provided it hasn't already been
1938  * done.
1939  *
1940  */
1941 
1942 
1943     n = atoi(s);
1944 
1945     if ( seenpage == TRUE )  {
1946 	if ( n < 0  ||  n > nfonts )
1947 	    error(FATAL, "illegal font position %d", n);
1948 
1949 	if ( gotspecial == FALSE )
1950 	    loadspecial();
1951     }	/* End if */
1952 
1953     return(n);
1954 
1955 }   /* End of t_font */
1956 
1957 
1958 /*****************************************************************************/
1959 
1960 
1961 static void
setfont(int n)1962 setfont(int n)
1963     /* use the font mounted here */
1964 {
1965 
1966 
1967 /*
1968  *
1969  * troff wants to use the font that's been mounted in position n. All we do here
1970  * is update the variable that keeps track of the current position. PostScript
1971  * font changes are handled in t_sf(), and are only generated right before we're
1972  * ready to print or draw something.
1973  *
1974  */
1975 
1976 
1977     if ( n < 0 || n > NFONT )
1978 	error(FATAL, "illegal font %d", n);
1979     if ( fontname[n].name == NULL && fontname[n].number == 0)
1980 	loaddefault();
1981     if ( fontname[n].name == NULL && fontname[n].number == 0)
1982 	error(FATAL,
1983   "font %d not loaded: check 'dpost' input for 'x font %d XXX' before 'f%d'",
1984 		n, n, n);
1985 
1986     font = n;
1987 
1988 }   /* End of setfont */
1989 
1990 
1991 /*****************************************************************************/
1992 
1993 void
t_sf(void)1994 t_sf(void)
1995 {
1996     int		fnum;			/* internal font number */
1997 
1998 
1999 /*
2000  *
2001  * Called whenever we need to use a new font or size. Only done right before we
2002  * print a character. The seenfonts[] array keeps track of the fonts we've used.
2003  * Helps manage host resident fonts and the DOCUMENTFONTS comment that's put out
2004  * at the end of the job. The array is indexed by internal number. Only works for
2005  * fonts that have internal numbers less than or equal to MAXINTERNAL.
2006  *
2007  */
2008 
2009 
2010     if ( fontname[font].name == NULL )
2011 	return;
2012 
2013     endtext();
2014 
2015     if ( (fnum = fontname[font].number) > MAXINTERNAL || fnum < 0 )
2016 	fnum = 0;
2017 
2018     if ( fnum > 0 && seenfonts[fnum] == 0 && hostfontdir != NULL )  {
2019 	sprintf(temp, "%s/%s", hostfontdir, fontname[font].name);
2020 	if ( access(temp, 04) == 0 )
2021 	    doglobal(temp);
2022     }	/* End if */
2023 
2024     if ( tf == stdout )  {
2025 	lastfont = font;
2026 	lastsize = size;
2027 	if ( seenfonts[fnum] == 0 )
2028 	    documentfonts();
2029 	seenfonts[fnum] = 1;
2030     }	/* End if */
2031 
2032     fprintf(tf, "%d %s f\n", pstab[size-1], fontname[font].name);
2033 
2034     if ( fontheight != 0 || fontslant != 0 )
2035 	fprintf(tf, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : pstab[size-1]);
2036 
2037 }   /* End of t_sf */
2038 
2039 
2040 /*****************************************************************************/
2041 
2042 
2043 static void
t_charht(int n)2044 t_charht(int n)
2045     /* use this as the character height */
2046 {
2047 
2048 /*
2049  *
2050  * Remembers the requested height, from 'x H n'. Forces a call to t_sf(), which
2051  * is where the real work is done, by setting lastfont to -1.
2052  *
2053  */
2054 
2055     fontheight = (n == pstab[size-1]) ? 0 : n;
2056     lastfont = -1;
2057 
2058 }   /* End of t_charht */
2059 
2060 
2061 /*****************************************************************************/
2062 
2063 
2064 static void
t_slant(int n)2065 t_slant(int n)
2066     /* slant characters this many degrees */
2067 {
2068 
2069 /*
2070  *
2071  * Remembers the requested slant, from 'x X n'. Forces a call to t_sf(), which
2072  * is where the real work is done, by setting lastfont to -1.
2073  *
2074  */
2075 
2076     fontslant = n;
2077     lastfont = -1;
2078 
2079 }   /* End of t_slant */
2080 
2081 
2082 /*****************************************************************************/
2083 
2084 
2085 static void
t_reset(int c)2086 t_reset(int c)
2087     /* pause or restart */
2088 {
2089 
2090 /*
2091  *
2092  * Found an "x stop" or "x pause" command. Although nothing's done here we could
2093  * add code to reset everything so dpost could handle multiple files formatted for
2094  * different devices.
2095  *
2096  */
2097 
2098 
2099 }   /* End of t_reset */
2100 
2101 
2102 /*****************************************************************************/
2103 
2104 
2105 static void
t_trailer(void)2106 t_trailer(void)
2107 {
2108 
2109 /*
2110  *
2111  * Called after we find an "x trailer" in the input file. Forcing out the last
2112  * page is done at the end of conv(), but probably belongs here.
2113  *
2114  */
2115 
2116 
2117     endtext();
2118 
2119 }   /* End of t_trailer */
2120 
2121 
2122 /*****************************************************************************/
2123 
2124 
2125 void
hgoto(int n)2126 hgoto(int n)
2127     /* new horizontal position */
2128 {
2129 
2130 
2131 /*
2132  *
2133  * Want to be at this absolute horizontal position next. Actual motion commands
2134  * are generated in oput(), charlib(), and the drawing routines.
2135  *
2136  */
2137 
2138 
2139     hpos = n;
2140 
2141 }   /* End of hgoto */
2142 
2143 
2144 /*****************************************************************************/
2145 
2146 
2147 static void
hmot(int n)2148 hmot(int n)
2149     /* move this far horizontally */
2150 {
2151 
2152 /*
2153  *
2154  * Handles relative horizontal motion. troff's current positon, as recorded in
2155  * in hpos, is changed by n units. Usually called right before we're supposed to
2156  * print a character.
2157  *
2158  */
2159 
2160 
2161     hpos += n;
2162 
2163 }   /* End of hmot */
2164 
2165 
2166 /*****************************************************************************/
2167 
2168 
2169 void
vgoto(int n)2170 vgoto(int n)
2171     /* new vertical position */
2172 {
2173 
2174 /*
2175  *
2176  * Moves vertically in troff's coordinate system to absolute position n.
2177  *
2178  */
2179 
2180 
2181     vpos = n;
2182 
2183 }   /* End of vgoto */
2184 
2185 
2186 /*****************************************************************************/
2187 
2188 
2189 static void
vmot(int n)2190 vmot(int n)
2191     /* move this far vertically */
2192 {
2193 
2194 /*
2195  *
2196  * Handles relative vertical motion of n units in troff's coordinate system.
2197  *
2198  */
2199 
2200 
2201     vpos += n;
2202 
2203 }   /* End of vmot */
2204 
2205 
2206 /*****************************************************************************/
2207 
2208 
2209 void
xymove(int x,int y)2210 xymove(int x, int y)
2211     /* this is where we want to be */
2212 {
2213 
2214 /*
2215  *
2216  * Makes sure the post-processor and printer agree about the current position.
2217  *
2218  */
2219 
2220 
2221     hgoto(x);
2222     vgoto(y);
2223 
2224     fprintf(tf, "%d %d m\n", hpos, vpos);
2225 
2226     lastx = hpos;
2227     lasty = vpos;
2228 
2229 }   /* End of xymove */
2230 
2231 
2232 /*****************************************************************************/
2233 
2234 
2235 static void
put1s(char * s)2236 put1s(char *s)
2237     /* find and print this character */
2238 {
2239     static int		i = 0;		/* last one we found - usually */
2240 
2241 /*
2242  *
2243  * *s points to the start of a two character string that represents one of troff's
2244  * special characters. To print it we first look for *s in the chname[] array using
2245  * chtab[i] to find the string representing character i in chname[]. If the lookup
2246  * is successful we add 128 to i and ask put1() to finish printing the character.
2247  * We remember the index where the last character was found because requests to
2248  * print a special character often come in bunches (eg. drawing lines with \(ru).
2249  *
2250  */
2251 
2252 
2253     if ( strcmp(s, &chname[chtab[i]]) != 0 )
2254 	for ( i = 0; i < nchtab; i++ )
2255 	    if ( strcmp(&chname[chtab[i]], s) == 0 )
2256 		break;
2257 
2258     if ( i < nchtab )
2259 	put1(i + 128);
2260     else i = 0;
2261 
2262 }   /* End of put1s */
2263 
2264 
2265 /*****************************************************************************/
2266 
2267 
2268 static void
put1(int c)2269 put1(int c)
2270     /* want to print this character */
2271 {
2272 
2273     int			i;		/* character code from fitab */
2274     int			j;		/* number of fonts we've checked so far */
2275     int			k;		/* font we're currently looking at */
2276     char		*pw;		/* font widthtab and */
2277     char		*p;		/* and codetab where c was found */
2278     int			code;		/* code used to get c printed */
2279     int			ofont;		/* font when we started */
2280 
2281 
2282 /*
2283  *
2284  * Arranges to have character c printed. If c < 128 it's a simple ASCII character,
2285  * otherwise it's a special character. Things done here have to agree with the way
2286  * the font tables were built by makedev, and work as follows. First we subtract
2287  * 32 from c because the tables don't record the non-graphic ASCII characters.
2288  * If fitab[k][c] isn't zero the character is on font k and the value is an index
2289  * that can be used to recover width and character code data from the other two
2290  * tables. If fitab[k][c] is zero the character isn't defined on font k and we
2291  * check the next font, which is found as follows. The current font is the first
2292  * one we check, and it's followed by a circular search of all the remaining fonts
2293  * that starts with the first special font and skips font position 0. If character
2294  * c is found somewhere besides the current font we change to that font and use
2295  * fitab[k][c] to locate missing data in the other two tables. The width of the
2296  * character can be found at widthtab[k][c] while codetab[k][c] is whatever we
2297  * need to tell the printer to have character c printed. lastc records the real
2298  * name of the character because it's lost by the time oput() gets called but
2299  * charlib() may need it.
2300  *
2301  * Took all the debugging stuff out because at least this part of the program is
2302  * reasonably solid.
2303  *
2304  */
2305 
2306 
2307     lastc = c;				/* charlib() needs the name not the code */
2308     if ( (c -= 32) <= 0 )		/* probably never happens */
2309 	return;
2310 
2311     k = ofont = font;
2312 
2313     if ( (i = fitab[k][c] & BMASK) != 0 )  {	/* it's on this font */
2314 	p = codetab[font];
2315 	pw = widthtab[font];
2316     } else if ( smnt > 0 )  {		/* on special (we hope) */
2317 	for ( k=smnt, j=0; j <= nfonts; j++, k = (k+1) % (nfonts+1) )  {
2318 	    if ( k == 0 )  continue;
2319 	    if ( (i = fitab[k][c] & BMASK) != 0 )  {
2320 		p = codetab[k];
2321 		pw = widthtab[k];
2322 		setfont(k);
2323 		break;
2324 	    }	/* End if */
2325 	}   /* End for */
2326     }	/* End else */
2327 
2328     if ( i != 0 && (code = p[i] & BMASK) != 0 )  {
2329 	lastw = widthfac * (((pw[i] & BMASK) * pstab[size-1] + unitwidth/2) / unitwidth);
2330 	oput(code);
2331     }	/* End if */
2332 
2333     if ( font != ofont )
2334 	setfont(ofont);
2335 
2336 }   /* End of put1 */
2337 
2338 
2339 /*****************************************************************************/
2340 
2341 
2342 static void
oput(int c)2343 oput(int c)
2344     /* want to print this character */
2345 {
2346 
2347 /*
2348  *
2349  * Arranges to print the character whose code is c in the current font. All the
2350  * actual positioning is done here, in charlib(), or in the drawing routines.
2351  *
2352  */
2353 
2354 
2355     if ( textcount > MAXSTACK )		/* don't put too much on the stack? */
2356 	endtext();
2357 
2358     if ( font != lastfont || size != lastsize )
2359 	t_sf();
2360 
2361     if ( vpos != lasty )
2362 	endline();
2363 
2364     starttext();
2365 
2366     if ( ABS(hpos - lastx) > slop )
2367 	endstring();
2368 
2369     if ( isascii(c) && isprint(c) )
2370 	switch ( c )  {
2371 	    case '(':
2372 	    case ')':
2373 	    case '\\':
2374 		    addchar('\\');
2375 
2376 	    default:
2377 		    addchar(c);
2378 	}   /* End switch */
2379     else if ( c > 040 )
2380 	addoctal(c);
2381     else charlib(c);
2382 
2383     lastx += lastw;
2384 
2385 }   /* End of oput */
2386 
2387 
2388 /*****************************************************************************/
2389 
2390 
2391 static void
starttext(void)2392 starttext(void)
2393 {
2394 
2395 /*
2396  * Called whenever we want to be sure we're ready to start collecting characters
2397  * for the next call to PostScript procedure t (ie. the one that prints them). If
2398  * textcount is positive we've already started, so there's nothing to do. The more
2399  * complicated encoding schemes save text strings in the strings[] array and need
2400  * detailed information about the strings when they're written to the output file
2401  * in endtext().
2402  *
2403  */
2404 
2405 
2406     if ( textcount < 1 )  {
2407 	switch ( encoding )  {
2408 	    case 0:
2409 	    case 1:
2410 		putc('(', tf);
2411 		break;
2412 
2413 	    case 2:
2414 	    case 3:
2415 		strptr = strings;
2416 		spacecount = 0;
2417 		line[1].str = strptr;
2418 		line[1].dx = 0;
2419 		line[1].spaces = 0;
2420 		line[1].start = hpos;
2421 		line[1].width = 0;
2422 		break;
2423 
2424 	    case MAXENCODING+1:			/* reverse video */
2425 		if ( lastend == -1 )
2426 		    lastend = hpos;
2427 		putc('(', tf);
2428 		break;
2429 
2430 	    case MAXENCODING+2:			/* follow a funny baseline */
2431 		putc('(', tf);
2432 		break;
2433 	}   /* End switch */
2434 	textcount = 1;
2435 	lastx = stringstart = hpos;
2436     }	/* End if */
2437 
2438 }   /* End of starttext */
2439 
2440 
2441 /*****************************************************************************/
2442 
2443 
2444 void
endtext(void)2445 endtext(void)
2446 {
2447 
2448     int		i;			/* loop index */
2449 
2450 
2451 /*
2452  *
2453  * Generates a call to the PostScript procedure that processes all the text we've
2454  * accumulated - provided textcount is positive.
2455  *
2456  */
2457 
2458     if ( textcount > 0 )  {		/* started working on some text */
2459 	switch ( encoding )  {
2460 	    case 0:
2461 		fprintf(tf, ")%d t\n", stringstart);
2462 		break;
2463 
2464 	    case 1:
2465 		fprintf(tf, ")%d %d t\n", stringstart, lasty);
2466 		break;
2467 
2468 	    case 2:
2469 		*strptr = '\0';
2470 		line[textcount].width = lastx - line[textcount].start;
2471 		if ( spacecount != 0 || textcount != 1 )  {
2472 		    for ( i = textcount; i > 0; i-- )
2473 			fprintf(tf, "(%s)%d %d", line[i].str, line[i].spaces, line[i].width);
2474 		    fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
2475 		} else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
2476 		break;
2477 
2478 	    case 3:
2479 		*strptr = '\0';
2480 		if ( spacecount != 0 || textcount != 1 )  {
2481 		    for ( i = textcount; i > 0; i-- )
2482 			fprintf(tf, "(%s)%d", line[i].str, line[i].dx);
2483 		    fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
2484 		} else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
2485 		break;
2486 
2487 	    case MAXENCODING+1:
2488 		fprintf(tf, ")%d ", stringstart);
2489 		fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop);
2490 		fprintf(tf, "t\n", stringstart);
2491 		lastend = (lastx + .5) + 2 * rvslop;
2492 		break;
2493 
2494 	    case MAXENCODING+2:
2495 		fprintf(tf, ")%d %d t\n", stringstart, lasty);
2496 		break;
2497 	}   /* End switch */
2498     }	/* End if */
2499 
2500     textcount = 0;
2501 
2502 }   /* End of endtext */
2503 
2504 
2505 /*****************************************************************************/
2506 
2507 
2508 static void
endstring(void)2509 endstring(void)
2510 {
2511     int		dx;
2512 
2513 /*
2514  *
2515  * Horizontal positions are out of sync. End the last open string, adjust the
2516  * printer's position, and start a new string. Assumes we've already started
2517  * accumulating text.
2518  *
2519  */
2520 
2521 
2522     switch ( encoding )  {
2523 	case 0:
2524 	case 1:
2525 	    fprintf(tf, ")%d(", stringstart);
2526 	    textcount++;
2527 	    lastx = stringstart = hpos;
2528 	    break;
2529 
2530 	case 2:
2531 	case 3:
2532 	    dx = hpos - lastx;
2533 	    if ( spacecount++ == 0 )
2534 		line[textcount].dx = dx;
2535 	    if ( line[textcount].dx != dx )  {
2536 		*strptr++ = '\0';
2537 		line[textcount].width = lastx - line[textcount].start;
2538 		line[++textcount].str = strptr;
2539 		*strptr++ = ' ';
2540 		line[textcount].dx = dx;
2541 		line[textcount].start = lastx;
2542 		line[textcount].width = 0;
2543 		line[textcount].spaces = 1;
2544 	    } else {
2545 		*strptr++ = ' ';
2546 		line[textcount].spaces++;
2547 	    }	/* End else */
2548 	    lastx += dx;
2549 	    break;
2550 
2551 	case MAXENCODING+1:
2552 	    fprintf(tf, ")%d(", stringstart);
2553 	    textcount++;
2554 	    lastx = stringstart = hpos;
2555 	    break;
2556 
2557 	case MAXENCODING+2:
2558 	    endtext();
2559 	    starttext();
2560 	    break;
2561 
2562     }	/* End switch */
2563 
2564 }   /* End of endstring */
2565 
2566 
2567 /*****************************************************************************/
2568 
2569 
2570 static void
endline(void)2571 endline(void)
2572 {
2573 
2574 /*
2575  *
2576  * The vertical position has changed. Dump any accumulated text, then adjust
2577  * the printer's vertical position.
2578  *
2579  */
2580 
2581 
2582     endtext();
2583 
2584     if ( encoding == 0 || encoding == MAXENCODING+1 )
2585 	fprintf(tf, "%d %d m\n", hpos, vpos);
2586 
2587     lastx = stringstart = lastend = hpos;
2588     lasty = vpos;
2589 
2590 }   /* End of endline */
2591 
2592 
2593 /*****************************************************************************/
2594 
2595 
2596 static void
addchar(int c)2597 addchar(int c)
2598     /* next character in current string */
2599 {
2600 
2601 /*
2602  *
2603  * Does whatever is needed to add character c to the current string.
2604  *
2605  */
2606 
2607 
2608     switch ( encoding )  {
2609 	case 0:
2610 	case 1:
2611 	    putc(c, tf);
2612 	    break;
2613 
2614 	case 2:
2615 	case 3:
2616 	    *strptr++ = c;
2617 	    break;
2618 
2619 	case MAXENCODING+1:
2620 	case MAXENCODING+2:
2621 	    putc(c, tf);
2622 	    break;
2623     }	/* End switch */
2624 
2625 }   /* End of addchar */
2626 
2627 
2628 /*****************************************************************************/
2629 
2630 
2631 static void
addoctal(int c)2632 addoctal(int c)
2633     /* add it as an octal escape */
2634 {
2635 
2636 
2637 /*
2638  *
2639  * Adds c to the current string as an octal escape \ddd.
2640  *
2641  */
2642 
2643 
2644     switch ( encoding )  {
2645 	case 0:
2646 	case 1:
2647 	    fprintf(tf, "\\%o", c);
2648 	    break;
2649 
2650 	case 2:
2651 	case 3:
2652 	    sprintf(strptr, "\\%o", c);
2653 	    strptr += strlen(strptr);
2654 	    break;
2655 
2656 	case MAXENCODING+1:
2657 	case MAXENCODING+2:
2658 	    fprintf(tf, "\\%o", c);
2659 	    break;
2660     }	/* End switch */
2661 
2662 }   /* End of addoctal */
2663 
2664 
2665 /*****************************************************************************/
2666 
2667 
2668 static void
charlib(int code)2669 charlib(int code)
2670     /* either 1 or 2 */
2671 {
2672     char	*name;			/* name of the character */
2673     char	tname[10];		/* in case it's a single ASCII character */
2674 
2675 
2676 /*
2677  *
2678  * Called from oput() for characters having codes less than 040. Special files
2679  * that define PostScript procedures for certain characters can be found in
2680  * directory *fontdir/devpost/charlib. If there's a file that has the same name as
2681  * the character we're trying to print it's copied to the output file, otherwise
2682  * nothing, except some positioning, is done.
2683  *
2684  * All character definitions are only made once. Subsequent requests to print the
2685  * character generate a call to a procedure that begins with the prefix build_ and
2686  * ends with the character's name. Special characters that are assigned codes
2687  * other than 1 are assumed to have additional data files that should be copied
2688  * to the output file immediately after the build_ call. Those data files should
2689  * end in the suffix .map, and usually will be a hex representation of a bitmap.
2690  *
2691  */
2692 
2693 
2694     endtext();
2695 
2696     if ( lastc < 128 )  {		/* just a simple ASCII character */
2697 	sprintf(tname, "%.3o", lastc);
2698 	name = tname;
2699     } else name = &chname[chtab[lastc - 128]];
2700 
2701     if ( downloaded[lastc] == 0 )  {
2702 	sprintf(temp, "%s/dev%s/charlib/%s", fontdir, realdev, name);
2703 	if ( access(temp, 04) == 0 && doglobal(temp) == TRUE )  {
2704 	    downloaded[lastc] = 1;
2705 	    t_sf();
2706 	}   /* End if */
2707     }	/* End if */
2708 
2709     if ( downloaded[lastc] == 1 )  {
2710 	xymove(hpos, vpos);
2711 	fprintf(tf, "%d build_%s\n", (int) lastw, name);
2712 	if ( code != 1 )  {		/* get the bitmap or whatever */
2713 	    sprintf(temp, "%s/dev%s/charlib/%s.map", fontdir, realdev, name);
2714 	    if ( access(temp, 04) == 0 && tf == stdout )
2715 		cat(temp);
2716 	}   /* End if */
2717 	fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos);
2718     }	/* End if */
2719 
2720 }   /* End of charlib */
2721 
2722 
2723 /*****************************************************************************/
2724 
2725 
2726 int
doglobal(char * name)2727 doglobal(char *name)
2728     /* copy this to the output - globally */
2729 {
2730     int		val = FALSE;		/* returned to the caller */
2731 
2732 
2733 /*
2734  *
2735  * Copies file *name to the output file and brackets it with whatever commands are
2736  * needed to have it exported to the global environment. TRUE is returned if we
2737  * successfully add file *name to the output file.
2738  *
2739  */
2740 
2741 
2742     if ( tf == stdout )  {
2743 	endtext();
2744 	fprintf(tf, "cleartomark restore\n");
2745 	fprintf(tf, "%s", BEGINGLOBAL);
2746 	val = cat(name);
2747 	fprintf(tf, "%s", ENDGLOBAL);
2748 	fprintf(tf, "save mark\n");
2749 	reset();
2750     }	/* End if */
2751 
2752     return(val);
2753 
2754 }   /* End of doglobal */
2755 
2756 
2757 /*****************************************************************************/
2758 
2759 
2760 static void
documentfonts(void)2761 documentfonts(void)
2762 {
2763     FILE	*fp_in;			/* PostScript font name read from here */
2764     FILE	*fp_out;		/* and added to this file */
2765 
2766 
2767 /*
2768  *
2769  * Whenever a new font is used we try to record the appropriate PostScript font
2770  * name in *temp_file for the DOCUMENTFONTS comment that's put out in done().
2771  * By default PostScript font names are found in /usr/lib/font/devpost. Fonts
2772  * that have a .name file are recorded in *temp_file. The first string in that
2773  * file is expected to be that font's (long) PostScript name.
2774  *
2775  */
2776 
2777 
2778     if ( temp_file == NULL )		/* generate a temp file name */
2779 	if ( (temp_file = tempnam(TEMPDIR, "dpost")) == NULL )
2780 	    return;
2781 
2782     sprintf(temp, "%s/dev%s/%s.name", fontdir, realdev, fontname[font].name);
2783 
2784     if ( (fp_in = fopen(temp, "r")) != NULL )  {
2785 	if ( (fp_out = fopen(temp_file, "a")) != NULL )  {
2786 	    if ( fscanf(fp_in, "%s", temp) == 1 )  {
2787 		if ( docfonts++ == 0 )
2788 		    fprintf(fp_out, "%s", DOCUMENTFONTS);
2789 		else if ( (docfonts - 1) % 8  == 0 )
2790 		    fprintf(fp_out, "\n%s", CONTINUECOMMENT);
2791 		fprintf(fp_out, " %s", temp);
2792 	    }	/* End if */
2793 	    fclose(fp_out);
2794 	}   /* End if */
2795 	fclose(fp_in);
2796     }	/* End if */
2797 
2798 }   /* End of documentfonts */
2799 
2800 
2801 /*****************************************************************************/
2802 
2803 
2804 static void
redirect(int pg)2805 redirect(int pg)
2806     /* next page we're printing */
2807 {
2808     static FILE	*fp_null = NULL;	/* if output is turned off */
2809 
2810 
2811 /*
2812  *
2813  * If we're not supposed to print page pg, tf will be directed to /dev/null,
2814  * otherwise output goes to stdout.
2815  *
2816  */
2817 
2818 
2819     if ( pg >= 0 && in_olist(pg) == ON )
2820 	tf = stdout;
2821     else if ( (tf = fp_null) == NULL )
2822 	tf = fp_null = fopen("/dev/null", "w");
2823 
2824 }   /* End of redirect */
2825