|
|
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[100];
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, "INFO") == 0 ) {
935: flushtext();
936: fprintf(tf, "%%INFO%s", buf);
937: } else if ( strcmp(str, "PS") == 0 || strcmp(str, "PostScript") == 0 ) {
938: flushtext();
939: fprintf(tf, "%s", buf);
940: } else if ( strcmp(str, "ExportPS") == 0 ) { /* dangerous!! */
941: if ( tf == stdout ) {
942: restore();
943: fprintf(tf, "%s", buf);
944: save();
945: } /* End if */
946: } /* End else */
947: break;
948: } /* End switch */
949:
950: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
951:
952: } /* End of devcntrl */
953:
954: /*****************************************************************************/
955:
956: loadfont(m, f, name)
957:
958: int m;
959: char *f;
960: char *name;
961:
962: {
963:
964: char path[150];
965:
966: /*
967: *
968: * Load position m with font f. Font file pathname is *fontdir/dev*realdev/*f
969: * or name, if name isn't empty. Use mapfont() to replace the missing font
970: * if we're emulating another device, name is empty, and the first mount
971: * fails.
972: *
973: */
974:
975: if ( name[0] == '\0' )
976: sprintf(path, "%s/dev%s/%s", fontdir, realdev, f);
977: else sprintf(path, "%s", name);
978:
979: if ( mountfont(path, m) == -1 ) {
980: if ( name[0] == '\0' ) {
981: sprintf(path, "%s/dev%s/%s", fontdir, realdev, mapfont(f));
982: if ( mountfont(path, m) == -1 ) {
983: sprintf(path, "%s/dev%s/%s", fontdir, realdev, f);
984: error(FATAL, "can't load %s at %d", path, m);
985: } /* End if */
986: } else error(FATAL, "can't load %s at %d", path, m);
987: } /* End if */
988:
989: if ( smnt == 0 && mount[m]->specfont )
990: smnt = m;
991:
992: if ( m == lastfont ) /* force a call to t_sf() */
993: lastfont = -1;
994:
995: if ( m > nfonts ) { /* got more positions */
996: nfonts = m;
997: gotspecial = FALSE;
998: } /* End if */
999:
1000: } /* End of loadfont */
1001:
1002: /*****************************************************************************/
1003:
1004: char *mapfont(name)
1005:
1006: char *name;
1007:
1008: {
1009:
1010: int i;
1011:
1012: /*
1013: *
1014: * Map a missing font name into one that should be available. Only used when
1015: * we're emulating another device and the first mount fails. Consider deleting
1016: * this routine.
1017: *
1018: */
1019:
1020: for ( i = 0; fontmap[i].name != NULL; i++ )
1021: if ( strcmp(name, fontmap[i].name) == 0 )
1022: return(fontmap[i].use);
1023:
1024: switch ( *++name ) {
1025: case 'I': return("I");
1026: case 'B': return("B");
1027: case 'X': return("BI");
1028: default: return("R");
1029: } /* End switch */
1030:
1031: } /* End of mapfont */
1032:
1033: /*****************************************************************************/
1034:
1035: loadspecial()
1036:
1037: {
1038:
1039: /*
1040: *
1041: * Fix - later.
1042: *
1043: */
1044:
1045: gotspecial = TRUE;
1046:
1047: } /* End of loadspecial */
1048:
1049: /*****************************************************************************/
1050:
1051: t_init()
1052:
1053: {
1054:
1055: char path[150];
1056: static int initialized = FALSE;
1057:
1058: /*
1059: *
1060: * Finish initialization - just read an "x init" command. Assumes we already
1061: * know the input file resolution.
1062: *
1063: */
1064:
1065: flushtext(); /* moved - for cat'ed troff files */
1066:
1067: if ( initialized == FALSE ) {
1068: if ( strcmp(devname, realdev) ) {
1069: sprintf(path, "%s/dev%s/DESC", fontdir, devname);
1070: if ( checkdesc(path) )
1071: realdev = devname;
1072: } /* End if */
1073:
1074: sprintf(path, "%s/dev%s/DESC", fontdir, realdev);
1075: if ( getdesc(path) == -1 )
1076: error(FATAL, "can't open %s", path);
1077: nfonts = 0;
1078: gotspecial = FALSE;
1079: widthfac = (float) res /devres;
1080: slop = pointslop * res / POINTS + .5;
1081: rvslop = res * .025;
1082: setup();
1083: initialized = TRUE;
1084: } /* End if */
1085:
1086: hpos = vpos = 0;
1087: size = 10;
1088: reset();
1089:
1090: } /* End of t_init */
1091:
1092: /*****************************************************************************/
1093:
1094: t_page(pg)
1095:
1096: int pg;
1097:
1098: {
1099:
1100: static int lastpg = 0;
1101:
1102: /*
1103: *
1104: * Finish the previous page and get ready for the next one. End page output
1105: * goes to /dev/null at the start of each input file. Start page output goes
1106: * to /dev/null at the end of each input file.
1107: *
1108: * Consider doing showpage after page level restore (as Adobe recommends). If
1109: * the order is changed use restore() and save(). forms.ps will likely also
1110: * need fixing.
1111: *
1112: */
1113:
1114: if ( tf == stdout )
1115: printed++;
1116:
1117: flushtext(); /* just in case */
1118:
1119: fprintf(tf, "cleartomark\n");
1120: fprintf(tf, "showpage\n");
1121: fprintf(tf, "saveobj restore\n");
1122: if ( dobbox == TRUE )
1123: writebbox(tf, PAGEBOUNDINGBOX, 10);
1124: fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed);
1125:
1126: redirect(pg);
1127:
1128: fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1);
1129: if ( dobbox == TRUE )
1130: fprintf(tf, "%s %s\n", PAGEBOUNDINGBOX, ATEND);
1131: fprintf(tf, "/saveobj save def\n");
1132: fprintf(tf, "mark\n");
1133: writerequest(printed+1, tf);
1134: fprintf(tf, "%d pagesetup\n", printed+1);
1135:
1136: if ( encoding != realencoding )
1137: fprintf(tf, "%d setdecoding\n", encoding);
1138:
1139: if ( gotcolor == TRUE )
1140: setcolor();
1141:
1142: lastpg = pg; /* for the next ENDPAGE comment */
1143: hpos = vpos = 0; /* get ready for the next page */
1144: reset(); /* force position and font stuff - later */
1145:
1146: seenpage = TRUE;
1147:
1148: } /* End of t_page */
1149:
1150: /*****************************************************************************/
1151:
1152: t_font(s)
1153:
1154: char *s;
1155:
1156: {
1157:
1158: int n;
1159:
1160: /*
1161: *
1162: * Converts the string *s into an integer and checks to make sure it's a legal
1163: * font position. Also arranges to mount all the special fonts after the last
1164: * legitimate font (by calling loadspecial()), provided it hasn't already been
1165: * done.
1166: *
1167: */
1168:
1169: n = atoi(s);
1170:
1171: if ( seenpage == TRUE ) {
1172: if ( n < 0 || n > nfonts )
1173: error(FATAL, "illegal font position %d", n);
1174:
1175: if ( gotspecial == FALSE )
1176: loadspecial();
1177: } /* End if */
1178:
1179: return(n);
1180:
1181: } /* End of t_font */
1182:
1183: /*****************************************************************************/
1184:
1185: setfont(m)
1186:
1187: int m;
1188:
1189: {
1190:
1191: /*
1192: *
1193: * Use the font mounted at position m. Bounds checks are probably unnecessary.
1194: * Changing the font and size used by the printer is handled in t_sf().
1195: *
1196: */
1197:
1198: if ( m < 0 || m > MAXFONTS )
1199: error(FATAL, "illegal font %d", m);
1200: font = m;
1201:
1202: } /* End of setfont */
1203:
1204: /*****************************************************************************/
1205:
1206: t_sf()
1207:
1208: {
1209:
1210: Font *fpos;
1211: char temp[150];
1212:
1213: /*
1214: *
1215: * Force a new font or size. Generates name definitions for fonts that haven't
1216: * been named, grabs host resident font files and keeps track of the fonts used
1217: * by this job. When necessary also adjusts the font's height and slant. Should
1218: * only be called immediately before printing a character.
1219: *
1220: */
1221:
1222: if ( tf == stdout && mounted(font) ) {
1223: flushtext();
1224:
1225: fpos = mount[font];
1226: if ( (fpos->flags & USED) == 0 ) {
1227: if ( (fpos->flags & NAMED) == 0 && fpos->fontname != NULL ) {
1228: sprintf(temp, "/%s /%s def\n", fpos->name, fpos->fontname);
1229: exportstring(temp);
1230: fpos->flags |= NAMED; /* unnecessary */
1231: } /* End if */
1232:
1233: if ( hostfontdir != NULL ) {
1234: sprintf(temp, "%s/%s", hostfontdir, fpos->name);
1235: exportfile(temp);
1236: } /* End if */
1237: } /* End if */
1238:
1239: fprintf(tf, "%d %s f\n", size, fpos->name);
1240: if ( fontheight != 0 || fontslant != 0 )
1241: fprintf(tf, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : size);
1242:
1243: lastfont = font;
1244: lastsize = size;
1245: fpos->flags |= USED;
1246: } /* End if */
1247:
1248: } /* End of t_sf */
1249:
1250: /*****************************************************************************/
1251:
1252: t_charht(n)
1253:
1254: int n;
1255:
1256: {
1257:
1258: /*
1259: *
1260: * Set character height to n points. Disabled if n is 0 or the current size.
1261: *
1262: */
1263:
1264: fontheight = (n == size) ? 0 : n;
1265: lastfont = -1;
1266:
1267: } /* End of t_charht */
1268:
1269: /*****************************************************************************/
1270:
1271: t_slant(n)
1272:
1273: int n;
1274:
1275: {
1276:
1277: /*
1278: *
1279: * Set slant to n degrees. Disable slanting if n is 0.
1280: *
1281: */
1282:
1283: fontslant = n;
1284: lastfont = -1;
1285:
1286: } /* End of t_slant */
1287:
1288: /*****************************************************************************/
1289:
1290: xymove(x, y)
1291:
1292: int x, y;
1293:
1294: {
1295:
1296: /*
1297: *
1298: * Make the the printer and post-processor agree about the current position.
1299: *
1300: */
1301:
1302: flushtext();
1303:
1304: hgoto(x);
1305: vgoto(y);
1306:
1307: fprintf(tf, "%d %d m\n", hpos, vpos);
1308:
1309: lastx = hpos;
1310: lasty = vpos;
1311:
1312: } /* End of xymove */
1313:
1314: /*****************************************************************************/
1315:
1316: put1(c)
1317:
1318: register int c;
1319:
1320: {
1321:
1322: register int i;
1323: register int j;
1324: register int k;
1325: int code;
1326: int ofont;
1327:
1328: /*
1329: *
1330: * Print character c. ASCII if c < ALPHABET, otherwise it's special. Look for
1331: * c in the current font, then in others starting at the first special font.
1332: * Save c in lastc so it's available when oput() runs. Restore original font
1333: * before leaving.
1334: *
1335: */
1336:
1337: lastc = c; /* charlib() needs name not code */
1338: if ( (c -= 32) <= 0 )
1339: return;
1340:
1341: k = ofont = font;
1342:
1343: if ( (i = onfont(lastc, k)) == -1 && smnt > 0 )
1344: for ( k = smnt, j = 0; j < nfonts; j++, k = k % nfonts + 1 ) {
1345: if ( (i = onfont(lastc, k)) != -1 ) {
1346: setfont(k);
1347: break;
1348: } /* End if */
1349: } /* End for */
1350:
1351: if ( i != -1 && (code = mount[k]->wp[i].code) != 0 ) {
1352: lastw = widthfac * (((int)mount[k]->wp[i].wid * size + unitwidth/2) / unitwidth);
1353: oput(code);
1354: } /* End if */
1355:
1356: if ( font != ofont )
1357: setfont(ofont);
1358:
1359: } /* End of put1 */
1360:
1361: /*****************************************************************************/
1362:
1363: oput(c)
1364:
1365: int c;
1366:
1367: {
1368:
1369: double llx, lly, urx, ury; /* boundingbox corners */
1370:
1371: /*
1372: *
1373: * Arranges to print the character whose code is c in the current font. All the
1374: * actual positioning is done here, in charlib(), or in the drawing routines.
1375: *
1376: */
1377:
1378: if ( textcount > MAXSTACK ) /* don't put too much on the stack? */
1379: flushtext();
1380:
1381: if ( font != lastfont || size != lastsize )
1382: t_sf();
1383:
1384: if ( vpos != lasty )
1385: endline();
1386:
1387: starttext();
1388:
1389: if ( ABS(hpos - lastx) > slop )
1390: endstring();
1391:
1392: if ( isascii(c) && isprint(c) )
1393: switch ( c ) {
1394: case '(':
1395: case ')':
1396: case '\\':
1397: addchar('\\');
1398:
1399: default:
1400: addchar(c);
1401: } /* End switch */
1402: else if ( c > 040 )
1403: addoctal(c);
1404: else charlib(c);
1405:
1406: if ( dobbox == TRUE ) {
1407: llx = lastx;
1408: lly = -(vpos + 0.5 * (devres * size / 72.0));
1409: urx = lastx + lastw;
1410: ury = -(vpos - (devres * size / 72.0));
1411: cover(llx, lly);
1412: cover(urx, ury);
1413: } /* End if */
1414:
1415: lastx += lastw;
1416:
1417: } /* End of oput */
1418:
1419: /*****************************************************************************/
1420:
1421: starttext()
1422:
1423: {
1424:
1425: /*
1426: * Called whenever we want to be sure we're ready to start collecting characters
1427: * for the next call to PostScript procedure t (ie. the one that prints them). If
1428: * textcount is positive we've already started, so there's nothing to do. The more
1429: * complicated encoding schemes save text strings in the strings[] array and need
1430: * detailed information about the strings when they're written to the output file
1431: * in flushtext().
1432: *
1433: */
1434:
1435: if ( textcount < 1 ) {
1436: switch ( encoding ) {
1437: case 0:
1438: case 1:
1439: putc('(', tf);
1440: break;
1441:
1442: case 2:
1443: case 3:
1444: strptr = strings;
1445: spacecount = 0;
1446: line[1].str = strptr;
1447: line[1].dx = 0;
1448: line[1].spaces = 0;
1449: line[1].start = hpos;
1450: line[1].width = 0;
1451: break;
1452:
1453: case MAXENCODING+1: /* reverse video */
1454: if ( lastend == -1 )
1455: lastend = hpos;
1456: putc('(', tf);
1457: break;
1458:
1459: case MAXENCODING+2: /* follow a funny baseline */
1460: putc('(', tf);
1461: break;
1462: } /* End switch */
1463:
1464: textcount = 1;
1465: lastx = stringstart = hpos;
1466: } /* End if */
1467:
1468: } /* End of starttext */
1469:
1470: /*****************************************************************************/
1471:
1472: flushtext()
1473:
1474: {
1475:
1476: int i;
1477:
1478: /*
1479: *
1480: * Generates a call to the PostScript procedure that processes all the text we've
1481: * accumulated - provided textcount is positive.
1482: *
1483: */
1484:
1485: if ( textcount > 0 ) {
1486: switch ( encoding ) {
1487: case 0:
1488: fprintf(tf, ")%d t\n", stringstart);
1489: break;
1490:
1491: case 1:
1492: fprintf(tf, ")%d %d t\n", stringstart, lasty);
1493: break;
1494:
1495: case 2:
1496: *strptr = '\0';
1497: line[textcount].width = lastx - line[textcount].start;
1498: if ( spacecount != 0 || textcount != 1 ) {
1499: for ( i = textcount; i > 0; i-- )
1500: fprintf(tf, "(%s)%d %d", line[i].str, line[i].spaces, line[i].width);
1501: fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
1502: } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
1503: break;
1504:
1505: case 3:
1506: *strptr = '\0';
1507: if ( spacecount != 0 || textcount != 1 ) {
1508: for ( i = textcount; i > 0; i-- )
1509: fprintf(tf, "(%s)%d", line[i].str, line[i].dx);
1510: fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
1511: } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
1512: break;
1513:
1514: case MAXENCODING+1:
1515: fprintf(tf, ")%d ", stringstart);
1516: fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop);
1517: fprintf(tf, "t\n", stringstart);
1518: lastend = (lastx + .5) + 2 * rvslop;
1519: break;
1520:
1521: case MAXENCODING+2:
1522: fprintf(tf, ")%d %d t\n", stringstart, lasty);
1523: break;
1524: } /* End switch */
1525: } /* End if */
1526:
1527: textcount = 0;
1528:
1529: } /* End of flushtext */
1530:
1531: /*****************************************************************************/
1532:
1533: endstring()
1534:
1535: {
1536:
1537: int dx;
1538:
1539: /*
1540: *
1541: * Horizontal positions are out of sync. End the last open string, adjust the
1542: * printer's position, and start a new string. Assumes we've already started
1543: * accumulating text.
1544: *
1545: */
1546:
1547: switch ( encoding ) {
1548: case 0:
1549: case 1:
1550: fprintf(tf, ")%d(", stringstart);
1551: textcount++;
1552: lastx = stringstart = hpos;
1553: break;
1554:
1555: case 2:
1556: case 3:
1557: dx = hpos - lastx;
1558: if ( spacecount++ == 0 )
1559: line[textcount].dx = dx;
1560: if ( line[textcount].dx != dx ) {
1561: *strptr++ = '\0';
1562: line[textcount].width = lastx - line[textcount].start;
1563: line[++textcount].str = strptr;
1564: *strptr++ = ' ';
1565: line[textcount].dx = dx;
1566: line[textcount].start = lastx;
1567: line[textcount].width = 0;
1568: line[textcount].spaces = 1;
1569: } else {
1570: *strptr++ = ' ';
1571: line[textcount].spaces++;
1572: } /* End else */
1573: lastx += dx;
1574: break;
1575:
1576: case MAXENCODING+1:
1577: fprintf(tf, ")%d(", stringstart);
1578: textcount++;
1579: lastx = stringstart = hpos;
1580: break;
1581:
1582: case MAXENCODING+2:
1583: flushtext();
1584: starttext();
1585: break;
1586: } /* End switch */
1587:
1588: } /* End of endstring */
1589:
1590: /*****************************************************************************/
1591:
1592: endline()
1593:
1594: {
1595:
1596: /*
1597: *
1598: * The vertical position has changed. Dump any accumulated text, then adjust
1599: * the printer's vertical position.
1600: *
1601: */
1602:
1603: flushtext();
1604:
1605: if ( encoding == 0 || encoding == MAXENCODING+1 )
1606: fprintf(tf, "%d %d m\n", hpos, vpos);
1607:
1608: lastx = stringstart = lastend = hpos;
1609: lasty = vpos;
1610:
1611: } /* End of endline */
1612:
1613: /*****************************************************************************/
1614:
1615: addchar(c)
1616:
1617: int c;
1618:
1619: {
1620:
1621: /*
1622: *
1623: * Does whatever is needed to add character c to the current string.
1624: *
1625: */
1626:
1627: switch ( encoding ) {
1628: case 0:
1629: case 1:
1630: putc(c, tf);
1631: break;
1632:
1633: case 2:
1634: case 3:
1635: *strptr++ = c;
1636: break;
1637:
1638: case MAXENCODING+1:
1639: case MAXENCODING+2:
1640: putc(c, tf);
1641: break;
1642: } /* End switch */
1643:
1644: } /* End of addchar */
1645:
1646: /*****************************************************************************/
1647:
1648: addoctal(c)
1649:
1650: int c;
1651:
1652: {
1653:
1654: /*
1655: *
1656: * Add c to the current string as an octal escape.
1657: *
1658: */
1659:
1660: switch ( encoding ) {
1661: case 0:
1662: case 1:
1663: fprintf(tf, "\\%o", c);
1664: break;
1665:
1666: case 2:
1667: case 3:
1668: sprintf(strptr, "\\%o", c);
1669: strptr += strlen(strptr);
1670: break;
1671:
1672: case MAXENCODING+1:
1673: case MAXENCODING+2:
1674: fprintf(tf, "\\%o", c);
1675: break;
1676: } /* End switch */
1677:
1678: } /* End of addoctal */
1679:
1680: /*****************************************************************************/
1681:
1682: charlib(code)
1683:
1684: int code; /* either 1 or 2 */
1685:
1686: {
1687:
1688: char *name; /* name of the character */
1689: char tname[10]; /* in case it's a single ASCII character */
1690: char temp[150];
1691:
1692: /*
1693: *
1694: * Called from oput() for characters having codes less than 040. Special files
1695: * that define PostScript procedures for certain characters can be found in
1696: * directory *fontdir/devpost/charlib. If there's a file that has the same name as
1697: * the character we're trying to print it's copied to the output file, otherwise
1698: * nothing, except some positioning, is done.
1699: *
1700: * All character definitions are only made once. Subsequent requests to print the
1701: * character generate a call to a procedure that begins with the prefix build_ and
1702: * ends with the character's name. Special characters that are assigned codes
1703: * other than 1 are assumed to have additional data files that should be copied
1704: * to the output file immediately after the build_ call. Those data files should
1705: * end in the suffix .map, and usually will be a hex representation of a bitmap.
1706: *
1707: */
1708:
1709: flushtext();
1710:
1711: if ( lastc < ALPHABET ) { /* ASCII character */
1712: sprintf(tname, "%.3o", lastc);
1713: name = tname;
1714: } else name = chname(lastc);
1715:
1716: if ( downloaded[lastc] == 0 ) {
1717: sprintf(temp, "%s/dev%s/charlib/%s", fontdir, realdev, name);
1718: if ( exportfile(temp) == TRUE ) {
1719: downloaded[lastc] = 1;
1720: t_sf();
1721: } /* End if */
1722: } /* End if */
1723:
1724: if ( downloaded[lastc] == 1 ) {
1725: xymove(hpos, vpos);
1726: fprintf(tf, "%d build_%s\n", (int) lastw, name);
1727: if ( code != 1 ) { /* get the bitmap or whatever */
1728: sprintf(temp, "%s/dev%s/charlib/%s.map", fontdir, realdev, name);
1729: if ( access(temp, 04) == 0 && tf == stdout )
1730: cat(temp);
1731: } /* End if */
1732: fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos);
1733: } /* End if */
1734:
1735: } /* End of charlib */
1736:
1737: /*****************************************************************************/
1738:
1739: reset()
1740:
1741: {
1742:
1743: /*
1744: *
1745: * Reset variables that keep track of the printer's current position, size and
1746: * font. Eventually forces things back in sync before oput() prints the next
1747: * character.
1748: *
1749: */
1750:
1751: lastx = -(slop + 1);
1752: lasty = -1;
1753: lastfont = lastsize = -1;
1754:
1755: } /* End of reset */
1756:
1757: /*****************************************************************************/
1758:
1759: resetpos()
1760:
1761: {
1762:
1763: /*
1764: *
1765: * Reset the position tracking variables. Forces oput() to get positions back
1766: * in sync before printing the next character.
1767: *
1768: */
1769:
1770: lastx = -(slop + 1);
1771: lasty = -1;
1772:
1773: } /* End of resetpos */
1774:
1775: /*****************************************************************************/
1776:
1777: save()
1778:
1779: {
1780:
1781: /*
1782: *
1783: * Save the current PostScript environment. Initialize things that may have
1784: * disappeared after the preceeding restore.
1785: *
1786: */
1787:
1788: fprintf(tf, "/saveobj save def\n");
1789: fprintf(tf, "mark\n");
1790:
1791: if ( encoding != realencoding )
1792: fprintf(tf, "%d setdecoding\n", encoding);
1793:
1794: if ( gotcolor == TRUE ) /* prevent getcolor() recursion */
1795: setcolor();
1796:
1797: } /* End of save */
1798:
1799: /*****************************************************************************/
1800:
1801: restore()
1802:
1803: {
1804:
1805: /*
1806: *
1807: * Restore the previous PostScript environment.
1808: *
1809: */
1810:
1811: flushtext();
1812: fprintf(tf, "cleartomark\n");
1813: fprintf(tf, "saveobj restore\n");
1814: reset();
1815:
1816: } /* End of restore */
1817:
1818: /*****************************************************************************/
1819:
1820: exportfile(path)
1821:
1822: char *path;
1823:
1824: {
1825:
1826: int val = FALSE;
1827:
1828: /*
1829: *
1830: * Exports the contents of file path to the global environment. Returns TRUE
1831: * if we're doing output (i.e. tf == stdout) and the copy worked.
1832: *
1833: */
1834:
1835: if ( tf == stdout && access(path, 04) == 0 ) {
1836: restore();
1837: fprintf(tf, "%s", BEGINGLOBAL);
1838: val = cat(path);
1839: fprintf(tf, "%s", ENDGLOBAL);
1840: save();
1841: } /* End if */
1842:
1843: return(val);
1844:
1845: } /* End of exportfile */
1846:
1847: /*****************************************************************************/
1848:
1849: exportstring(str)
1850:
1851: char *str;
1852:
1853: {
1854:
1855: /*
1856: *
1857: * Exports string str to the global environment. No return value needed yet.
1858: *
1859: */
1860:
1861: if ( tf == stdout && str != NULL && *str != '\0' ) {
1862: restore();
1863: fprintf(tf, "%s", BEGINGLOBAL);
1864: fprintf(tf, "%s", str);
1865: fprintf(tf, "%s", ENDGLOBAL);
1866: save();
1867: } /* End if */
1868:
1869: } /* End of exportstring */
1870:
1871: /*****************************************************************************/
1872:
1873: redirect(pg)
1874:
1875: int pg;
1876:
1877: {
1878:
1879: static FILE *fp_null = NULL;
1880:
1881: /*
1882: *
1883: * If we're not supposed to print page pg, tf will be directed to /dev/null,
1884: * otherwise output goes to stdout.
1885: *
1886: */
1887:
1888: if ( pg >= 0 && in_olist(pg) == ON )
1889: tf = stdout;
1890: else if ( (tf = fp_null) == NULL )
1891: tf = fp_null = fopen("/dev/null", "w");
1892:
1893: } /* End of redirect */
1894:
1895: /*****************************************************************************/
1896:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.