|
|
1.1 root 1: /*
2: *
3: * dpost - troff post-processor for PostScript printers.
4: *
5: * A program that translates output generated by the device independent troff
6: * into PostScript. Much was borrowed from dimpress and dps (formally dlzw),
7: * and even though the code has changed, credit has to be given to Richard
8: * Flood for his early work on the PostScript driver.
9: *
10: * The big change is in the font table routines. The old binary format and
11: * makedev are gone. dpost and troff now read ASCII tables, and both skip
12: * unrecognized entries in the ASCII tables. That means problems, like where
13: * to put the real name of the PostScript font, have disappeared. The added
14: * flexibility means some overhead translating the ASCII tables, but the
15: * overhead isn't too bad.
16: *
17: * dpost can also now calculate a reasonably tight BoundingBox, which helps
18: * picture inclusion. The calculations, by default, are disabled. Couldn't
19: * justify the overhead for a comment, particularly one that's only needed
20: * occasionally. Use the -B option to get the comment.
21: *
22: * Output produced by dpost is still nonconforming. Definitions made in pages
23: * and exported to the job's global environment are the primary problem. It's
24: * an efficient approach, but means pages are not independent. Violations are
25: * bracketed by %%BeginGlobal and %%EndGlobal comments and can be pulled into
26: * the prologue by utility programs (like postreverse) that recognize the new
27: * comments.
28: *
29: * The program handles files formatted for any device, although the best and
30: * most efficient output is generated when the font and description files
31: * match PostScript's resident fonts. Emulation is relatively expensive, and
32: * can produce output files that are more than twice the size of the input
33: * files.
34: *
35: * Several different methods can be used to encode lines of text. What's done
36: * depends on the value assigned to encoding. Print time should decrease as
37: * encoding increases (up to MAXENCODING). Setting encoding to 3 (or higher)
38: * is not normally recommended. It's fast and produces very compact output,
39: * but rounding errors in troff's width tables can accumulate and lead to a
40: * ragged right margin. encoding can be changed on the command line using the
41: * -e option.
42: *
43: * PostScript fonts don't support all of troff's characters. Some are built
44: * by special PostScript procedures in directory *fontdir/devpost/charlib.
45: * The charlib approach is not meant to replace user defined fonts. It was
46: * a quick implementation designed to handle characters that aren't used
47: * often - charlib should not be overused! The charlib lookup is triggered
48: * when a character in a font table is assigned a code less than 32.
49: *
50: * Most defaults are set in the prologue, but can be changed by options. The
51: * -P option passes arbitrary PostScript into the setup section of the output
52: * file. It can be used to set (or change) values that can't be accessed by
53: * other options. For example,
54: *
55: * dpost -P'/useclippath false def' file > file.ps
56: *
57: * defines useclippath to be false. Everything passed through using the -P
58: * (-C to copy a file) options become part of the job's global environment.
59: * Definitions override defaults in the prologue.
60: *
61: * dpost expects to find the following procedures in the prologue:
62: *
63: * setup
64: *
65: * mark ... setup -
66: *
67: * Initialization procedure mainly responsible for setting up an
68: * appropriate coordinate system.
69: *
70: * pagesetup
71: *
72: * page pagesetup -
73: *
74: * Called at the start of each page, immediately after the page
75: * level save. Argument is the current page number.
76: *
77: * setdecoding
78: *
79: * num setdecoding -
80: *
81: * Select the decoding procedure used to print text strings encoded
82: * by dpost. num is whatever has been assigned to encoding.
83: *
84: * f
85: *
86: * size font f -
87: *
88: * Set the font and size used for character imaging. The font name
89: * argument is (normally) the name troff used. Mapping to the real
90: * PostScript font name is made using the fontname field in the
91: * ASCII width tables.
92: *
93: * m
94: *
95: * x y m -
96: *
97: * Move to point (x, y). Not used for positioning words in text
98: * strings.
99: *
100: * t
101: *
102: * mark text t mark
103: *
104: * Everything on the stack (up to the mark) is treated as a line
105: * of text to be decoded and printed. What's on the stack depends
106: * on encoding.
107: *
108: * w
109: *
110: * string x y w -
111: *
112: * Print a single word starting at position (x, y). Only used in
113: * the more complicated encoding schemes, like the ones based on
114: * widthshow.
115: *
116: * done
117: *
118: * Make sure the last page prints. Always called, but only needed
119: * when printing more than one page on each sheet of paper.
120: *
121: * output language from troff:
122: * all numbers are character strings
123: *
124: * sn size in points
125: * fn font as number from 1-n
126: * cx ascii character x
127: * Cxyz funny char xyz. terminated by white space
128: * Hn go to absolute horizontal position n
129: * Vn go to absolute vertical position n (down is positive)
130: * hn go n units horizontally (relative)
131: * vn ditto vertically
132: * nnc move right nn, then print c (exactly 2 digits!)
133: * (this wart is an optimization that shrinks output file size
134: * about 35% and run-time about 15% while preserving ascii-ness)
135: * Dt ...\n draw operation 't':
136: * Dl x y line from here by x,y
137: * Dc d circle of diameter d with left side here
138: * De x y ellipse of axes x,y with left side here
139: * Da x1 y1 x2 y2 arc counter-clockwise from current point (x, y) to
140: * (x + x1 + x2, y + y1 + y2)
141: * D~ x y x y ... wiggly line by x,y then x,y ...
142: * nb a end of line (information only -- no action needed)
143: * b = space before line, a = after
144: * p new page begins -- set v to 0
145: * #...\n comment
146: * x ...\n device control functions:
147: * x i init
148: * x T s name of device is s
149: * x r n h v resolution is n/inch
150: * h = min horizontal motion, v = min vert
151: * x p pause (can restart)
152: * x s stop -- done forever
153: * x t generate trailer
154: * x f n s font position n contains font s
155: * x H n set character height to n
156: * x S n set slant to N
157: *
158: * Subcommands like "i" are often spelled out like "init".
159: *
160: */
161:
162: #include <stdio.h>
163: #include <fcntl.h>
164: #include <signal.h>
165: #include <math.h>
166: #include <ctype.h>
167: #include <time.h>
168:
169: #include "comments.h" /* structuring comments */
170: #include "gen.h" /* general purpose definitions */
171: #include "path.h" /* prologue and a few other files */
172: #include "ext.h" /* external variable declarations */
173: #include "font.h" /* font table definitions */
174: #include "dpost.h" /* a few definitions just used here */
175: #include "motion.h" /* positioning macros */
176:
177: char *prologue = DPOST; /* the PostScript prologue */
178: char *colorfile = COLOR; /* color support */
179: char *drawfile = DRAW; /* drawing routines */
180: char *formfile = FORMFILE; /* multiple pages on each sheet */
181: char *baselinefile = BASELINE; /* for text along curved baseline */
182:
183: char *fontdir = FONTDIR; /* font table directories */
184: char *hostfontdir = NULL; /* host resident font directory */
185:
186: char *realdev = DEVNAME; /* use these width tables */
187: char devname[20] = ""; /* job formatted for this device */
188: Fontmap fontmap[] = FONTMAP; /* font translation table - emulation */
189: char *useencoding = NULL; /* text font encoding - from -E option */
190:
191: int copies = 1; /* copies of each sheet */
192: int printed = 0; /* pages processed and printed */
193: int formsperpage = 1; /* pages on each sheet of paper */
194: int picflag = ON; /* enable/disable picture inclusion */
195:
196: int encoding = DFLTENCODING; /* how text is translated to PostScript */
197: int realencoding = DFLTENCODING; /* where we started */
198: int maxencoding = MAXENCODING; /* max that users can select */
199:
200: int landscape = FALSE; /* for BoundingBox calculations only */
201: double magnification = 1.0;
202: double xoffset = 0.0;
203: double yoffset = 0.0;
204:
205: int smnt; /* special fonts start here */
206: int devres; /* device resolution */
207: int unitwidth; /* and unitwidth - from DESC file */
208:
209: char downloaded[MAXCH+32+ALPHABET]; /* status of charlib characters */
210:
211: int nfonts = 0; /* number of font positions */
212: int size = 10; /* current point size */
213: int font = 0; /* and font position */
214: int hpos = 0; /* where troff wants to be */
215: int vpos = 0;
216: float lastw = 0; /* width of the last input character */
217: int lastc = 0; /* its name (or index) - for charlib() */
218:
219: int fontheight = 0; /* points from x H ... */
220: int fontslant = 0; /* angle from x S ... */
221:
222: int res; /* resolution assumed in input file */
223: float widthfac = 1.0; /* for emulation = res/devres */
224:
225: int lastsize = -1; /* for tracking printer's current size */
226: int lastfont = -1; /* current font */
227: float lastx = -1; /* and current position */
228: int lasty = -1;
229: int lastend; /* where last character on this line was */
230:
231: int seenpage = FALSE; /* expect fonts are now all mounted */
232: int gotspecial = FALSE; /* append special fonts - emulation */
233:
234: float pointslop = SLOP; /* horizontal error in points */
235: int slop; /* and machine units */
236: int rvslop; /* to extend box in reverse video mode */
237:
238: int textcount = 0; /* strings accumulated so far */
239: int stringstart = 0; /* where the next one starts */
240: int spacecount = 0; /* spaces in current string */
241:
242: Line line[MAXSTACK+3]; /* data about words accumulated so far */
243: char strings[STRINGSPACE]; /* strings temporarily saved here */
244: char *strptr; /* next free slot in strings[] */
245:
246: FILE *tf = NULL; /* most output goes here */
247: FILE *fp_acct = NULL; /* accounting file */
248:
249: char *optnames = "a:c:e:m:n:o:p:tw:x:y:A:BC:E:J:F:H:L:OP:R:S:T:DI";
250:
251: extern int gotcolor; /* read *colorfile when TRUE */
252: extern Font fonts[]; /* data about every font we see */
253: extern Font *mount[]; /* troff mounts fonts here */
254:
255: /*****************************************************************************/
256:
257: main(agc, agv)
258:
259: int agc;
260: char *agv[];
261:
262: {
263:
264: /*
265: *
266: * Translates output from troff into PostScript. Input files must be formatted
267: * for the same device. Each input file begins on a new page.
268: *
269: */
270:
271: argc = agc; /* global so everyone can use them */
272: argv = agv;
273:
274: prog_name = argv[0]; /* for error messages */
275:
276: init_signals(); /* interrupt handling */
277: header(); /* structuring comments */
278: options(); /* command line options */
279: arguments(); /* translate the input files */
280: done(); /* add trailing comments etc. */
281: account(); /* job accounting data */
282:
283: exit(x_stat);
284:
285: } /* End of main */
286:
287: /*****************************************************************************/
288:
289: init_signals()
290:
291: {
292:
293: /*
294: *
295: * Make sure we handle interrupts.
296: *
297: */
298:
299: if ( signal(SIGINT, interrupt) == SIG_IGN ) {
300: signal(SIGINT, SIG_IGN);
301: signal(SIGQUIT, SIG_IGN);
302: signal(SIGHUP, SIG_IGN);
303: } else {
304: signal(SIGHUP, interrupt);
305: signal(SIGQUIT, interrupt);
306: } /* End else */
307:
308: signal(SIGTERM, interrupt);
309:
310: } /* End of init_signals */
311:
312: /*****************************************************************************/
313:
314: header()
315:
316: {
317:
318: int ch;
319: int old_optind = optind;
320:
321: /*
322: *
323: * Scan the option list for things needed now (e.g. prologue file), but could
324: * be changed from defaults. An attempt to follow to Adobe's 2.0 structuring
325: * conventions.
326: *
327: */
328:
329: while ( (ch = getopt(argc, argv, optnames)) != EOF )
330: if ( ch == 'L' )
331: setpaths(optarg);
332: else if ( ch == 'B' )
333: dobbox = TRUE;
334: else if ( ch == '?' )
335: error(FATAL, "");
336:
337: optind = old_optind; /* restored for options() */
338:
339: fprintf(stdout, "%s", NONCONFORMING);
340: fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
341: fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
342: fprintf(stdout, "%s %s\n", PAGES, ATEND);
343: if ( dobbox == TRUE )
344: fprintf(stdout, "%s %s\n", BOUNDINGBOX, ATEND);
345: fprintf(stdout, "%s", ENDCOMMENTS);
346:
347: if ( cat(prologue) == FALSE )
348: error(FATAL, "can't read %s", prologue);
349:
350: if ( DOROUND )
351: cat(ROUNDPAGE);
352:
353: fprintf(stdout, "%s", ENDPROLOG);
354: fprintf(stdout, "%s", BEGINSETUP);
355: fprintf(stdout, "mark\n");
356:
357: } /* End of header */
358:
359: /*****************************************************************************/
360:
361: options()
362:
363: {
364:
365: int ch;
366:
367: extern char *optarg;
368: extern int optind;
369:
370: /*
371: *
372: * Command line options - there are too many!
373: *
374: */
375:
376: while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
377: switch ( ch ) {
378: case 'a': /* aspect ratio */
379: fprintf(stdout, "/aspectratio %s def\n", optarg);
380: break;
381:
382: case 'c': /* number of copies */
383: copies = atoi(optarg);
384: fprintf(stdout, "/#copies %s store\n", optarg);
385: break;
386:
387: case 'e': /* select the encoding scheme */
388: if ( (encoding = atoi(optarg)) < 0 || encoding > MAXENCODING )
389: encoding = DFLTENCODING;
390: realencoding = encoding;
391: break;
392:
393: case 'm': /* magnification */
394: magnification = atof(optarg);
395: fprintf(stdout, "/magnification %s def\n", optarg);
396: break;
397:
398: case 'n': /* forms per page */
399: formsperpage = atoi(optarg);
400: fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
401: fprintf(stdout, "/formsperpage %s def\n", optarg);
402: break;
403:
404: case 'o': /* output page list */
405: out_list(optarg);
406: break;
407:
408: case 'p': /* landscape or portrait mode */
409: landscape = (*optarg == 'l') ? TRUE : FALSE;
410: if ( landscape == TRUE )
411: fprintf(stdout, "/landscape true def\n");
412: else fprintf(stdout, "/landscape false def\n");
413: break;
414:
415: case 't': /* compatibility */
416: break;
417:
418: case 'w': /* line width - for drawing */
419: fprintf(stdout, "/linewidth %s def\n", optarg);
420: break;
421:
422: case 'x': /* shift horizontally */
423: xoffset = atof(optarg);
424: fprintf(stdout, "/xoffset %s def\n", optarg);
425: break;
426:
427: case 'y': /* shift vertically */
428: yoffset = atof(optarg);
429: fprintf(stdout, "/yoffset %s def\n", optarg);
430: break;
431:
432: case 'A': /* job accounting */
433: case 'J':
434: if ( (fp_acct = fopen(optarg, "a")) == NULL )
435: error(FATAL, "can't open accounting file %s", optarg);
436: break;
437:
438: case 'B': /* enable BoundingBox calculations */
439: dobbox = TRUE;
440: fprintf(stdout, "/rotation 1 def\n");
441: fprintf(stdout, "/gotpagebbox true def\n");
442: break;
443:
444: case 'C': /* copy file to output */
445: if ( cat(optarg) == FALSE )
446: error(FATAL, "can't read %s", optarg);
447: break;
448:
449: case 'E': /* text font encoding - override DESC */
450: useencoding = optarg;
451: break;
452:
453: case 'F': /* font table directory */
454: fontdir = optarg;
455: break;
456:
457: case 'H': /* host resident font directory */
458: hostfontdir = optarg;
459: break;
460:
461: case 'L': /* prologue file */
462: setpaths(optarg); /* already been done in header() */
463: break;
464:
465: case 'O': /* disable picture inclusion */
466: picflag = OFF;
467: break;
468:
469: case 'P': /* copy string to output */
470: fprintf(stdout, "%s\n", optarg);
471: break;
472:
473: case 'R': /* global or page level request */
474: saverequest(optarg);
475: break;
476:
477: case 'S': /* horizontal position error */
478: if ( (pointslop = atof(optarg)) < 0 )
479: pointslop = 0;
480: break;
481:
482: case 'T': /* target printer */
483: realdev = optarg;
484: break;
485:
486: case 'D': /* debug flag */
487: debug = ON;
488: tf = stdout;
489: break;
490:
491: case 'I': /* ignore FATAL errors */
492: ignore = ON;
493: break;
494:
495: case '?': /* don't know the option */
496: error(FATAL, "");
497: break;
498:
499: default:
500: error(FATAL, "missing case for option %c", ch);
501: break;
502: } /* End switch */
503: } /* End while */
504:
505: argc -= optind;
506: argv += optind;
507:
508: } /* End of options */
509:
510: /*****************************************************************************/
511:
512: setpaths(name)
513:
514: char *name;
515:
516: {
517:
518: char *path;
519:
520: /*
521: *
522: * Extends the -L option to permit modification of more than just the prologue
523: * file pathname. Syntax is -Lpath or -Lname:path. For debugging and development
524: * only!
525: *
526: */
527:
528: for ( path = name; *path; path++ )
529: if ( *path == ':' || *path == ' ' ) {
530: while ( *path == ':' || *path == ' ' ) path++;
531: break;
532: } /* End if */
533:
534: if ( *path == '\0' ) /* didn't find "name:" prefix */
535: path = name;
536:
537: if ( path == name || strncmp(name, "prologue", strlen("prologue")) == 0 )
538: prologue = path;
539: else if ( strncmp(name, "draw", strlen("draw")) == 0 )
540: drawfile = path;
541: else if ( strncmp(name, "color", strlen("color")) == 0 )
542: colorfile = path;
543: else if ( strncmp(name, "form", strlen("form")) == 0 )
544: formfile = path;
545: else if ( strncmp(name, "baseline", strlen("baseline")) == 0 )
546: baselinefile = path;
547:
548: } /* End of setpaths */
549:
550: /*****************************************************************************/
551:
552: setup()
553:
554: {
555:
556: double t;
557:
558: /*
559: *
560: * Job and BoundingBox initialization. Called once from t_init() - must know
561: * the resolution before generating the PostScript call to setup. dpost only
562: * includes an encoding file if it's set in the DESC file or requested with
563: * the -E option.
564: *
565: */
566:
567: writerequest(0, stdout); /* global requests e.g. manual feed */
568: fprintf(stdout, "/resolution %d def\n", res);
569: if ( useencoding != NULL || fontencoding != NULL )
570: setencoding((useencoding != NULL) ? useencoding : fontencoding);
571: fprintf(stdout, "setup\n");
572: fprintf(stdout, "%d setdecoding\n", realencoding);
573:
574: if ( formsperpage > 1 ) { /* multiple pages */
575: if ( cat(formfile) == FALSE )
576: error(FATAL, "can't read %s", formfile);
577: fprintf(stdout, "%d setupforms\n", formsperpage);
578: } /* End if */
579:
580: fprintf(stdout, "%s", ENDSETUP);
581:
582: if ( dobbox == TRUE ) { /* ctm[] - must agree with prologue */
583: translate(pagewidth/2.0, pageheight/2.0);
584: if ( landscape == TRUE ) {
585: rotate(90.0);
586: t = pagewidth;
587: pagewidth = pageheight;
588: pageheight = t;
589: } /* End if */
590: translate(-pagewidth/2.0, pageheight/2.0);
591: translate(72.0 * xoffset, -72.0 * yoffset);
592: scale(magnification, magnification);
593: scale(72.0/devres, 72.0/devres);
594: } /* End if */
595:
596: } /* End of setup */
597:
598: /*****************************************************************************/
599:
600: arguments()
601:
602: {
603:
604: FILE *fp;
605:
606: /*
607: *
608: * Everything else is an input file. No arguments or '-' means stdin.
609: *
610: */
611:
612: if ( argc < 1 )
613: conv(stdin);
614: else
615: while ( argc > 0 ) {
616: if ( strcmp(*argv, "-") == 0 )
617: fp = stdin;
618: else if ( (fp = fopen(*argv, "r")) == NULL )
619: error(FATAL, "can't open %s", *argv);
620: conv(fp);
621: if ( fp != stdin )
622: fclose(fp);
623: argc--;
624: argv++;
625: } /* End while */
626:
627: } /* End of arguments */
628:
629: /*****************************************************************************/
630:
631: done()
632:
633: {
634:
635: int i;
636: int n;
637:
638: /*
639: *
640: * Force out the last page and add trailing comments.
641: *
642: */
643:
644: fprintf(stdout, "%s", TRAILER);
645: fprintf(stdout, "done\n");
646: fprintf(stdout, "%s %d\n", PAGES, printed);
647:
648: for ( i = 0, n = 0; i < MAXFONTS+1; i++ )
649: if ( (fonts[i].flags & USED) && fonts[i].fontname != NULL ) {
650: if ( n++ == 0 )
651: fprintf(stdout, "%s", DOCUMENTFONTS);
652: else if ( (n - 1) % 8 == 0 )
653: fprintf(stdout, "\n%s", CONTINUECOMMENT);
654: fprintf(stdout, " %s", fonts[i].fontname);
655: } /* End if */
656: if ( n > 0 )
657: putc('\n', stdout);
658:
659: if ( dobbox == TRUE )
660: writebbox(stdout, BOUNDINGBOX, 10);
661:
662: } /* End of done */
663:
664: /*****************************************************************************/
665:
666: account()
667:
668: {
669:
670: /*
671: *
672: * Accounting record to fp_acct - provided it's not NULL.
673: *
674: */
675:
676: if ( fp_acct != NULL )
677: fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
678:
679: } /* End of account */
680:
681: /*****************************************************************************/
682:
683: conv(fp)
684:
685: register FILE *fp;
686:
687: {
688:
689: register int c;
690: int m, n, n1, m1;
691: char str[50];
692:
693: /*
694: *
695: * Read troff output from file fp and translate it into PostScript. The final
696: * t_page() call means input files start on a new page.
697: *
698: */
699:
700: redirect(-1); /* do output only after a page command */
701: lineno = 1;
702:
703: while ((c = getc(fp)) != EOF) {
704: switch (c) {
705: case '\n': /* just count this line */
706: lineno++;
707: break;
708:
709: case ' ': /* when input is text */
710: case 0: /* occasional noise creeps in */
711: break;
712:
713: case '0': case '1': case '2': case '3': case '4':
714: case '5': case '6': case '7': case '8': case '9':
715: /* two motion digits plus a character */
716: hmot((c-'0')*10 + getc(fp)-'0');
717: put1(getc(fp));
718: break;
719:
720: case 'c': /* single ascii character */
721: put1(getc(fp));
722: break;
723:
724: case 'C': /* special character */
725: fscanf(fp, "%s", str);
726: put1(chindex(str));
727: break;
728:
729: case 'N': /* character at position n */
730: fscanf(fp, "%d", &m);
731: flushtext();
732: oput(m);
733: break;
734:
735: case 'D': /* drawing functions */
736: flushtext();
737: getdraw();
738: if ( size != lastsize )
739: t_sf();
740: switch ((c=getc(fp))) {
741: case 'p': /* draw a path */
742: while (fscanf(fp, "%d %d", &n, &m) == 2)
743: drawline(n, m);
744: lineno++;
745: break;
746:
747: case 'l': /* draw a line */
748: fscanf(fp, "%d %d %c", &n, &m, &n1);
749: drawline(n, m);
750: break;
751:
752: case 'c': /* circle */
753: fscanf(fp, "%d", &n);
754: drawcirc(n);
755: break;
756:
757: case 'e': /* ellipse */
758: fscanf(fp, "%d %d", &m, &n);
759: drawellip(m, n);
760: break;
761:
762: case 'a': /* counter-clockwise arc */
763: case 'A': /* clockwise arc */
764: fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1);
765: drawarc(n, m, n1, m1, c);
766: break;
767:
768: case 'q': /* spline without end points */
769: drawspline(fp, 1);
770: lineno++;
771: break;
772:
773: case '~': /* wiggly line */
774: drawspline(fp, 2);
775: lineno++;
776: break;
777:
778: default:
779: error(FATAL, "unknown drawing function %c", c);
780: break;
781: } /* End switch */
782: break;
783:
784: case 's': /* use this point size */
785: fscanf(fp, "%d", &size); /* ignore fractional sizes */
786: break;
787:
788: case 'f': /* use font mounted here */
789: fscanf(fp, "%s", str);
790: setfont(t_font(str));
791: break;
792:
793: case 'H': /* absolute horizontal motion */
794: fscanf(fp, "%d", &n);
795: hgoto(n);
796: break;
797:
798: case 'h': /* relative horizontal motion */
799: fscanf(fp, "%d", &n);
800: hmot(n);
801: break;
802:
803: case 'w': /* word space */
804: break;
805:
806: case 'V': /* absolute vertical position */
807: fscanf(fp, "%d", &n);
808: vgoto(n);
809: break;
810:
811: case 'v': /* relative vertical motion */
812: fscanf(fp, "%d", &n);
813: vmot(n);
814: break;
815:
816: case 'p': /* new page */
817: fscanf(fp, "%d", &n);
818: t_page(n);
819: break;
820:
821: case 'n': /* end of line */
822: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
823: hgoto(0);
824: lineno++;
825: break;
826:
827: case '#': /* comment */
828: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
829: lineno++;
830: break;
831:
832: case 'x': /* device control function */
833: devcntrl(fp);
834: lineno++;
835: break;
836:
837: default:
838: error(FATAL, "unknown input character %o %c", c, c);
839: done();
840: } /* End switch */
841: } /* End while */
842:
843: t_page(-1); /* print the last page */
844: flushtext();
845:
846: } /* End of conv */
847:
848: /*****************************************************************************/
849:
850: devcntrl(fp)
851:
852: FILE *fp;
853:
854: {
855:
856: char str[50], buf[256], str1[50];
857: int c, n;
858:
859: /*
860: *
861: * Interpret device control commands, ignoring any we don't recognize. The
862: * "x X ..." commands are a device dependent collection generated by troff's
863: * \X'...' request.
864: *
865: */
866:
867: fscanf(fp, "%s", str);
868:
869: switch ( str[0] ) {
870: case 'f': /* load font in a position */
871: fscanf(fp, "%d %s", &n, str);
872: fgets(buf, sizeof buf, fp); /* in case there's a filename */
873: ungetc('\n', fp); /* fgets() goes too far */
874: str1[0] = '\0'; /* in case there's nothing to come in */
875: sscanf(buf, "%s", str1);
876: loadfont(n, str, str1);
877: break;
878:
879: case 'i': /* initialize */
880: t_init();
881: break;
882:
883: case 'p': /* pause */
884: break;
885:
886: case 'r': /* resolution assumed when prepared */
887: fscanf(fp, "%d", &res);
888: break;
889:
890: case 's': /* stop */
891: case 't': /* trailer */
892: flushtext();
893: break;
894:
895: case 'H': /* char height */
896: fscanf(fp, "%d", &n);
897: t_charht(n);
898: break;
899:
900: case 'S': /* slant */
901: fscanf(fp, "%d", &n);
902: t_slant(n);
903: break;
904:
905: case 'T': /* device name */
906: fscanf(fp, "%s", devname);
907: break;
908:
909: case 'X': /* copy through - from troff */
910: fscanf(fp, " %[^: \n]:", str);
911: fgets(buf, sizeof(buf), fp);
912: ungetc('\n', fp);
913: if ( strcmp(str, "PI") == 0 || strcmp(str, "PictureInclusion") == 0 )
914: picture(buf);
915: else if ( strcmp(str, "InlinePicture") == 0 )
916: inlinepic(fp, buf);
917: else if ( strcmp(str, "BeginPath") == 0 )
918: beginpath(buf, FALSE);
919: else if ( strcmp(str, "DrawPath") == 0 )
920: drawpath(buf, FALSE);
921: else if ( strcmp(str, "BeginObject") == 0 )
922: beginpath(buf, TRUE);
923: else if ( strcmp(str, "EndObject") == 0 )
924: drawpath(buf, TRUE);
925: else if ( strcmp(str, "NewBaseline") == 0 )
926: newbaseline(buf);
927: else if ( strcmp(str, "DrawText") == 0 )
928: drawtext(buf);
929: else if ( strcmp(str, "SetText") == 0 )
930: settext(buf);
931: else if ( strcmp(str, "SetColor") == 0 ) {
932: newcolor(buf);
933: setcolor();
934: } else if ( strcmp(str, "PS") == 0 || strcmp(str, "PostScript") == 0 ) {
935: flushtext();
936: fprintf(tf, "%s", buf);
937: } /* End else */
938: break;
939: } /* End switch */
940:
941: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
942:
943: } /* End of devcntrl */
944:
945: /*****************************************************************************/
946:
947: loadfont(m, f, dir)
948:
949: int m;
950: char *f;
951: char *dir;
952:
953: {
954:
955: char path[150];
956:
957: /*
958: *
959: * Load position m with font f. Font file pathname is *fontdir/dev*realdev/*f
960: * or *dir/*f, if dir isn't empty. Use mapfont() to replace the missing font
961: * if we're emulating another device, dir is empty, and the first mount fails.
962: *
963: */
964:
965: if ( dir[0] == '\0' )
966: sprintf(path, "%s/dev%s/%s", fontdir, realdev, f);
967: else sprintf(path, "%s/%s", dir, f);
968:
969: if ( mountfont(path, m) == -1 ) {
970: if ( dir[0] == '\0' ) {
971: sprintf(path, "%s/dev%s/%s", fontdir, realdev, mapfont(f));
972: if ( mountfont(path, m) == -1 ) {
973: sprintf(path, "%s/dev%s/%s", fontdir, realdev, f);
974: error(FATAL, "can't load %s at %d", path, m);
975: } /* End if */
976: } else error(FATAL, "can't load %s at %d", path, m);
977: } /* End if */
978:
979: if ( smnt == 0 && mount[m]->specfont )
980: smnt = m;
981:
982: if ( m == lastfont ) /* force a call to t_sf() */
983: lastfont = -1;
984:
985: if ( m > nfonts ) { /* got more positions */
986: nfonts = m;
987: gotspecial = FALSE;
988: } /* End if */
989:
990: } /* End of loadfont */
991:
992: /*****************************************************************************/
993:
994: char *mapfont(name)
995:
996: char *name;
997:
998: {
999:
1000: int i;
1001:
1002: /*
1003: *
1004: * Map a missing font name into one that should be available. Only used when
1005: * we're emulating another device and the first mount fails. Consider deleting
1006: * this routine.
1007: *
1008: */
1009:
1010: for ( i = 0; fontmap[i].name != NULL; i++ )
1011: if ( strcmp(name, fontmap[i].name) == 0 )
1012: return(fontmap[i].use);
1013:
1014: switch ( *++name ) {
1015: case 'I': return("I");
1016: case 'B': return("B");
1017: case 'X': return("BI");
1018: default: return("R");
1019: } /* End switch */
1020:
1021: } /* End of mapfont */
1022:
1023: /*****************************************************************************/
1024:
1025: loadspecial()
1026:
1027: {
1028:
1029: /*
1030: *
1031: * Fix - later.
1032: *
1033: */
1034:
1035: gotspecial = TRUE;
1036:
1037: } /* End of loadspecial */
1038:
1039: /*****************************************************************************/
1040:
1041: t_init()
1042:
1043: {
1044:
1045: char path[150];
1046: static int initialized = FALSE;
1047:
1048: /*
1049: *
1050: * Finish initialization - just read an "x init" command. Assumes we already
1051: * know the input file resolution.
1052: *
1053: */
1054:
1055: flushtext(); /* moved - for cat'ed troff files */
1056:
1057: if ( initialized == FALSE ) {
1058: if ( strcmp(devname, realdev) ) {
1059: sprintf(path, "%s/dev%s/DESC", fontdir, devname);
1060: if ( checkdesc(path) )
1061: realdev = devname;
1062: } /* End if */
1063:
1064: sprintf(path, "%s/dev%s/DESC", fontdir, realdev);
1065: if ( getdesc(path) == -1 )
1066: error(FATAL, "can't open %s", path);
1067: nfonts = 0;
1068: gotspecial = FALSE;
1069: widthfac = (float) res /devres;
1070: slop = pointslop * res / POINTS + .5;
1071: rvslop = res * .025;
1072: setup();
1073: initialized = TRUE;
1074: } /* End if */
1075:
1076: hpos = vpos = 0;
1077: size = 10;
1078: reset();
1079:
1080: } /* End of t_init */
1081:
1082: /*****************************************************************************/
1083:
1084: t_page(pg)
1085:
1086: int pg;
1087:
1088: {
1089:
1090: static int lastpg = 0;
1091:
1092: /*
1093: *
1094: * Finish the previous page and get ready for the next one. End page output
1095: * goes to /dev/null at the start of each input file. Start page output goes
1096: * to /dev/null at the end of each input file.
1097: *
1098: * Consider doing showpage after page level restore (as Adobe recommends). If
1099: * the order is changed use restore() and save(). forms.ps will likely also
1100: * need fixing.
1101: *
1102: */
1103:
1104: if ( tf == stdout )
1105: printed++;
1106:
1107: flushtext(); /* just in case */
1108:
1109: fprintf(tf, "cleartomark\n");
1110: fprintf(tf, "showpage\n");
1111: fprintf(tf, "saveobj restore\n");
1112: if ( dobbox == TRUE )
1113: writebbox(tf, PAGEBOUNDINGBOX, 10);
1114: fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed);
1115:
1116: redirect(pg);
1117:
1118: fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1);
1119: if ( dobbox == TRUE )
1120: fprintf(tf, "%s %s\n", PAGEBOUNDINGBOX, ATEND);
1121: fprintf(tf, "/saveobj save def\n");
1122: fprintf(tf, "mark\n");
1123: writerequest(printed+1, tf);
1124: fprintf(tf, "%d pagesetup\n", printed+1);
1125:
1126: if ( encoding != realencoding )
1127: fprintf(tf, "%d setdecoding\n", encoding);
1128:
1129: if ( gotcolor == TRUE )
1130: setcolor();
1131:
1132: lastpg = pg; /* for the next ENDPAGE comment */
1133: hpos = vpos = 0; /* get ready for the next page */
1134: reset(); /* force position and font stuff - later */
1135:
1136: seenpage = TRUE;
1137:
1138: } /* End of t_page */
1139:
1140: /*****************************************************************************/
1141:
1142: t_font(s)
1143:
1144: char *s;
1145:
1146: {
1147:
1148: int n;
1149:
1150: /*
1151: *
1152: * Converts the string *s into an integer and checks to make sure it's a legal
1153: * font position. Also arranges to mount all the special fonts after the last
1154: * legitimate font (by calling loadspecial()), provided it hasn't already been
1155: * done.
1156: *
1157: */
1158:
1159: n = atoi(s);
1160:
1161: if ( seenpage == TRUE ) {
1162: if ( n < 0 || n > nfonts )
1163: error(FATAL, "illegal font position %d", n);
1164:
1165: if ( gotspecial == FALSE )
1166: loadspecial();
1167: } /* End if */
1168:
1169: return(n);
1170:
1171: } /* End of t_font */
1172:
1173: /*****************************************************************************/
1174:
1175: setfont(m)
1176:
1177: int m;
1178:
1179: {
1180:
1181: /*
1182: *
1183: * Use the font mounted at position m. Bounds checks are probably unnecessary.
1184: * Changing the font and size used by the printer is handled in t_sf().
1185: *
1186: */
1187:
1188: if ( m < 0 || m > MAXFONTS )
1189: error(FATAL, "illegal font %d", m);
1190: font = m;
1191:
1192: } /* End of setfont */
1193:
1194: /*****************************************************************************/
1195:
1196: t_sf()
1197:
1198: {
1199:
1200: Font *fpos;
1201: char temp[150];
1202:
1203: /*
1204: *
1205: * Force a new font or size. Generates name definitions for fonts that haven't
1206: * been named, grabs host resident font files and keeps track of the fonts used
1207: * by this job. When necessary also adjusts the font's height and slant. Should
1208: * only be called immediately before printing a character.
1209: *
1210: */
1211:
1212: if ( tf == stdout && mounted(font) ) {
1213: flushtext();
1214:
1215: fpos = mount[font];
1216: if ( (fpos->flags & USED) == 0 ) {
1217: if ( (fpos->flags & NAMED) == 0 && fpos->fontname != NULL ) {
1218: sprintf(temp, "/%s /%s def\n", fpos->name, fpos->fontname);
1219: exportstring(temp);
1220: fpos->flags |= NAMED; /* unnecessary */
1221: } /* End if */
1222:
1223: if ( hostfontdir != NULL ) {
1224: sprintf(temp, "%s/%s", hostfontdir, fpos->name);
1225: exportfile(temp);
1226: } /* End if */
1227: } /* End if */
1228:
1229: fprintf(tf, "%d %s f\n", size, fpos->name);
1230: if ( fontheight != 0 || fontslant != 0 )
1231: fprintf(tf, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : size);
1232:
1233: lastfont = font;
1234: lastsize = size;
1235: fpos->flags |= USED;
1236: } /* End if */
1237:
1238: } /* End of t_sf */
1239:
1240: /*****************************************************************************/
1241:
1242: t_charht(n)
1243:
1244: int n;
1245:
1246: {
1247:
1248: /*
1249: *
1250: * Set character height to n points. Disabled if n is 0 or the current size.
1251: *
1252: */
1253:
1254: fontheight = (n == size) ? 0 : n;
1255: lastfont = -1;
1256:
1257: } /* End of t_charht */
1258:
1259: /*****************************************************************************/
1260:
1261: t_slant(n)
1262:
1263: int n;
1264:
1265: {
1266:
1267: /*
1268: *
1269: * Set slant to n degrees. Disable slanting if n is 0.
1270: *
1271: */
1272:
1273: fontslant = n;
1274: lastfont = -1;
1275:
1276: } /* End of t_slant */
1277:
1278: /*****************************************************************************/
1279:
1280: xymove(x, y)
1281:
1282: int x, y;
1283:
1284: {
1285:
1286: /*
1287: *
1288: * Make the the printer and post-processor agree about the current position.
1289: *
1290: */
1291:
1292: flushtext();
1293:
1294: hgoto(x);
1295: vgoto(y);
1296:
1297: fprintf(tf, "%d %d m\n", hpos, vpos);
1298:
1299: lastx = hpos;
1300: lasty = vpos;
1301:
1302: } /* End of xymove */
1303:
1304: /*****************************************************************************/
1305:
1306: put1(c)
1307:
1308: register int c;
1309:
1310: {
1311:
1312: register int i;
1313: register int j;
1314: register int k;
1315: int code;
1316: int ofont;
1317:
1318: /*
1319: *
1320: * Print character c. ASCII if c < ALPHABET, otherwise it's special. Look for
1321: * c in the current font, then in others starting at the first special font.
1322: * Save c in lastc so it's available when oput() runs. Restore original font
1323: * before leaving.
1324: *
1325: */
1326:
1327: lastc = c; /* charlib() needs name not code */
1328: if ( (c -= 32) <= 0 )
1329: return;
1330:
1331: k = ofont = font;
1332:
1333: if ( (i = onfont(lastc, k)) == -1 && smnt > 0 )
1334: for ( k = smnt, j = 0; j < nfonts; j++, k = k % nfonts + 1 ) {
1335: if ( (i = onfont(lastc, k)) != -1 ) {
1336: setfont(k);
1337: break;
1338: } /* End if */
1339: } /* End for */
1340:
1341: if ( i != -1 && (code = mount[k]->wp[i].code) != 0 ) {
1342: lastw = widthfac * (((int)mount[k]->wp[i].wid * size + unitwidth/2) / unitwidth);
1343: oput(code);
1344: } /* End if */
1345:
1346: if ( font != ofont )
1347: setfont(ofont);
1348:
1349: } /* End of put1 */
1350:
1351: /*****************************************************************************/
1352:
1353: oput(c)
1354:
1355: int c;
1356:
1357: {
1358:
1359: double llx, lly, urx, ury; /* boundingbox corners */
1360:
1361: /*
1362: *
1363: * Arranges to print the character whose code is c in the current font. All the
1364: * actual positioning is done here, in charlib(), or in the drawing routines.
1365: *
1366: */
1367:
1368: if ( textcount > MAXSTACK ) /* don't put too much on the stack? */
1369: flushtext();
1370:
1371: if ( font != lastfont || size != lastsize )
1372: t_sf();
1373:
1374: if ( vpos != lasty )
1375: endline();
1376:
1377: starttext();
1378:
1379: if ( ABS(hpos - lastx) > slop )
1380: endstring();
1381:
1382: if ( isascii(c) && isprint(c) )
1383: switch ( c ) {
1384: case '(':
1385: case ')':
1386: case '\\':
1387: addchar('\\');
1388:
1389: default:
1390: addchar(c);
1391: } /* End switch */
1392: else if ( c > 040 )
1393: addoctal(c);
1394: else charlib(c);
1395:
1396: if ( dobbox == TRUE ) {
1397: llx = lastx;
1398: lly = -(vpos + 0.5 * (devres * size / 72.0));
1399: urx = lastx + lastw;
1400: ury = -(vpos - (devres * size / 72.0));
1401: cover(llx, lly);
1402: cover(urx, ury);
1403: } /* End if */
1404:
1405: lastx += lastw;
1406:
1407: } /* End of oput */
1408:
1409: /*****************************************************************************/
1410:
1411: starttext()
1412:
1413: {
1414:
1415: /*
1416: * Called whenever we want to be sure we're ready to start collecting characters
1417: * for the next call to PostScript procedure t (ie. the one that prints them). If
1418: * textcount is positive we've already started, so there's nothing to do. The more
1419: * complicated encoding schemes save text strings in the strings[] array and need
1420: * detailed information about the strings when they're written to the output file
1421: * in flushtext().
1422: *
1423: */
1424:
1425: if ( textcount < 1 ) {
1426: switch ( encoding ) {
1427: case 0:
1428: case 1:
1429: putc('(', tf);
1430: break;
1431:
1432: case 2:
1433: case 3:
1434: strptr = strings;
1435: spacecount = 0;
1436: line[1].str = strptr;
1437: line[1].dx = 0;
1438: line[1].spaces = 0;
1439: line[1].start = hpos;
1440: line[1].width = 0;
1441: break;
1442:
1443: case MAXENCODING+1: /* reverse video */
1444: if ( lastend == -1 )
1445: lastend = hpos;
1446: putc('(', tf);
1447: break;
1448:
1449: case MAXENCODING+2: /* follow a funny baseline */
1450: putc('(', tf);
1451: break;
1452: } /* End switch */
1453:
1454: textcount = 1;
1455: lastx = stringstart = hpos;
1456: } /* End if */
1457:
1458: } /* End of starttext */
1459:
1460: /*****************************************************************************/
1461:
1462: flushtext()
1463:
1464: {
1465:
1466: int i;
1467:
1468: /*
1469: *
1470: * Generates a call to the PostScript procedure that processes all the text we've
1471: * accumulated - provided textcount is positive.
1472: *
1473: */
1474:
1475: if ( textcount > 0 ) {
1476: switch ( encoding ) {
1477: case 0:
1478: fprintf(tf, ")%d t\n", stringstart);
1479: break;
1480:
1481: case 1:
1482: fprintf(tf, ")%d %d t\n", stringstart, lasty);
1483: break;
1484:
1485: case 2:
1486: *strptr = '\0';
1487: line[textcount].width = lastx - line[textcount].start;
1488: if ( spacecount != 0 || textcount != 1 ) {
1489: for ( i = textcount; i > 0; i-- )
1490: fprintf(tf, "(%s)%d %d", line[i].str, line[i].spaces, line[i].width);
1491: fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
1492: } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
1493: break;
1494:
1495: case 3:
1496: *strptr = '\0';
1497: if ( spacecount != 0 || textcount != 1 ) {
1498: for ( i = textcount; i > 0; i-- )
1499: fprintf(tf, "(%s)%d", line[i].str, line[i].dx);
1500: fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
1501: } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
1502: break;
1503:
1504: case MAXENCODING+1:
1505: fprintf(tf, ")%d ", stringstart);
1506: fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop);
1507: fprintf(tf, "t\n", stringstart);
1508: lastend = (lastx + .5) + 2 * rvslop;
1509: break;
1510:
1511: case MAXENCODING+2:
1512: fprintf(tf, ")%d %d t\n", stringstart, lasty);
1513: break;
1514: } /* End switch */
1515: } /* End if */
1516:
1517: textcount = 0;
1518:
1519: } /* End of flushtext */
1520:
1521: /*****************************************************************************/
1522:
1523: endstring()
1524:
1525: {
1526:
1527: int dx;
1528:
1529: /*
1530: *
1531: * Horizontal positions are out of sync. End the last open string, adjust the
1532: * printer's position, and start a new string. Assumes we've already started
1533: * accumulating text.
1534: *
1535: */
1536:
1537: switch ( encoding ) {
1538: case 0:
1539: case 1:
1540: fprintf(tf, ")%d(", stringstart);
1541: textcount++;
1542: lastx = stringstart = hpos;
1543: break;
1544:
1545: case 2:
1546: case 3:
1547: dx = hpos - lastx;
1548: if ( spacecount++ == 0 )
1549: line[textcount].dx = dx;
1550: if ( line[textcount].dx != dx ) {
1551: *strptr++ = '\0';
1552: line[textcount].width = lastx - line[textcount].start;
1553: line[++textcount].str = strptr;
1554: *strptr++ = ' ';
1555: line[textcount].dx = dx;
1556: line[textcount].start = lastx;
1557: line[textcount].width = 0;
1558: line[textcount].spaces = 1;
1559: } else {
1560: *strptr++ = ' ';
1561: line[textcount].spaces++;
1562: } /* End else */
1563: lastx += dx;
1564: break;
1565:
1566: case MAXENCODING+1:
1567: fprintf(tf, ")%d(", stringstart);
1568: textcount++;
1569: lastx = stringstart = hpos;
1570: break;
1571:
1572: case MAXENCODING+2:
1573: flushtext();
1574: starttext();
1575: break;
1576: } /* End switch */
1577:
1578: } /* End of endstring */
1579:
1580: /*****************************************************************************/
1581:
1582: endline()
1583:
1584: {
1585:
1586: /*
1587: *
1588: * The vertical position has changed. Dump any accumulated text, then adjust
1589: * the printer's vertical position.
1590: *
1591: */
1592:
1593: flushtext();
1594:
1595: if ( encoding == 0 || encoding == MAXENCODING+1 )
1596: fprintf(tf, "%d %d m\n", hpos, vpos);
1597:
1598: lastx = stringstart = lastend = hpos;
1599: lasty = vpos;
1600:
1601: } /* End of endline */
1602:
1603: /*****************************************************************************/
1604:
1605: addchar(c)
1606:
1607: int c;
1608:
1609: {
1610:
1611: /*
1612: *
1613: * Does whatever is needed to add character c to the current string.
1614: *
1615: */
1616:
1617: switch ( encoding ) {
1618: case 0:
1619: case 1:
1620: putc(c, tf);
1621: break;
1622:
1623: case 2:
1624: case 3:
1625: *strptr++ = c;
1626: break;
1627:
1628: case MAXENCODING+1:
1629: case MAXENCODING+2:
1630: putc(c, tf);
1631: break;
1632: } /* End switch */
1633:
1634: } /* End of addchar */
1635:
1636: /*****************************************************************************/
1637:
1638: addoctal(c)
1639:
1640: int c;
1641:
1642: {
1643:
1644: /*
1645: *
1646: * Add c to the current string as an octal escape.
1647: *
1648: */
1649:
1650: switch ( encoding ) {
1651: case 0:
1652: case 1:
1653: fprintf(tf, "\\%o", c);
1654: break;
1655:
1656: case 2:
1657: case 3:
1658: sprintf(strptr, "\\%o", c);
1659: strptr += strlen(strptr);
1660: break;
1661:
1662: case MAXENCODING+1:
1663: case MAXENCODING+2:
1664: fprintf(tf, "\\%o", c);
1665: break;
1666: } /* End switch */
1667:
1668: } /* End of addoctal */
1669:
1670: /*****************************************************************************/
1671:
1672: charlib(code)
1673:
1674: int code; /* either 1 or 2 */
1675:
1676: {
1677:
1678: char *name; /* name of the character */
1679: char tname[10]; /* in case it's a single ASCII character */
1680: char temp[150];
1681:
1682: /*
1683: *
1684: * Called from oput() for characters having codes less than 040. Special files
1685: * that define PostScript procedures for certain characters can be found in
1686: * directory *fontdir/devpost/charlib. If there's a file that has the same name as
1687: * the character we're trying to print it's copied to the output file, otherwise
1688: * nothing, except some positioning, is done.
1689: *
1690: * All character definitions are only made once. Subsequent requests to print the
1691: * character generate a call to a procedure that begins with the prefix build_ and
1692: * ends with the character's name. Special characters that are assigned codes
1693: * other than 1 are assumed to have additional data files that should be copied
1694: * to the output file immediately after the build_ call. Those data files should
1695: * end in the suffix .map, and usually will be a hex representation of a bitmap.
1696: *
1697: */
1698:
1699: flushtext();
1700:
1701: if ( lastc < ALPHABET ) { /* ASCII character */
1702: sprintf(tname, "%.3o", lastc);
1703: name = tname;
1704: } else name = chname(lastc);
1705:
1706: if ( downloaded[lastc] == 0 ) {
1707: sprintf(temp, "%s/dev%s/charlib/%s", fontdir, realdev, name);
1708: if ( exportfile(temp) == TRUE ) {
1709: downloaded[lastc] = 1;
1710: t_sf();
1711: } /* End if */
1712: } /* End if */
1713:
1714: if ( downloaded[lastc] == 1 ) {
1715: xymove(hpos, vpos);
1716: fprintf(tf, "%d build_%s\n", (int) lastw, name);
1717: if ( code != 1 ) { /* get the bitmap or whatever */
1718: sprintf(temp, "%s/dev%s/charlib/%s.map", fontdir, realdev, name);
1719: if ( access(temp, 04) == 0 && tf == stdout )
1720: cat(temp);
1721: } /* End if */
1722: fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos);
1723: } /* End if */
1724:
1725: } /* End of charlib */
1726:
1727: /*****************************************************************************/
1728:
1729: reset()
1730:
1731: {
1732:
1733: /*
1734: *
1735: * Reset variables that keep track of the printer's current position, size and
1736: * font. Eventually forces things back in sync before oput() prints the next
1737: * character.
1738: *
1739: */
1740:
1741: lastx = -(slop + 1);
1742: lasty = -1;
1743: lastfont = lastsize = -1;
1744:
1745: } /* End of reset */
1746:
1747: /*****************************************************************************/
1748:
1749: resetpos()
1750:
1751: {
1752:
1753: /*
1754: *
1755: * Reset the position tracking variables. Forces oput() to get positions back
1756: * in sync before printing the next character.
1757: *
1758: */
1759:
1760: lastx = -(slop + 1);
1761: lasty = -1;
1762:
1763: } /* End of resetpos */
1764:
1765: /*****************************************************************************/
1766:
1767: save()
1768:
1769: {
1770:
1771: /*
1772: *
1773: * Save the current PostScript environment. Initialize things that may have
1774: * disappeared after the preceeding restore.
1775: *
1776: */
1777:
1778: fprintf(tf, "/saveobj save def\n");
1779: fprintf(tf, "mark\n");
1780:
1781: if ( encoding != realencoding )
1782: fprintf(tf, "%d setdecoding\n", encoding);
1783:
1784: if ( gotcolor == TRUE ) /* prevent getcolor() recursion */
1785: setcolor();
1786:
1787: } /* End of save */
1788:
1789: /*****************************************************************************/
1790:
1791: restore()
1792:
1793: {
1794:
1795: /*
1796: *
1797: * Restore the previous PostScript environment.
1798: *
1799: */
1800:
1801: flushtext();
1802: fprintf(tf, "cleartomark\n");
1803: fprintf(tf, "saveobj restore\n");
1804: reset();
1805:
1806: } /* End of restore */
1807:
1808: /*****************************************************************************/
1809:
1810: exportfile(path)
1811:
1812: char *path;
1813:
1814: {
1815:
1816: int val = FALSE;
1817:
1818: /*
1819: *
1820: * Exports the contents of file path to the global environment. Returns TRUE
1821: * if we're doing output (i.e. tf == stdout) and the copy worked.
1822: *
1823: */
1824:
1825: if ( tf == stdout && access(path, 04) == 0 ) {
1826: restore();
1827: fprintf(tf, "%s", BEGINGLOBAL);
1828: val = cat(path);
1829: fprintf(tf, "%s", ENDGLOBAL);
1830: save();
1831: } /* End if */
1832:
1833: return(val);
1834:
1835: } /* End of exportfile */
1836:
1837: /*****************************************************************************/
1838:
1839: exportstring(str)
1840:
1841: char *str;
1842:
1843: {
1844:
1845: /*
1846: *
1847: * Exports string str to the global environment. No return value needed yet.
1848: *
1849: */
1850:
1851: if ( tf == stdout && str != NULL && *str != '\0' ) {
1852: restore();
1853: fprintf(tf, "%s", BEGINGLOBAL);
1854: fprintf(tf, "%s", str);
1855: fprintf(tf, "%s", ENDGLOBAL);
1856: save();
1857: } /* End if */
1858:
1859: } /* End of exportstring */
1860:
1861: /*****************************************************************************/
1862:
1863: redirect(pg)
1864:
1865: int pg;
1866:
1867: {
1868:
1869: static FILE *fp_null = NULL;
1870:
1871: /*
1872: *
1873: * If we're not supposed to print page pg, tf will be directed to /dev/null,
1874: * otherwise output goes to stdout.
1875: *
1876: */
1877:
1878: if ( pg >= 0 && in_olist(pg) == ON )
1879: tf = stdout;
1880: else if ( (tf = fp_null) == NULL )
1881: tf = fp_null = fopen("/dev/null", "w");
1882:
1883: } /* End of redirect */
1884:
1885: /*****************************************************************************/
1886:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.