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