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