xref: /csrg-svn/local/transcript/src/psdit.c (revision 30594)
1 /*	psdit.c	1.1	87/03/08	*/
2 #ifndef lint
3 static char Notice[] = "Copyright (c) 1984, 1985 Adobe Systems Incorporated";
4 static char *RCSID="$Header: psdit.c,v 2.1 85/11/24 11:50:41 shore Rel $";
5 #endif
6 /* psdit.c
7  *
8  * Copyright (c) 1984, 1985 Adobe Systems Incorporated
9  *
10  * ditroff intermediate file to PostScript translator
11  *
12  * Original Version: Barry Hayes spring/summer 1984
13  * Edit History:
14  * Andrew Shore: Sat Nov 23 20:05:26 1985
15  * End Edit History.
16  *
17  * RCSLOG:
18  * $Log:	psdit.c,v $
19  * Revision 2.1  85/11/24  11:50:41  shore
20  * Product Release 2.0
21  *
22  * Revision 1.8  85/11/23  20:09:44  shore
23  * test for termination of included PostScript was bad
24  *
25  * Revision 1.7  85/11/21  14:23:56  shore
26  * added envget check for PSLIBDIR
27  *
28  * Revision 1.6  85/11/20  00:43:43  shore
29  * support for included PostScript
30  * big rework on FlushShow, word "breaks"
31  * removed FlushFont and made them instant
32  * Still no Gremlin support yet
33  *
34  * Revision 1.5  85/10/03  10:48:09  shore
35  * added FlushShow to xf fix !
36  *
37  * Revision 1.4  85/10/02  16:20:32  shore
38  * fixed xf bug
39  * mounting a font causes a font switch!
40  *
41  * Revision 1.3  85/07/09  13:10:20  shore
42  * added fclose on map file
43  *
44  * Revision 1.2  85/05/14  11:24:23  shore
45  * added flush to trailer
46  * fixed read bug when mounting fonts
47  *
48  *
49  */
50 
51 /*
52 output language from troff:
53 all numbers are character strings
54 
55 sn	size in points
56 fn	font as number from 1-n
57 cx	ascii character x
58 Cxyz	funny char xyz. terminated by white space
59 Hn	go to absolute horizontal position n
60 Vn	go to absolute vertical position n (down is positive)
61 hn	go n units horizontally (relative)
62 vn	ditto vertically
63 nnc	move right nn, then print c (exactly 2 digits!)
64 		(this wart is an optimization that shrinks output file size
65 		 about 35% and run-time about 15% while preserving ascii-ness)
66 Dt ...\n	draw operation 't':
67 	Dl x y		line from here by x,y
68 	Dc d		circle of diameter d with left side here
69 	De x y		ellipse of axes x,y with left side here
70 	Da x y r	arc counter-clockwise by x,y of radius r
71 	D~ x y x y ...	wiggly line by x,y then x,y ...
72 nb a	end of line (information only -- no action needed)
73 	a = space before line, a = after
74 w	paddable word space -- no action needed
75 pn	new page begins -- set v to 0
76 {	push current environment (font info & location)
77 }	pop a saved environment
78 txxxx	print string xxxx using natural widths
79 #...\n	comment
80 x ...\n	device control functions:
81 	x i[nit]	init
82 	x T s		name of device is s
83 	x r[es] n h v	resolution is n/inch
84 			h = min horizontal motion, v = min vert
85 	x p[ause]	pause (can restart)
86 	x s[top]	stop -- done for ever
87 	x t[railer]	generate trailer
88 	x f[font] n s	font position n contains font s
89 	x H[eight] n	set character height to n
90 	x S[slant] n	set slant to N
91 
92 Adobe Extension for included PostScript:
93 %
94 (raw postscript...)
95 .\n
96 
97 */
98 
99 #include <stdio.h>
100 #include <ctype.h>
101 #include <signal.h>
102 #include <pwd.h>
103 #ifdef SYSV
104 extern struct passwd *getpwuid();
105 #endif
106 #include "transcript.h"
107 
108 #include "dev.h"
109 
110 char *malloc();
111 
112 #define	NFONT	10
113 
114 /* DIT state consists of: */
115 private int	hpos;		/* current horizontal position */
116 private int	vpos;		/* current vertical position */
117 private int	fontsize;	/* current font size */
118 private int	fontheight;	/* current character height */
119 private int	fontslant;	/* current font slant */
120 private int	font;		/* current font */
121 private int	resolution;	/* device resolution */
122 private int	minhoriz;	/* minimum horizontal motion */
123 private int	minvert;	/* minimum vertical motion */
124 
125 private int	onspecial;
126 private int	specfont;
127 private int	prevfont;
128 private int 	pfont;
129 
130 /* {} push/pop stack */
131 #define DSTACK 10
132 private struct ditstack {
133     int hpos, vpos, fontsize, fontheight, fontslant, font;
134 } ditstack[DSTACK];
135 private int dlevel = 0;
136 
137 #define ErrorTolerance 48
138 #define PSWID 0x00000FFF
139 #define ISPSPROC 0x000FF000
140 
141 
142 /* PSscale is equivalent to (x * PSmag / 72000) + 0.5 */
143 #define PSmag 16
144 #define PSscale(x) (((x)+2250)/4500)
145 
146 /* we maintain PS coords with PSmag times the precision */
147 /* current PS state is: */
148 
149 private int	PSx;		/* current horizontal position */
150 private int	PSy;		/* current vertical position */
151 private int	savex, savey;	/* position of start of current show string */
152 
153 /* ps move types -- note that XMOVE|YMOVE == XYMOVE ! */
154 #define NONE 0
155 #define XMOVE 1
156 #define YMOVE 2
157 #define XYMOVE 3
158 
159 private int movepending = NONE;
160 
161 /* buffer string for show -- save up adjacent chars */
162 #define SHOWSIZE 400
163 private char showbuf[SHOWSIZE + 3]; /* extras are for quoting */
164 private int showind = 0;	/* index into string of next available byte */
165 private int PSshowlen = 0;	/* size in big units of buffered string */
166 private int nshow = 0;		/* actual number of show chars in showbuf */
167 private int startx;		/* troff starting pos of current string */
168 private int thisw;
169 
170 /* #define NONE 0 */
171 #define HMOT 1
172 #define VMOT 2
173 #define CPUT 4
174 #define BRK  8
175 #define FNT  16
176 private int lastcmd;
177 
178 private int	output	= 0;	/* do we do output at all? */
179 private int	nolist	= 0;	/* output page list if > 0 */
180 private int	olist[20];	/* pairs of page numbers */
181 private int	spage	= 9999;	/* stop every spage pages */
182 private int	scount	= 0;
183 private int	stopped = 0;
184 private int	pageno = 0;
185 private int	firstpage = TRUE;
186 
187 private struct	dev	dev;
188 private struct font *fontbase[NFONT+1];
189 private short	*pstab;
190 private int	dres;	/* resolution from DESC */
191 private int	nsizes; /* number of point sizes from DESC */
192 private int	nfonts; /* number of fonts from DESC */
193 private int	smnt;	/* index of first special font */
194 private int	nchtab;
195 private char	*chname;
196 private short	*chtab;
197 private char	*fitab[NFONT+1];
198 private char	*widthtab[NFONT+1];	/* widtab would be a better name */
199 private char	*codetab[NFONT+1];	/* device codes */
200 
201 private int     *pswidths[NFONT+1]; /* ps width tables */
202 private int	fontdelta[NFONT+1]; /* nonzero if xf overwrites font i */
203 
204 /* font position info: */
205 private struct {
206 	char *name;
207 	int number;
208 } fontname[NFONT+1];
209 
210 #define	FATAL	1
211 #define	BMASK	0377
212 
213 #ifdef DEBUG
214 int	dbg	= 0;
215 int	fdbg = 0;
216 #define debugp(xxx) {if(dbg != 0){dbg--; printf xxx ; VOIDC fflush(stdout);}}
217 #else
218 #define debugp(x)
219 #endif
220 
221 private FILE	*tf = stdout;	/* output file */
222 private char devname[20] = "psc";
223 
224 private char	*infilename = "stdin"; /* input file name */
225 private char	*prologfile = PSDITPRO;
226 private char	*ditdir = DitDir;
227 
228 private char	*prog;		/* argv[0] - program name */
229 
230 main(argc, argv)
231 int argc;
232 char *argv[];
233 {
234     FILE *fp;
235     VOID done();
236 
237     prog = argv[0];
238     while (argc > 1 && argv[1][0] == '-') {
239 	switch (argv[1][1]) {
240 	    case 'f':
241 	    case 'F':
242 		if (argv[1][2])
243 		    ditdir = &argv[1][2];
244 		else {
245 		    ditdir = argv[2];
246 		    argv++;
247 		    argc--;
248 		}
249 		break;
250 	    case 'p':
251 		if (argv[1][2])
252 		    prologfile = &argv[1][2];
253 		break;
254 	    case 'o':
255 		outlist (&argv[1][2]);
256 		break;
257 	    case 'd':
258 #ifdef DEBUG
259 		dbg = atoi (&argv[1][2]);
260 		if (dbg == 0)
261 		    dbg = 1;
262 		tf = stdout;
263 #endif DEBUG
264 		break;
265 	    case 'b': 		/* ignore busy */
266 		break;
267 	    case 'w': 		/* ignore wait */
268 		break;
269 	    case 's':
270 		spage = atoi (&argv[1][2]);
271 		if (spage <= 0)
272 		    spage = 9999;
273 		break;
274 	}
275 	argc--;
276 	argv++;
277     }
278 
279     if (signal (SIGINT, done) == SIG_IGN) {
280 	signal (SIGINT, SIG_IGN);
281 	signal (SIGQUIT, SIG_IGN);
282 	signal (SIGHUP, SIG_IGN);
283     }
284     else {
285 	signal (SIGQUIT, done);
286 	signal (SIGHUP, done);
287     }
288     signal (SIGTERM, done);
289 
290     preface ();
291 
292     if (argc <= 1)
293 	conv (stdin);
294     else
295 	while (--argc > 0) {
296 	    if (strcmp (*++argv, "-") == 0)
297 		fp = stdin;
298 	    else if ((fp = fopen (*argv, "r")) == NULL) {
299 		fprintf (stderr, "%s: can't open %s\n", prog, *argv);
300 		pexit(prog,2);
301 	    }
302 	    infilename = *argv;
303 	    conv (fp);
304 	    VOIDC fclose (fp);
305 	}
306     done ();
307 }
308 
309 private outlist(s)	/* process list of page numbers to be printed */
310 char *s;
311 {
312     int     n1, n2, i;
313 
314     nolist = 0;
315     while (*s) {
316 	n1 = 0;
317 	if (isdigit (*s)) {
318 	    do {
319 		n1 = 10 * n1 + *s++ - '0';
320 	    }
321 	    while (isdigit (*s));
322 	}
323 	else {
324 	    n1 = -9999;
325 	}
326 	n2 = n1;
327 	if (*s == '-') {
328 	    s++;
329 	    n2 = 0;
330 	    if (isdigit (*s)) {
331 		do {
332 		    n2 = 10 * n2 + *s++ - '0';
333 		}
334 		while (isdigit (*s));
335 	    }
336 	    else {
337 		n2 = 9999;
338 	    }
339 	}
340 	olist[nolist++] = n1;
341 	olist[nolist++] = n2;
342 	if (*s != '\0') {
343 	    s++;
344 	}
345     }
346     olist[nolist] = 0;
347 #ifdef DEBUG
348     if (dbg)
349 	for (i = 0; i < nolist; i += 2)
350 	    printf ("%3d %3d\n", olist[i], olist[i + 1]);
351 #endif
352 }
353 
354 private conv(fp)	/* convert a file */
355 register FILE *fp;
356 {
357     register int    c, k;
358     int     m, n, n1, m1;
359     char    str[100], buf[300];
360 
361     while ((c = getc(fp)) != EOF) {
362 	switch (c) {
363 	    case '\n': case ' ': case '\0':
364 		break;
365 	    case '{': 		/* push down current environment */
366 		t_push();
367 		break;
368 	    case '}':
369 		t_pop();
370 		break;
371 	    case '0': case '1': case '2': case '3': case '4':
372 	    case '5': case '6': case '7': case '8': case '9':
373 	    /* two motion digits plus a character */
374 		hmot((c - '0') * 10 + getc (fp) - '0');
375 		lastcmd = HMOT;
376 		put1(getc(fp), (char *) 0);
377 		lastcmd = CPUT;
378 		break;
379 	    case 'c': 		/* single ascii character */
380 		put1(getc(fp), (char *) 0);
381 		lastcmd = CPUT;
382 		break;
383 	    case 'C':
384 		fscanf(fp, "%s", str);
385 		put1s(str);
386 		lastcmd = CPUT;
387 		break;
388 	    case 't': 		/* straight text */
389 		fgets(buf, sizeof (buf), fp);
390 		t_text (buf);
391 		lastcmd = CPUT;
392 		break;
393 	    case 'D': 		/* draw function */
394 		fgets(buf, sizeof (buf), fp);
395 		switch (buf[0]) {
396 		    case 'l': 	/* draw a line */
397 			sscanf (buf + 1, "%d %d", &n, &m);
398 			drawline (n, m);
399 			break;
400 		    case 'c': 	/* circle */
401 			sscanf (buf + 1, "%d", &n);
402 			drawcirc (n);
403 			break;
404 		    case 'e': 	/* ellipse */
405 			sscanf (buf + 1, "%d %d", &m, &n);
406 			drawellip (m, n);
407 			break;
408 		    case 'a': 	/* arc */
409 			sscanf (buf + 1, "%d %d %d %d", &n, &m, &n1, &m1);
410 			drawarc (n, m, n1, m1);
411 			break;
412 		    case '~': 	/* wiggly line */
413 			drawwig (buf + 1);
414 			break;
415 		    default:
416 			fprintf(stderr,"%s: unknown drawing function %s\n",
417 				prog,buf);
418 			exit(2);
419 			break;
420 		}
421 		break;
422 	    case 's':
423 		fscanf (fp, "%d", &n);
424 		t_size (n);
425 		lastcmd = FNT;
426 		break;
427 	    case 'f':
428 		fscanf (fp, "%s", str);
429 		setfont (t_font (str));
430 		lastcmd = FNT;
431 		break;
432 	    case 'H': 		/* absolute horizontal motion */
433 		while ((c = getc (fp)) == ' ');
434 		k = 0;
435 		do {
436 		    k = 10 * k + c - '0';
437 		} while (isdigit (c = getc (fp)));
438 		ungetc (c, fp);
439 		hgoto (k);
440 		lastcmd = HMOT;
441 		break;
442 	    case 'h': 		/* relative horizontal motion */
443 		while ((c = getc (fp)) == ' ');
444 		k = 0;
445 		do {
446 		    k = 10 * k + c - '0';
447 		} while (isdigit (c = getc (fp)));
448 		ungetc (c, fp);
449 		hmot (k);
450 		lastcmd = HMOT;
451 		break;
452 	    case 'w':
453 		FlushShow(1);
454 		lastcmd = BRK;
455 		break;
456 	    case 'V':
457 		fscanf (fp, "%d", &n);
458 		vgoto (n);
459 		lastcmd = VMOT;
460 		break;
461 	    case 'v':
462 		fscanf (fp, "%d", &n);
463 		vmot (n);
464 		lastcmd = VMOT;
465 		break;
466 	    case 'p': 		/* new page */
467 		fscanf (fp, "%d", &n);
468 		t_page (n);
469 		lastcmd = NONE;
470 		break;
471 	    case 'n': 		/* end of line -- ignore */
472 		while (getc (fp) != '\n');
473 		FlushShow(1);
474 		lastcmd = BRK;
475 		break;
476 	    case '#': 		/* comment */
477 	    /* maybe should pass through as a PS comment */
478 		while (getc (fp) != '\n');
479 		break;
480 	    case 'x': 		/* device control */
481 		devcntrl (fp);
482 		break;
483 	    case '%':		/* imbedded PostScript */
484 	    /* copy everything up to but NOT including a line */
485 	    /* with at single "." */
486 	    FlushShow(0);MoveTo();DoMove();
487 	    printf("\n%% included PostScript\n");
488 	    while (fgets(buf, sizeof buf, fp) != NULL) {
489 		if (strcmp(".\n",buf) == 0) break;
490 		fputs(buf,stdout);
491 	    }
492 	    break;
493 	    default:
494 		fprintf(stderr,"%s: bad input char \\%03o (%c)\n",prog,c,c);
495 		exit(2);
496 		done ();
497 	}
498     }
499 }
500 
501 
502 /* put in PostScript prolog */
503 private preface()
504 {
505     register    FILE *prolog;
506     char    hostname[256];
507     char tempfile[512];
508     struct passwd  *pswd;
509     long    clock;
510     char *libdir;
511 
512     fprintf (tf, "%%!%s\n", COMMENTVERSION);
513     pswd = getpwuid (getuid ());
514     VOIDC gethostname (hostname, sizeof hostname);
515     fprintf (tf, "%%%%Creator: %s:%s (%s)\n", hostname,
516 	    pswd->pw_name, pswd->pw_gecos);
517     fprintf (tf, "%%%%Title: %s (ditroff)\n", infilename);
518     fprintf (tf, "%%%%CreationDate: %s",
519 		(time (&clock), ctime (&clock)));
520     fprintf (tf, "%%%%EndComments\n");
521 
522     if ((libdir = envget("PSLIBDIR")) == NULL) libdir = LibDir;
523     mstrcat(tempfile, libdir, prologfile, sizeof tempfile);
524     if ((copyfile(tempfile, stdout)) != 0) {
525 	fprintf(stderr,"%s: can't copy prolog file %s\n",prog, tempfile);
526 	exit(2);
527     }
528     printf ("ditstart\n");
529 }
530 
531 private devcntrl(fp)	/* interpret device control functions */
532 FILE *fp;
533 {
534     char    str[20], str1[50], buf[50];
535     int     c, n, res, minh, minv;
536 
537     fscanf (fp, "%s", str);
538     switch (str[0]) {		/* crude for now */
539 	case 'i': 		/* initialize */
540 	    fileinit ();
541 	    t_init ();
542 	    lastcmd = NONE;
543 	    break;
544 	case 'T': 		/* device name */
545 	    fscanf (fp, "%s", devname);
546 	    if (strcmp (devname, "psc")) {
547 		fprintf(stderr,"%s: device not psc\n",prog);
548 		exit(2);
549 	    }
550 	    printf ("(%s)xT\n", devname);
551 	    lastcmd = NONE;
552 	    break;
553 	case 't': 		/* trailer */
554 	    t_trailer ();
555 	    lastcmd = NONE;
556 	    break;
557 	case 'p': 		/* pause -- can restart */
558 	    t_reset ('p');
559 	    lastcmd = NONE;
560 	    break;
561 	case 's': 		/* stop */
562 	    t_reset ('s');
563 	    lastcmd = NONE;
564 	    break;
565 	case 'r': 		/* resolution assumed when prepared */
566 	    fscanf (fp, "%d %d %d", &res, &minh, &minv);
567 	    t_res (res, minh, minv);
568 	    lastcmd = NONE;
569 	    break;
570 	case 'f': 		/* font used */
571 	    fscanf (fp, "%d %s", &n, str);
572 	    fgets (buf, sizeof buf, fp);/* in case theres a filename */
573 	    ungetc ('\n', fp);	/* fgets goes too far */
574 	    str1[0] = 0;	/* in case there is nothing to come in */
575 	    sscanf (buf, "%s", str1);
576 	    loadfont (n, str, str1);
577 	    lastcmd = FNT;
578 	    break;
579 	case 'H': 		/* char height */
580 	    fscanf (fp, "%d", &n);
581 	    t_charht (n);
582 	    lastcmd = FNT;
583 	    break;
584 	case 'S': 		/* slant */
585 	    fscanf (fp, "%d", &n);
586 	    t_slant (n);
587 	    lastcmd = FNT;
588 	    break;
589     }
590     /* skip rest of input line */
591     while ((c = getc (fp)) != '\n') {if (c == EOF) break;};
592 }
593 
594 private fileinit()	/* read in font and code files, etc. */
595 {
596     int     i, fin, nw;
597     char    *filebase, *p;
598     char    temp[60];
599     unsigned msize;
600 
601     /* open table for device,
602      * read in resolution, size info, font info,   etc. and set params */
603 
604     sprintf (temp, "%s/dev%s/DESC.out", ditdir, devname);
605     if ((fin = open (temp, 0)) < 0) {
606 	fprintf (stderr, "%s: can't open %s - %s\n", prog, devname, temp);
607 	pexit(prog,2);
608     }
609     if (read(fin,(char *)&dev, (int) sizeof(struct dev)) != sizeof(struct dev)) {
610 	fprintf (stderr, "%s: can't read %s\n", prog, temp);
611 	pexit(prog,2);
612     }
613     dres = dev.res;
614     nfonts = dev.nfonts;
615     nsizes = dev.nsizes;
616     nchtab = dev.nchtab;
617     /* enough room for whole file */
618     filebase = malloc ((unsigned) dev.filesize);
619     if (read (fin, filebase, dev.filesize) != dev.filesize) {
620 	fprintf (stderr, "%s: trouble reading %s\n", prog, temp);
621 	pexit(prog,2);
622     }
623     pstab = (short *) filebase;		/* point size table */
624     chtab = pstab + nsizes + 1;		/* char index table */
625     chname = (char *) (chtab + dev.nchtab);	/* char name table */
626     p = chname + dev.lchname;		/* end of char name table */
627     /* parse the preloaded font tables */
628     for (i = 1; i <= nfonts; i++) {
629 	fontdelta[i] = 0;
630 	fontbase[i] = (struct font *) p;
631 	nw = *p & BMASK;	/* number of width entries */
632 	if ((smnt == 0) && (fontbase[i]->specfont == 1))
633 	    smnt = i;		/* first special font */
634 	p += sizeof (struct font); /* skip header */
635 	widthtab[i] = p;		/* width table */
636 					/* kern table is next */
637 	codetab[i] = p + 2 * nw;	/* device codes */
638 	fitab[i] = p + 3 * nw;		/* font index table */
639 
640 	p += 3 * nw + dev.nchtab + (128 - 32);	/* next font */
641 	t_fp (i, fontbase[i]->namefont, fontbase[i]->intname);
642 	loadpswidths (i, fontbase[i]->namefont);
643 	sayload (i, fontbase[i]->namefont, (char *) 0);
644 #ifdef DEBUG
645 	if (fdbg > 1)
646 	    fontprint (i);
647 #endif
648     }
649     fontdelta[0] = 0;
650     msize = 3*255 + dev.nchtab + (128-32) + sizeof (struct font);
651     fontbase[0] = (struct font *) malloc(msize);
652     widthtab[0] = (char *) fontbase[0] + sizeof (struct font);
653     fontbase[0]->nwfont = 255;
654     close (fin);
655 }
656 
657 private loadpswidths(i,name)
658 int i;
659 char *name;
660 {
661     char temp[60];
662     register FILE *auxin;
663     register int j;
664     int cc, wid, funny;
665 
666     sprintf(temp, "%s/dev%s/%s.aux", ditdir, devname, name);
667     auxin = fopen(temp, "r");
668     /* allocate table */
669     if (pswidths[i] == NULL) {
670 	pswidths[i] = (int *) malloc(256 * (sizeof (int)));
671     }
672     /* initialize to not-there */
673     for (j = 0; j <= 255; pswidths[i][j++] = -1);
674     /* read them in */
675     while (fscanf(auxin, "%d %d %d", &cc, &wid, &funny) != EOF) {
676 	pswidths[i][cc] = wid | (funny << 12);
677     }
678     VOIDC fclose(auxin);
679 }
680 
681 #ifdef DEBUG
682 private fontprint(i)	/* debugging print of font i (0,...) */
683 int i;
684 {
685     int     j, n;
686     char   *p;
687 
688     printf ("font %d:\n", i);
689     p = (char *) fontbase[i];
690     n = fontbase[i]->nwfont & BMASK;
691     printf ("base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",
692 	    p, n, fontbase[i]->specfont,
693 	    fontbase[i]->namefont, widthtab[i], fitab[i]);
694     printf ("widths:\n");
695     for (j = 0; j <= n; j++) {
696 	printf (" %2d", widthtab[i][j] & BMASK);
697 	if (j % 20 == 19)
698 	    printf ("\n");
699     }
700     printf ("\ncodetab:\n");
701     for (j = 0; j <= n; j++) {
702 	printf (" %2d", codetab[i][j] & BMASK);
703 	if (j % 20 == 19)
704 	    printf ("\n");
705     }
706     printf ("\nfitab:\n");
707     for (j = 0; j <= dev.nchtab + 128 - 32; j++) {
708 	printf (" %2d", fitab[i][j] & BMASK);
709 	if (j % 20 == 19)
710 	    printf ("\n");
711     }
712     printf ("\n");
713 }
714 #endif
715 
716 private loadfont(n, s, s1) /* load font info for font s on position n */
717 int n;
718 char *s, *s1;
719 {
720     char    temp[60];
721     int     fin, nw, norig;
722     int     bcount;
723 
724     if (n < 0 || n > NFONT) {
725 	fprintf(stderr,"%s: illegal fp command %d %s\n", prog, n, s);
726 	exit(2);
727     }
728     if (strcmp(s, fontbase[n]->namefont) == 0) return;
729     if (fontbase[n]->namefont != 0) {
730 	fontdelta[n] = 1;
731     }
732     if (s1 == NULL || s1[0] == '\0') {
733 	sprintf (temp, "%s/dev%s/%s.out", ditdir, devname, s);
734     }
735     else {
736 	sprintf (temp, "%s/%s.out", s1, s);
737     }
738     if ((fin = open (temp, 0)) < 0) {
739 	fprintf(stderr,"%s: can't open font table %s\n", prog, temp);
740 	pexit(prog,2);
741     }
742     norig = fontbase[n]->nwfont & BMASK;
743     bcount = 3 * norig + nchtab + 128 - 32 + sizeof (struct font);
744     VOIDC read (fin, (char *)fontbase[n], bcount);
745     if ((fontbase[n]->nwfont & BMASK) > norig) {
746 	fprintf(stderr,"%s: Font %s too big for position %d\n", prog, s, n);
747 	exit(2);
748     }
749     close (fin);
750     nw = fontbase[n]->nwfont & BMASK;
751     widthtab[n] = (char *) fontbase[n] + sizeof (struct font);
752     codetab[n] = (char *) widthtab[n] + 2 * nw;
753     fitab[n] = (char *) widthtab[n] + 3 * nw;
754     t_fp (n, fontbase[n]->namefont, fontbase[n]->intname);
755     loadpswidths (n, fontbase[n]->namefont);
756     sayload (n, s, s1);
757     fontbase[n]->nwfont = norig; /* so can later use full original size */
758 #ifdef DEBUG
759     if (fdbg > 1)
760 	fontprint (n);
761 #endif
762 }
763 
764 private sayload(n, s, s1)	/* position n contains font s (internal s1) */
765 int n;
766 char *s, *s1;
767 {
768     char    pass[60];
769     FILE    *ptrfile;
770     char    Adobefont[60];
771 
772     if (s1 == NULL || s1[0] == '\0') {
773 	sprintf (pass, "%s/dev%s/%s.map", ditdir, devname, s);
774     }
775     else {
776 	sprintf (pass, "%s/%s.map", s1, s);
777     }
778 
779     if ((ptrfile = fopen (pass, "r")) == NULL) {
780 	fprintf(stderr,"%s: can't open font map file %s\n", prog, pass);
781 	pexit(prog,2);
782     }
783 
784     fscanf (ptrfile, "%s", Adobefont);
785     FlushShow(0);
786     printf ("%d(%s)xf %d f\n", n, Adobefont, n);
787     font = n;
788     VOIDC fclose(ptrfile);
789 }
790 
791 private VOID done()
792 {
793     if (tf == NULL)
794 	exit (1);
795     t_reset ('s');
796     exit (0);
797 }
798 
799 private t_init()	/* "x i" - initialize device */
800 {
801     movepending = NONE;
802     savex = savey = 0;
803 
804     t_size (10);		/* start somewhere */
805     t_slant (0);
806     setfont (1);		/* set font */
807     printf("xi\n");
808     printf("%%%%EndProlog\n");
809 }
810 
811 private t_push()	/* begin a new block */
812 {
813     FlushShow(1);MoveTo();DoMove();
814     if (dlevel == DSTACK) {
815 	fprintf(stderr,"%s: ditroff push/pop overflow!\n",prog);
816 	exit(2);
817     }
818     ditstack[dlevel].hpos = hpos;
819     ditstack[dlevel].vpos = vpos;
820     ditstack[dlevel].fontsize = fontsize;
821     ditstack[dlevel].fontheight = fontheight;
822     ditstack[dlevel].fontslant = fontslant;
823     ditstack[dlevel].font = font;
824     dlevel++;
825     printf ("\nditpush\n");
826 }
827 
828 private t_pop()	/* pop to previous state */
829 {
830     FlushShow(1);MoveTo();DoMove();
831     if (dlevel == 0) {
832 	fprintf(stderr,"%s: ditroff push/pop underflow!\n",prog);
833 	exit(2);
834     }
835     dlevel--;
836     hpos = ditstack[dlevel].hpos;
837     vpos = ditstack[dlevel].vpos;
838     fontsize = ditstack[dlevel].fontsize;
839     fontheight = ditstack[dlevel].fontheight;
840     fontslant = ditstack[dlevel].fontslant;
841     font = ditstack[dlevel].font;
842     printf ("%d s %d xH %d xS %d f\n",fontsize,fontheight,fontslant,font);
843     startx = savex = hpos;
844     savey = vpos;
845     PSx = hpos * PSmag;
846     PSy = vpos * PSmag;
847     printf("%d %d MXY\n",savex,savey);
848     movepending = NONE;
849     printf("\nditpop\n");
850 }
851 
852 private t_page(n)	/* do whatever new page functions */
853 {
854     int     i;
855 
856     if (output) {
857 	if (++scount >= spage) {
858 	    t_reset ('p');
859 	    scount = 0;
860 	}
861     }
862     output = 1;
863     FlushShow(0);
864     if (!firstpage) {
865 	printf("\n%d p",n);
866     }
867     firstpage = FALSE;
868     printf ("\n%%%%Page: %d %d\n", n, ++pageno, n);
869     for (i = 0; i <= nfonts; i++) {
870 	if (fontdelta[i] != 0) {
871 	    sayload (i, fontname[i].name, (char *) 0);
872 	}
873     }
874     vpos = 0;
875     PSy = 0;
876     printf ("%d s %d xH %d xS %d f\n",fontsize,fontheight,fontslant,font);
877     if (nolist == 0)
878 	return;
879     output = 0;
880     for (i = 0; i < nolist; i += 2)
881 	if (n >= olist[i] && n <= olist[i + 1]) {
882 	    output = 1;
883 	    break;
884 	}
885 }
886 
887 private t_size(n)	/* convert integer to internal size number*/
888 int n;
889 {
890     FlushShow(1);
891     if (fontsize != n) {
892 	fontsize = n;
893 	printf("%d s\n",fontsize);
894     }
895 }
896 
897 private t_charht(n)	/* set character height to n */
898 int n;
899 {
900     FlushShow(1);
901     if (fontheight != n) {
902 	fontheight = n;
903 	printf("%d xH\n",fontheight);
904     }
905 }
906 
907 private t_slant(n)	/* set slant to n */
908 int n;
909 {
910     FlushShow(1);
911     if (fontslant != n) {
912 	fontslant = n;
913 	printf("%d xS\n",fontslant);
914     }
915 }
916 
917 private t_font(s)	/* convert string to internal font number */
918 char *s;
919 {
920     int     n;
921 
922     n = atoi (s);
923     if (n < 0 || n > nfonts) n = 1;
924     return (n);
925 }
926 
927 private t_text(s)	/* print string s as text??? */
928 char *s;
929 {
930 	fprintf(stderr,"%s: ditroff t <%s> unimplemented!\n",prog,s);
931 }
932 
933 private t_reset(c)
934 {
935     output = 1;			/* by God */
936     if (c == 'p') {
937 	printf ("\nxp\n");
938     }
939     else {
940 	if (!stopped)
941 	    printf ("\nxs\n");
942 	stopped = 1;
943     }
944     fflush (tf);
945 }
946 
947 private t_res(res, minh, minv)
948 int res, minh, minv;
949 {
950     resolution = res;
951     minhoriz = minh;
952     minvert = minv;
953     printf ("%d %d %d xr\n", res, minh, minv);
954 }
955 
956 private t_trailer()
957 {
958     FlushShow(0);
959     printf("\n%d p",pageno);
960     printf("\n%%%%Trailer\n");
961     printf("xt\n");
962 }
963 
964 private put1s(s)	/* s is a funny char name */
965 char *s;
966 {
967     int     i;
968 
969     if (!output) return;
970     debugp(("%s ", s));
971 
972     /* search for s in the funny char name table */
973     for (i = 0; i < nchtab; i++) {
974 	if (strcmp(&chname[chtab[i]], s) == 0) break;
975     }
976 
977     if (i < nchtab) {
978 	put1(i + 128, s);
979     }
980     else {
981 	debugp(("not found "));
982 	putnf (0, s);
983     }
984 }
985 
986 #define needsescape(c) ((c=='\\') || (c=='(') || (c==')'))
987 
988 private put1(c, s)	/* output char c */
989 int c;
990 char *s;
991 {
992     char *pw;
993     register char *p;
994     register int i, k;
995     register int cc;
996     int ofont, code;
997     int psinfo, pswid, tw;
998 
999     if (!output) return;
1000     if (c == 32) {
1001 	thisw = 0;
1002 	FlushShow(0);
1003 	return;
1004     }
1005     if (c < 32) {
1006 	debugp(("non-exist 0%o\n",c));
1007 	return;
1008     }
1009 
1010     c -= 32;	/* offset char code */
1011     k = ofont = pfont = font;
1012     if (onspecial) pfont = prevfont;
1013 
1014     if ((i = (fitab[pfont][c] & BMASK)) != 0) {/* char on this font */
1015 	p = codetab[pfont];
1016 	pw = widthtab[pfont];
1017 	if (onspecial) {
1018 	    setfont(prevfont);
1019 	    thisw = 0;
1020 	    onspecial = 0;
1021 	}
1022     }
1023     else if (smnt > 0) {	/* on special (we hope) */
1024 	for (k = smnt; k <= nfonts; k += 1)
1025 	    if ((i = (fitab[k][c] & BMASK)) != 0) {
1026 		p = codetab[k];
1027 		pw = widthtab[k];
1028 		prevfont = pfont;
1029 		if (onspecial && (k == specfont)) break;
1030 		setfont (k);
1031 		thisw = 0;
1032 		onspecial = 1;
1033 		specfont = k;
1034 		break;
1035 	    }
1036     }
1037     if ((i == 0) || (k > nfonts) || ((code = p[i] & BMASK) == 0)) {
1038 	debugp(("not found 0%o\n", c+32));
1039 	putnf (c + 32, s);
1040 	return;
1041     }
1042     /* when we get here,
1043      *  c == biased character code
1044      *	k == font number
1045      *  i == index into codetab and widthtab for this character
1046      *  p == codetab for this font
1047      *  pw == width tab for this font
1048      *  code == character code for this char
1049      */
1050 
1051     cc = c + 32;
1052     debugp(((isascii(cc) && isprint(cc)) ? "%c %d\n":"%03o %d\n",
1053     		cc, code));
1054     psinfo = pswidths[font][code];	/* PS specific char info */
1055     pswid = psinfo & PSWID;		/* PS character width */
1056     thisw = pw[i] & BMASK;		/* troff char width */
1057     tw = thisw = (thisw * fontsize + dev.unitwidth/2) / dev.unitwidth;
1058 
1059     if ((psinfo & ISPSPROC) && (psinfo != -1)) {
1060 	/* character is implemented by a PostScript proc */
1061 	showspecial(s, code, pswid);
1062 	if (pswid > 0) {
1063 	    PSx += PSscale(pswid * fontsize * dres);
1064 	}
1065 	thisw = 0;
1066     }
1067     else {
1068 	showchar(code);
1069 	if (pswid > 0) {
1070 	    PSshowlen += PSscale(pswid * fontsize * dres);
1071 	}
1072     }
1073 
1074 /*
1075     if (font != ofont) {
1076 	setfont(ofont);
1077 	startx = hpos + tw;
1078 	thisw = 0;
1079 	lastcmd = FNT;
1080     }
1081 */
1082     debugp(("...width (%d)\n", pw[i]&BMASK));
1083 }
1084 
1085 
1086 private putnf(c, s)	/* note that a character wasnt found */
1087 int c;
1088 char *s;
1089 {
1090 
1091     FlushShow(0);
1092     thisw = 0;
1093     if ((s == NULL) || (*s == '\0')) printf("(\%3o)cb\n", c);
1094     else if ((strcmp(s, "\\|") == 0) || (strcmp(s, "\\^") == 0)
1095     || (strcmp (s, "\\&") == 0))
1096 	return;
1097     else
1098 	printf("(%s)cb\n", s);
1099 }
1100 
1101 
1102 private t_fp(n, s, si)	/* font position n now contains font s, intname si */
1103 int n;		/* position */
1104 char *s;	/* font (ditname) */
1105 char *si;	/* font (intname = number) */
1106 {
1107     fontname[n].name = s;
1108     fontname[n].number = atoi (si);
1109 }
1110 
1111 private setfont(n)	/* set font to n */
1112 int n;
1113 {
1114     FlushShow(1);
1115 
1116     if (n < 0 || n > NFONT) {
1117 	fprintf(stderr,"%s: illegal font %d\n", prog,n);
1118     }
1119     if (font != n) {
1120 	font = n;
1121 	printf("%d f\n",font);
1122     }
1123     onspecial = 0;
1124 }
1125 
1126 private drawline(dx, dy)	/* draw line from here to dx, dy */
1127 int dx, dy;
1128 {
1129     FlushShow(0); MoveTo(); DoMove();
1130     printf("%d %d Dl\n", dx, dy);
1131     hpos += dx;
1132     PSx = hpos * PSmag;
1133     vpos += dy;
1134     PSy = vpos * PSmag;
1135 }
1136 
1137 private drawwig(s)	/* draw wiggly line */
1138 char *s;
1139 {
1140     FlushShow(0); MoveTo(); DoMove();
1141     printf("D~ %s D~~\n",s);
1142 }
1143 
1144 private drawcirc(d)
1145 int d;
1146 {
1147     FlushShow(0); MoveTo(); DoMove();
1148     printf("%d Dc\n",d);
1149 }
1150 
1151 private drawarc(dx1, dy1, dx2, dy2)
1152 int dx1, dy1, dx2, dy2;
1153 {
1154     FlushShow(0); MoveTo(); DoMove();
1155     printf("%d %d %d %d Da\n", dx1, dy1, dx2, dy2);
1156     hpos += dx1 + dx2;
1157     PSx = hpos * PSmag;
1158     vpos += dy1 + dy2;
1159     PSy = vpos * PSmag;
1160 }
1161 
1162 private drawellip(a, b)
1163 int a, b;
1164 {
1165     FlushShow(0);MoveTo();DoMove();
1166     printf("%d %d De\n",a,b);
1167 }
1168 
1169 private hmot(a)	/* relative horizontal motion */
1170 int a;
1171 {
1172     register int aa;
1173     aa = abs(a);
1174     if ((aa < 8) || (aa > (10 * thisw)) || (a >= 100)
1175     || ((thisw != 0) && (abs(thisw - a) > 4))) {
1176 	FlushShow(1);
1177     }
1178     hpos += a;
1179     if (lastcmd != CPUT) startx = hpos;
1180 }
1181 
1182 private hgoto(a) /* absolute horizontal motion */
1183 int a;
1184 {
1185     FlushShow(1);
1186     startx = hpos = a;
1187     thisw = 0;
1188 }
1189 
1190 private vmot(a) /* relative vertical motion */
1191 int a;
1192 {
1193     FlushShow(1);
1194     vpos += a;
1195     thisw = 0;
1196 }
1197 
1198 private vgoto(a) /* absolute vertical motion */
1199 int a;
1200 {
1201     FlushShow(1);
1202     vpos = a;
1203     thisw = 0;
1204 }
1205 
1206 private showspecial(s,cc,wid)
1207 char *s;
1208 int cc;
1209 int wid;
1210 {
1211     char *sp;
1212 
1213     FlushShow(0);
1214     MoveTo();
1215     DoMove();
1216     putchar('(');
1217     for (sp = s; *sp != '\0'; sp++) {
1218 	if (needsescape(*sp)) {
1219 	    putchar('\\');
1220 	}
1221 	putchar(*sp);
1222     }
1223     printf(")%d %d oc\n",cc,wid);
1224 }
1225 
1226 private showchar(c)
1227 int c;
1228 {
1229     if (showind == 0) {MoveTo();}
1230     else if ((vpos * PSmag) != PSy) {
1231 	FlushShow(0);
1232 	MoveTo();
1233     }
1234     if (showind >= SHOWSIZE) FlushShow(0);
1235     if (isascii(c) && isprint(c)) {
1236 	switch (c) {
1237 	    case '\\': case '(': case ')':
1238 	        showbuf[showind++] = '\\';
1239 		/* fall through */
1240 
1241 	    default:
1242 		showbuf[showind++] = c;
1243 	}
1244     }
1245     else {
1246 	showbuf[showind++] = '\\';
1247 	showbuf[showind++] = ((c>>6)&03) + '0';
1248 	showbuf[showind++] = ((c>>3)&07) + '0';
1249 	showbuf[showind++] = (c&07) + '0';
1250     }
1251     showbuf[showind] = '\0';
1252     nshow++;
1253 }
1254 
1255 private MoveTo() {
1256     int x, y;
1257     x = hpos * PSmag;
1258     y = vpos * PSmag;
1259 
1260     if (x != PSx) {
1261 	startx = savex = hpos;
1262 	PSx = x;
1263 	movepending |= XMOVE;
1264     }
1265     if (y != PSy) {
1266 	savey = vpos;
1267 	PSy = y;
1268 	movepending |= YMOVE;
1269     }
1270 }
1271 
1272 private FlushMove() {
1273     switch (movepending) {
1274 	case NONE:
1275 	    break;
1276 	case XMOVE:
1277 	    printf("%d",savex);
1278 	    break;
1279 	case YMOVE:
1280 	    printf("%d",savey);
1281 	    break;
1282 	case XYMOVE:
1283 	    printf("%d %d",savex,savey);
1284 	    break;
1285 	default:
1286 	    fprintf(stderr,"%s: invalid move code %d\n",prog, movepending);
1287 	    exit(2);
1288     }
1289 }
1290 
1291 private char *movecmds[] = {
1292     "MX","MY","MXY"
1293 };
1294 
1295 private DoMove() {
1296     FlushMove();
1297     if (movepending != NONE) {
1298 	printf(" %s\n",movecmds[movepending-1]);
1299 	movepending = NONE;
1300     }
1301 }
1302 
1303 private char showops[] = "SXYN";
1304 
1305 private FlushShow(t) int t; {
1306     long err, tlen;
1307     float cerror;
1308 
1309     if (showind == 0) {thisw = 0; return;}
1310     if (movepending != NONE) {
1311 	FlushMove();
1312     }
1313     tlen = hpos - startx;
1314     if (lastcmd == CPUT) tlen += thisw;
1315     err = tlen * PSmag - PSshowlen;
1316     if ((nshow != 1) && (abs(err) > ErrorTolerance)) {
1317 	cerror = ((float) err) / ((nshow - 1) * PSmag);
1318 #ifdef DEBUG
1319 	fprintf(stderr,"F%d lc %d thisw %d ",t,lastcmd,thisw);
1320         fprintf(stderr,"x %ld h %ld tn %ld %ld ",
1321 		startx, hpos, tlen*PSmag,PSshowlen);
1322 	fprintf(stderr,"error %d %.4f %s\n",nshow,cerror,showbuf);
1323 	fflush(stderr);
1324 #endif
1325 	printf(" %.4f(%s)A%c\n", cerror, showbuf, showops[movepending]);
1326     }
1327     else {
1328 	printf("(%s)%c\n", showbuf, showops[movepending]);
1329     }
1330 
1331     showind = 0;
1332     nshow = 0;
1333     showbuf[showind] = '\0';
1334     PSx += PSshowlen;
1335     PSshowlen = 0;
1336     startx = hpos;
1337     if (lastcmd == CPUT) startx += thisw;
1338     thisw = 0;
1339     movepending = NONE;
1340 }
1341