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