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