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