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