xref: /csrg-svn/local/transcript/src/psdit.c (revision 30595)
1 #ifndef lint
2 static char Notice[] = "Copyright (c) 1984, 1985 Adobe Systems Incorporated";
3 static char *RCSID="$Header: psdit.c,v 2.1 85/11/24 11:50:41 shore Rel $";
4 #endif
5 # define XMOD
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 #ifdef XMOD
590 	case 'X': {		/* \X command from ditroff */
591             int last;
592 	    char largebuf[128];
593 	    fscanf (fp, "%1s", str);
594 	    switch (str[0]) {
595 		case 'p' :
596 		    FlushShow(0);MoveTo();DoMove();
597 		    fgets(largebuf, sizeof(largebuf), fp);
598 		    last = strlen(largebuf) - 1;
599 		    if (last >= 0 && largebuf[last] == '\n') {
600 			ungetc('\n', fp);
601 			largebuf[last] = ' ';
602 		    }
603 		    fputs(largebuf, tf);
604 		    putc('\n', tf);
605 		    break;
606 		case 'f' :
607 		    FlushShow(0);MoveTo();DoMove();
608 		    if (fscanf(fp, "%s", largebuf) == 1) {
609 			char *nl = (char *) index(largebuf, '\n');
610 			if (nl) *nl = '\0';
611 			includefile(largebuf);
612 		    } else
613 			fprintf(stderr, "warning - include cmd w/o path.\n");
614 		    break;
615 	    }
616 	}
617 	break;
618 #endif
619     }
620     /* skip rest of input line */
621     while ((c = getc (fp)) != '\n') {if (c == EOF) break;};
622 }
623 
624 #ifdef XMOD
625 includefile(filenm)
626 char *filenm; {
627 
628 	FILE *inf;
629 	int ch, c1, c2, firstch = 0;
630 
631 	if (!(inf = fopen(filenm, "r"))) {
632 		fprintf(stderr, "psdit: fopen(%s): ", filenm);
633 		perror();
634 		exit(1);
635 	}
636 	c1 = fgetc(inf); c2 = fgetc(inf);
637 	if (c1 != '%' || c2 != '!')
638 		fprintf(stderr, "psdit: %s not a postscript file.\n", filenm),
639 		exit(1);
640 
641 	fputs("%!", tf);
642 	while ((ch = fgetc(inf)) != EOF) {
643 		fputc(ch, tf);
644 		if (firstch && ch == '%') {
645 			/* we have to double leading '%'s */
646 			fputc('%', tf);
647 		}
648 		firstch = (ch == '\n');
649 	}
650 	fclose(inf);
651 }
652 #endif
653 private fileinit()	/* read in font and code files, etc. */
654 {
655     int     i, fin, nw;
656     char    *filebase, *p;
657     char    temp[60];
658     unsigned msize;
659 
660     /* open table for device,
661      * read in resolution, size info, font info,   etc. and set params */
662 
663     sprintf (temp, "%s/dev%s/DESC.out", ditdir, devname);
664     if ((fin = open (temp, 0)) < 0) {
665 	fprintf (stderr, "%s: can't open %s - %s\n", prog, devname, temp);
666 	pexit(prog,2);
667     }
668     if (read(fin,(char *)&dev, (int) sizeof(struct dev)) != sizeof(struct dev)) {
669 	fprintf (stderr, "%s: can't read %s\n", prog, temp);
670 	pexit(prog,2);
671     }
672     dres = dev.res;
673     nfonts = dev.nfonts;
674     nsizes = dev.nsizes;
675     nchtab = dev.nchtab;
676     /* enough room for whole file */
677     filebase = malloc ((unsigned) dev.filesize);
678     if (read (fin, filebase, dev.filesize) != dev.filesize) {
679 	fprintf (stderr, "%s: trouble reading %s\n", prog, temp);
680 	pexit(prog,2);
681     }
682     pstab = (short *) filebase;		/* point size table */
683     chtab = pstab + nsizes + 1;		/* char index table */
684     chname = (char *) (chtab + dev.nchtab);	/* char name table */
685     p = chname + dev.lchname;		/* end of char name table */
686     /* parse the preloaded font tables */
687     for (i = 1; i <= nfonts; i++) {
688 	fontdelta[i] = 0;
689 	fontbase[i] = (struct font *) p;
690 	nw = *p & BMASK;	/* number of width entries */
691 	if ((smnt == 0) && (fontbase[i]->specfont == 1))
692 	    smnt = i;		/* first special font */
693 	p += sizeof (struct font); /* skip header */
694 	widthtab[i] = p;		/* width table */
695 					/* kern table is next */
696 	codetab[i] = p + 2 * nw;	/* device codes */
697 	fitab[i] = p + 3 * nw;		/* font index table */
698 
699 	p += 3 * nw + dev.nchtab + (128 - 32);	/* next font */
700 	t_fp (i, fontbase[i]->namefont, fontbase[i]->intname);
701 	loadpswidths (i, fontbase[i]->namefont);
702 	sayload (i, fontbase[i]->namefont, (char *) 0);
703 #ifdef DEBUG
704 	if (fdbg > 1)
705 	    fontprint (i);
706 #endif
707     }
708     fontdelta[0] = 0;
709     msize = 3*255 + dev.nchtab + (128-32) + sizeof (struct font);
710     fontbase[0] = (struct font *) malloc(msize);
711     widthtab[0] = (char *) fontbase[0] + sizeof (struct font);
712     fontbase[0]->nwfont = 255;
713     close (fin);
714 }
715 
716 private loadpswidths(i,name)
717 int i;
718 char *name;
719 {
720     char temp[60];
721     register FILE *auxin;
722     register int j;
723     int cc, wid, funny;
724 
725     sprintf(temp, "%s/dev%s/%s.aux", ditdir, devname, name);
726     auxin = fopen(temp, "r");
727     /* allocate table */
728     if (pswidths[i] == NULL) {
729 	pswidths[i] = (int *) malloc(256 * (sizeof (int)));
730     }
731     /* initialize to not-there */
732     for (j = 0; j <= 255; pswidths[i][j++] = -1);
733     /* read them in */
734     while (fscanf(auxin, "%d %d %d", &cc, &wid, &funny) != EOF) {
735 	pswidths[i][cc] = wid | (funny << 12);
736     }
737     VOIDC fclose(auxin);
738 }
739 
740 #ifdef DEBUG
741 private fontprint(i)	/* debugging print of font i (0,...) */
742 int i;
743 {
744     int     j, n;
745     char   *p;
746 
747     printf ("font %d:\n", i);
748     p = (char *) fontbase[i];
749     n = fontbase[i]->nwfont & BMASK;
750     printf ("base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",
751 	    p, n, fontbase[i]->specfont,
752 	    fontbase[i]->namefont, widthtab[i], fitab[i]);
753     printf ("widths:\n");
754     for (j = 0; j <= n; j++) {
755 	printf (" %2d", widthtab[i][j] & BMASK);
756 	if (j % 20 == 19)
757 	    printf ("\n");
758     }
759     printf ("\ncodetab:\n");
760     for (j = 0; j <= n; j++) {
761 	printf (" %2d", codetab[i][j] & BMASK);
762 	if (j % 20 == 19)
763 	    printf ("\n");
764     }
765     printf ("\nfitab:\n");
766     for (j = 0; j <= dev.nchtab + 128 - 32; j++) {
767 	printf (" %2d", fitab[i][j] & BMASK);
768 	if (j % 20 == 19)
769 	    printf ("\n");
770     }
771     printf ("\n");
772 }
773 #endif
774 
775 private loadfont(n, s, s1) /* load font info for font s on position n */
776 int n;
777 char *s, *s1;
778 {
779     char    temp[60];
780     int     fin, nw, norig;
781     int     bcount;
782 
783     if (n < 0 || n > NFONT) {
784 	fprintf(stderr,"%s: illegal fp command %d %s\n", prog, n, s);
785 	exit(2);
786     }
787     if (strcmp(s, fontbase[n]->namefont) == 0) return;
788     if (fontbase[n]->namefont != 0) {
789 	fontdelta[n] = 1;
790     }
791     if (s1 == NULL || s1[0] == '\0') {
792 	sprintf (temp, "%s/dev%s/%s.out", ditdir, devname, s);
793     }
794     else {
795 	sprintf (temp, "%s/%s.out", s1, s);
796     }
797     if ((fin = open (temp, 0)) < 0) {
798 	fprintf(stderr,"%s: can't open font table %s\n", prog, temp);
799 	pexit(prog,2);
800     }
801     norig = fontbase[n]->nwfont & BMASK;
802     bcount = 3 * norig + nchtab + 128 - 32 + sizeof (struct font);
803     VOIDC read (fin, (char *)fontbase[n], bcount);
804     if ((fontbase[n]->nwfont & BMASK) > norig) {
805 	fprintf(stderr,"%s: Font %s too big for position %d\n", prog, s, n);
806 	exit(2);
807     }
808     close (fin);
809     nw = fontbase[n]->nwfont & BMASK;
810     widthtab[n] = (char *) fontbase[n] + sizeof (struct font);
811     codetab[n] = (char *) widthtab[n] + 2 * nw;
812     fitab[n] = (char *) widthtab[n] + 3 * nw;
813     t_fp (n, fontbase[n]->namefont, fontbase[n]->intname);
814     loadpswidths (n, fontbase[n]->namefont);
815     sayload (n, s, s1);
816     fontbase[n]->nwfont = norig; /* so can later use full original size */
817 #ifdef DEBUG
818     if (fdbg > 1)
819 	fontprint (n);
820 #endif
821 }
822 
823 private sayload(n, s, s1)	/* position n contains font s (internal s1) */
824 int n;
825 char *s, *s1;
826 {
827     char    pass[60];
828     FILE    *ptrfile;
829     char    Adobefont[60];
830 
831     if (s1 == NULL || s1[0] == '\0') {
832 	sprintf (pass, "%s/dev%s/%s.map", ditdir, devname, s);
833     }
834     else {
835 	sprintf (pass, "%s/%s.map", s1, s);
836     }
837 
838     if ((ptrfile = fopen (pass, "r")) == NULL) {
839 	fprintf(stderr,"%s: can't open font map file %s\n", prog, pass);
840 	pexit(prog,2);
841     }
842 
843     fscanf (ptrfile, "%s", Adobefont);
844     FlushShow(0);
845     printf ("%d(%s)xf %d f\n", n, Adobefont, n);
846     font = n;
847     VOIDC fclose(ptrfile);
848 }
849 
850 private VOID done()
851 {
852     if (tf == NULL)
853 	exit (1);
854     t_reset ('s');
855     exit (0);
856 }
857 
858 private t_init()	/* "x i" - initialize device */
859 {
860     movepending = NONE;
861     savex = savey = 0;
862 
863     t_size (10);		/* start somewhere */
864     t_slant (0);
865     setfont (1);		/* set font */
866     printf("xi\n");
867     printf("%%%%EndProlog\n");
868 }
869 
870 private t_push()	/* begin a new block */
871 {
872     FlushShow(1);MoveTo();DoMove();
873     if (dlevel == DSTACK) {
874 	fprintf(stderr,"%s: ditroff push/pop overflow!\n",prog);
875 	exit(2);
876     }
877     ditstack[dlevel].hpos = hpos;
878     ditstack[dlevel].vpos = vpos;
879     ditstack[dlevel].fontsize = fontsize;
880     ditstack[dlevel].fontheight = fontheight;
881     ditstack[dlevel].fontslant = fontslant;
882     ditstack[dlevel].font = font;
883     dlevel++;
884     printf ("\nditpush\n");
885 }
886 
887 private t_pop()	/* pop to previous state */
888 {
889     FlushShow(1);MoveTo();DoMove();
890     if (dlevel == 0) {
891 	fprintf(stderr,"%s: ditroff push/pop underflow!\n",prog);
892 	exit(2);
893     }
894     dlevel--;
895     hpos = ditstack[dlevel].hpos;
896     vpos = ditstack[dlevel].vpos;
897     fontsize = ditstack[dlevel].fontsize;
898     fontheight = ditstack[dlevel].fontheight;
899     fontslant = ditstack[dlevel].fontslant;
900     font = ditstack[dlevel].font;
901     printf ("%d s %d xH %d xS %d f\n",fontsize,fontheight,fontslant,font);
902     startx = savex = hpos;
903     savey = vpos;
904     PSx = hpos * PSmag;
905     PSy = vpos * PSmag;
906     printf("%d %d MXY\n",savex,savey);
907     movepending = NONE;
908     printf("\nditpop\n");
909 }
910 
911 private t_page(n)	/* do whatever new page functions */
912 {
913     int     i;
914 
915     if (output) {
916 	if (++scount >= spage) {
917 	    t_reset ('p');
918 	    scount = 0;
919 	}
920     }
921     output = 1;
922     FlushShow(0);
923     if (!firstpage) {
924 	printf("\n%d p",n);
925     }
926     firstpage = FALSE;
927     printf ("\n%%%%Page: %d %d\n", n, ++pageno, n);
928     for (i = 0; i <= nfonts; i++) {
929 	if (fontdelta[i] != 0) {
930 	    sayload (i, fontname[i].name, (char *) 0);
931 	}
932     }
933     vpos = 0;
934     PSy = 0;
935     printf ("%d s %d xH %d xS %d f\n",fontsize,fontheight,fontslant,font);
936     if (nolist == 0)
937 	return;
938     output = 0;
939     for (i = 0; i < nolist; i += 2)
940 	if (n >= olist[i] && n <= olist[i + 1]) {
941 	    output = 1;
942 	    break;
943 	}
944 }
945 
946 private t_size(n)	/* convert integer to internal size number*/
947 int n;
948 {
949     FlushShow(1);
950     if (fontsize != n) {
951 	fontsize = n;
952 #ifdef XMOD
953 	fontheight = n;
954 #endif
955 	printf("%d s\n",fontsize);
956     }
957 }
958 
959 private t_charht(n)	/* set character height to n */
960 int n;
961 {
962     FlushShow(1);
963     if (fontheight != n) {
964 	fontheight = n;
965 	printf("%d xH\n",fontheight);
966     }
967 }
968 
969 private t_slant(n)	/* set slant to n */
970 int n;
971 {
972     FlushShow(1);
973     if (fontslant != n) {
974 	fontslant = n;
975 	printf("%d xS\n",fontslant);
976     }
977 }
978 
979 private t_font(s)	/* convert string to internal font number */
980 char *s;
981 {
982     int     n;
983 
984     n = atoi (s);
985     if (n < 0 || n > nfonts) n = 1;
986     return (n);
987 }
988 
989 private t_text(s)	/* print string s as text??? */
990 char *s;
991 {
992 	fprintf(stderr,"%s: ditroff t <%s> unimplemented!\n",prog,s);
993 }
994 
995 private t_reset(c)
996 {
997     output = 1;			/* by God */
998     if (c == 'p') {
999 	printf ("\nxp\n");
1000     }
1001     else {
1002 	if (!stopped)
1003 	    printf ("\nxs\n");
1004 	stopped = 1;
1005     }
1006     fflush (tf);
1007 }
1008 
1009 private t_res(res, minh, minv)
1010 int res, minh, minv;
1011 {
1012     resolution = res;
1013     minhoriz = minh;
1014     minvert = minv;
1015     printf ("%d %d %d xr\n", res, minh, minv);
1016 }
1017 
1018 private t_trailer()
1019 {
1020     FlushShow(0);
1021     printf("\n%d p",pageno);
1022     printf("\n%%%%Trailer\n");
1023     printf("xt\n");
1024 }
1025 
1026 private put1s(s)	/* s is a funny char name */
1027 char *s;
1028 {
1029     int     i;
1030 
1031     if (!output) return;
1032     debugp(("%s ", s));
1033 
1034     /* search for s in the funny char name table */
1035     for (i = 0; i < nchtab; i++) {
1036 	if (strcmp(&chname[chtab[i]], s) == 0) break;
1037     }
1038 
1039     if (i < nchtab) {
1040 	put1(i + 128, s);
1041     }
1042     else {
1043 	debugp(("not found "));
1044 	putnf (0, s);
1045     }
1046 }
1047 
1048 #define needsescape(c) ((c=='\\') || (c=='(') || (c==')'))
1049 
1050 private put1(c, s)	/* output char c */
1051 int c;
1052 char *s;
1053 {
1054     char *pw;
1055     register char *p;
1056     register int i, k;
1057     register int cc;
1058     int ofont, code;
1059     int psinfo, pswid, tw;
1060 
1061     if (!output) return;
1062     if (c == 32) {
1063 	thisw = 0;
1064 	FlushShow(0);
1065 	return;
1066     }
1067     if (c < 32) {
1068 	debugp(("non-exist 0%o\n",c));
1069 	return;
1070     }
1071 
1072     c -= 32;	/* offset char code */
1073     k = ofont = pfont = font;
1074     if (onspecial) pfont = prevfont;
1075 
1076     if ((i = (fitab[pfont][c] & BMASK)) != 0) {/* char on this font */
1077 	p = codetab[pfont];
1078 	pw = widthtab[pfont];
1079 	if (onspecial) {
1080 	    setfont(prevfont);
1081 	    thisw = 0;
1082 	    onspecial = 0;
1083 	}
1084     }
1085     else if (smnt > 0) {	/* on special (we hope) */
1086 	for (k = smnt; k <= nfonts; k += 1)
1087 	    if ((i = (fitab[k][c] & BMASK)) != 0) {
1088 		p = codetab[k];
1089 		pw = widthtab[k];
1090 		prevfont = pfont;
1091 		if (onspecial && (k == specfont)) break;
1092 		setfont (k);
1093 		thisw = 0;
1094 		onspecial = 1;
1095 		specfont = k;
1096 		break;
1097 	    }
1098     }
1099     if ((i == 0) || (k > nfonts) || ((code = p[i] & BMASK) == 0)) {
1100 	debugp(("not found 0%o\n", c+32));
1101 	putnf (c + 32, s);
1102 	return;
1103     }
1104     /* when we get here,
1105      *  c == biased character code
1106      *	k == font number
1107      *  i == index into codetab and widthtab for this character
1108      *  p == codetab for this font
1109      *  pw == width tab for this font
1110      *  code == character code for this char
1111      */
1112 
1113     cc = c + 32;
1114     debugp(((isascii(cc) && isprint(cc)) ? "%c %d\n":"%03o %d\n",
1115     		cc, code));
1116     psinfo = pswidths[font][code];	/* PS specific char info */
1117     pswid = psinfo & PSWID;		/* PS character width */
1118     thisw = pw[i] & BMASK;		/* troff char width */
1119     tw = thisw = (thisw * fontsize + dev.unitwidth/2) / dev.unitwidth;
1120 
1121     if ((psinfo & ISPSPROC) && (psinfo != -1)) {
1122 	/* character is implemented by a PostScript proc */
1123 	showspecial(s, code, pswid);
1124 	if (pswid > 0) {
1125 	    PSx += PSscale(pswid * fontsize * dres);
1126 	}
1127 	thisw = 0;
1128     }
1129     else {
1130 	showchar(code);
1131 	if (pswid > 0) {
1132 	    PSshowlen += PSscale(pswid * fontsize * dres);
1133 	}
1134     }
1135 
1136 /*
1137     if (font != ofont) {
1138 	setfont(ofont);
1139 	startx = hpos + tw;
1140 	thisw = 0;
1141 	lastcmd = FNT;
1142     }
1143 */
1144     debugp(("...width (%d)\n", pw[i]&BMASK));
1145 }
1146 
1147 
1148 private putnf(c, s)	/* note that a character wasnt found */
1149 int c;
1150 char *s;
1151 {
1152 
1153     FlushShow(0);
1154     thisw = 0;
1155     if ((s == NULL) || (*s == '\0')) printf("(\%3o)cb\n", c);
1156     else if ((strcmp(s, "\\|") == 0) || (strcmp(s, "\\^") == 0)
1157     || (strcmp (s, "\\&") == 0))
1158 	return;
1159     else
1160 	printf("(%s)cb\n", s);
1161 }
1162 
1163 
1164 private t_fp(n, s, si)	/* font position n now contains font s, intname si */
1165 int n;		/* position */
1166 char *s;	/* font (ditname) */
1167 char *si;	/* font (intname = number) */
1168 {
1169     fontname[n].name = s;
1170     fontname[n].number = atoi (si);
1171 }
1172 
1173 private setfont(n)	/* set font to n */
1174 int n;
1175 {
1176     FlushShow(1);
1177 
1178     if (n < 0 || n > NFONT) {
1179 	fprintf(stderr,"%s: illegal font %d\n", prog,n);
1180     }
1181     if (font != n) {
1182 	font = n;
1183 	printf("%d f\n",font);
1184     }
1185     onspecial = 0;
1186 }
1187 
1188 private drawline(dx, dy)	/* draw line from here to dx, dy */
1189 int dx, dy;
1190 {
1191     FlushShow(0); MoveTo(); DoMove();
1192     printf("%d %d Dl\n", dx, dy);
1193     hpos += dx;
1194     PSx = hpos * PSmag;
1195     vpos += dy;
1196     PSy = vpos * PSmag;
1197 }
1198 
1199 private drawwig(s)	/* draw wiggly line */
1200 char *s;
1201 {
1202     FlushShow(0); MoveTo(); DoMove();
1203     printf("D~ %s D~~\n",s);
1204 }
1205 
1206 private drawcirc(d)
1207 int d;
1208 {
1209     FlushShow(0); MoveTo(); DoMove();
1210     printf("%d Dc\n",d);
1211 }
1212 
1213 private drawarc(dx1, dy1, dx2, dy2)
1214 int dx1, dy1, dx2, dy2;
1215 {
1216     FlushShow(0); MoveTo(); DoMove();
1217     printf("%d %d %d %d Da\n", dx1, dy1, dx2, dy2);
1218     hpos += dx1 + dx2;
1219     PSx = hpos * PSmag;
1220     vpos += dy1 + dy2;
1221     PSy = vpos * PSmag;
1222 }
1223 
1224 private drawellip(a, b)
1225 int a, b;
1226 {
1227     FlushShow(0);MoveTo();DoMove();
1228     printf("%d %d De\n",a,b);
1229 }
1230 
1231 private hmot(a)	/* relative horizontal motion */
1232 int a;
1233 {
1234     register int aa;
1235     aa = abs(a);
1236     if ((aa < 8) || (aa > (10 * thisw)) || (a >= 100)
1237     || ((thisw != 0) && (abs(thisw - a) > 4))) {
1238 	FlushShow(1);
1239     }
1240     hpos += a;
1241     if (lastcmd != CPUT) startx = hpos;
1242 }
1243 
1244 private hgoto(a) /* absolute horizontal motion */
1245 int a;
1246 {
1247     FlushShow(1);
1248     startx = hpos = a;
1249     thisw = 0;
1250 }
1251 
1252 private vmot(a) /* relative vertical motion */
1253 int a;
1254 {
1255     FlushShow(1);
1256     vpos += a;
1257     thisw = 0;
1258 }
1259 
1260 private vgoto(a) /* absolute vertical motion */
1261 int a;
1262 {
1263     FlushShow(1);
1264     vpos = a;
1265     thisw = 0;
1266 }
1267 
1268 private showspecial(s,cc,wid)
1269 char *s;
1270 int cc;
1271 int wid;
1272 {
1273     char *sp;
1274 
1275     FlushShow(0);
1276     MoveTo();
1277     DoMove();
1278     putchar('(');
1279     for (sp = s; *sp != '\0'; sp++) {
1280 	if (needsescape(*sp)) {
1281 	    putchar('\\');
1282 	}
1283 	putchar(*sp);
1284     }
1285     printf(")%d %d oc\n",cc,wid);
1286 }
1287 
1288 private showchar(c)
1289 int c;
1290 {
1291     if (showind == 0) {MoveTo();}
1292     else if ((vpos * PSmag) != PSy) {
1293 	FlushShow(0);
1294 	MoveTo();
1295     }
1296     if (showind >= SHOWSIZE) FlushShow(0);
1297     if (isascii(c) && isprint(c)) {
1298 	switch (c) {
1299 	    case '\\': case '(': case ')':
1300 	        showbuf[showind++] = '\\';
1301 		/* fall through */
1302 
1303 	    default:
1304 		showbuf[showind++] = c;
1305 	}
1306     }
1307     else {
1308 	showbuf[showind++] = '\\';
1309 	showbuf[showind++] = ((c>>6)&03) + '0';
1310 	showbuf[showind++] = ((c>>3)&07) + '0';
1311 	showbuf[showind++] = (c&07) + '0';
1312     }
1313     showbuf[showind] = '\0';
1314     nshow++;
1315 }
1316 
1317 private MoveTo() {
1318     int x, y;
1319     x = hpos * PSmag;
1320     y = vpos * PSmag;
1321 
1322     if (x != PSx) {
1323 	startx = savex = hpos;
1324 	PSx = x;
1325 	movepending |= XMOVE;
1326     }
1327     if (y != PSy) {
1328 	savey = vpos;
1329 	PSy = y;
1330 	movepending |= YMOVE;
1331     }
1332 }
1333 
1334 private FlushMove() {
1335     switch (movepending) {
1336 	case NONE:
1337 	    break;
1338 	case XMOVE:
1339 	    printf("%d",savex);
1340 	    break;
1341 	case YMOVE:
1342 	    printf("%d",savey);
1343 	    break;
1344 	case XYMOVE:
1345 	    printf("%d %d",savex,savey);
1346 	    break;
1347 	default:
1348 	    fprintf(stderr,"%s: invalid move code %d\n",prog, movepending);
1349 	    exit(2);
1350     }
1351 }
1352 
1353 private char *movecmds[] = {
1354     "MX","MY","MXY"
1355 };
1356 
1357 private DoMove() {
1358     FlushMove();
1359     if (movepending != NONE) {
1360 	printf(" %s\n",movecmds[movepending-1]);
1361 	movepending = NONE;
1362     }
1363 }
1364 
1365 private char showops[] = "SXYN";
1366 
1367 private FlushShow(t) int t; {
1368     long err, tlen;
1369     float cerror;
1370 
1371     if (showind == 0) {thisw = 0; return;}
1372     if (movepending != NONE) {
1373 	FlushMove();
1374     }
1375     tlen = hpos - startx;
1376     if (lastcmd == CPUT) tlen += thisw;
1377     err = tlen * PSmag - PSshowlen;
1378     if ((nshow != 1) && (abs(err) > ErrorTolerance)) {
1379 	cerror = ((float) err) / ((nshow - 1) * PSmag);
1380 #ifdef DEBUG
1381 	fprintf(stderr,"F%d lc %d thisw %d ",t,lastcmd,thisw);
1382         fprintf(stderr,"x %ld h %ld tn %ld %ld ",
1383 		startx, hpos, tlen*PSmag,PSshowlen);
1384 	fprintf(stderr,"error %d %.4f %s\n",nshow,cerror,showbuf);
1385 	fflush(stderr);
1386 #endif
1387 	printf(" %.4f(%s)A%c\n", cerror, showbuf, showops[movepending]);
1388     }
1389     else {
1390 	printf("(%s)%c\n", showbuf, showops[movepending]);
1391     }
1392 
1393     showind = 0;
1394     nshow = 0;
1395     showbuf[showind] = '\0';
1396     PSx += PSshowlen;
1397     PSshowlen = 0;
1398     startx = hpos;
1399     if (lastcmd == CPUT) startx += thisw;
1400     thisw = 0;
1401     movepending = NONE;
1402 }
1403