clean up input (check for EOF), fix algorithm for calculating when
[unix-history] / usr / src / local / ditroff / ditroff.old.okeeffe / driver / dip.c
CommitLineData
0ed3cde2 1/* dip.c 1.6 (Berkeley) 84/01/03
ef0f9059
DS
2 * dip
3 * driver for impress/imagen canon laser printer
4 */
5
6/*
7output language from troff:
8all numbers are character strings
9
10sn size in points
11fn font as number from 1-n
12cx ascii character x
13Cxyz funny char xyz. terminated by white space
14Hn go to absolute horizontal position n
15Vn go to absolute vertical position n (down is positive)
16hn go n units horizontally (relative)
17vn ditto vertically
18nnc move right nn, then print c (exactly 2 digits!)
19 (this wart is an optimization that shrinks output file size
20 about 35% and run-time about 15% while preserving ascii-ness)
21Dt ...\n draw operation 't':
22 Dl x y line from here by x,y
23 Dc d circle of diameter d with left side here
24 De x y ellipse of axes x,y with left side here
25 Da x y r arc counter-clockwise by x,y of radius r
26 D~ x y x y ... wiggly line by x,y then x,y ...
27nb a end of line (information only -- no action needed)
28 b = space before line, a = after
6dded2dd 29pn new page begins -- set v to 0
ef0f9059
DS
30#...\n comment
31x ...\n device control functions:
32 x i init
33 x T s name of device is s
34 x r n h v resolution is n/inch
35 h = min horizontal motion, v = min vert
36 x p pause (can restart)
37 x s stop -- done for ever
38 x t generate trailer
39 x f n s font position n contains font s
40 x H n set character height to n
41 x S n set slant to N
42
43 Subcommands like "i" are often spelled out like "init".
44*/
45
46#include <stdio.h>
47#include <signal.h>
48#include <math.h>
49#include <ctype.h>
ef0f9059
DS
50#include "dev.h"
51#include "canon.h"
6dded2dd 52#include "rst.h"
ef0f9059 53
ef0f9059 54
6dded2dd
DS
55/* #define DEBUGABLE /* whether or not it'll accept the -d option */
56#define abs(n) ((n) >= 0 ? (n) : -(n))
57#define hmot(n) hpos += n
58#define hgoto(n) hpos = n
59#define vmot(n) vpos += n
60#define vgoto(n) vpos = n
ef0f9059 61
6dded2dd
DS
62#define FATAL 1
63#define BMASK 0377
64#define NFONT 30 /* maximum forever */
65
313aa806 66#ifndef FONTDIR
6dded2dd 67#define FONTDIR "/usr/lib/font";
313aa806 68#endif
6dded2dd
DS
69#define BITDIR "/usr/local/lib/ifontt";
70
71 /* BOTTOMTHRESH and DELTATHRESH are used to */
72 /* search through the glyphs downloaded to */
73 /* determine which ones to keep and which to */
74 /* dump. They're tested against BOTTOMTHRESH */
75 /* first, then if THAT doesn't release enough */
76 /* space, DELTATHRESH is added until it is. */
77#define BOTTOMTHRESH 16
78#define DELTATHRESH 16
79#define MEMSIZE 70000 /* amount of memory inside imagen */
80#define BUFFER 20000 /* imagen memory set aside for page buffer */
81#define CHARRAY 128 /* size of character use count array */
82
83int MAXX = (RES*8+RES/3); /* size of the page... (not 8-1/2" x 11", */
84int MAXY = (RES*10+RES/2+RES/4); /* but 8-1/3" x 10-3/4") */
85
86int output = 0; /* do we do output at all? */
87int pageno = -1; /* output page number */
88int nolist = 0; /* output page list if > 0 */
89int olist[20]; /* pairs of page numbers */
ef0f9059
DS
90
91struct dev dev;
92struct font *fontbase[NFONT+1];
6dded2dd
DS
93short * pstab;
94int nsizes = 1;
ef0f9059 95int nfonts;
ef0f9059 96int nchtab;
6dded2dd
DS
97char * chname;
98short * chtab;
99unsigned char * fitab[NFONT+1]; /* legal characters for each font */
100unsigned char * widtab[NFONT+1]; /* width table for each font */
101unsigned char * codetab[NFONT+1]; /* device code translation */
102char * fontname[NFONT+1]; /* what font is on what position? */
103
104#ifdef DEBUGABLE
ef0f9059 105int dbg = 0;
6dded2dd
DS
106#endif
107
108FILE * tf = stdout; /* output file pointer */
109char * fontdir = FONTDIR;
110char * bitdir = BITDIR;
111FILE * fp = stdin; /* input file pointer */
112
113int totglyph= 0; /* total space used by glyphs sent down */
114int maxglyph= MEMSIZE - BUFFER; /* maximum space for glyphs */
115
116int size = 1;
117int font = 1;
118int family;
119int hpos; /* current horizontal position (left = 0) */
120int vpos; /* current vertical position (down positive) */
121int lastw = 0; /* width of last input character */
122extern int linethickness; /* line drawing pars: Thickness (pixels) */
123extern int style; /* and type (SOLID, DOTTED, . . . ) */
124
125typedef struct {
126 int font;
127 int size;
128 unsigned char chused[CHARRAY]; /* test array - character downloaded? */
129 glyph_dir *glyph; /* array of character descriptions */
130 unsigned char *cdp; /* char data pointer */
131} fontset;
132
133fontset *fs; /* A global pointer to the current family */
134fontset fontdata[NFONT+1]; /* table of family data descripters */
135
136int lastsize = -1;
137int lastfont = -1;
138int lastx = -1;
139int lasty = -1;
140int lastfam = -1;
141
142
ef0f9059
DS
143
144main(argc, argv)
145char *argv[];
146{
6dded2dd 147 int i;
ef0f9059 148 char *mktemp();
6dded2dd 149 char *operand();
ef0f9059 150
6dded2dd
DS
151 while (--argc > 0 && **++argv == '-') {
152 switch ((*argv)[1]) {
2cf235a3
DS
153 case 'X':
154 MAXX = atoi(operand(&argc, &argv));
155 break;
156 case 'Y':
157 MAXY = atoi(operand(&argc, &argv));
158 break;
6dded2dd
DS
159 case 'F':
160 fontdir = operand(&argc, &argv);
ef0f9059
DS
161 break;
162 case 'f':
6dded2dd 163 bitdir = operand(&argc, &argv);
ef0f9059
DS
164 break;
165 case 'o':
6dded2dd 166 outlist(operand(&argc, &argv));
ef0f9059
DS
167 break;
168 case 'b':
6dded2dd
DS
169 if ((i = atoi(operand(&argc, &argv))) < 1000) i = 1000;
170 else if (i > MEMSIZE - 1000) i = MEMSIZE - 1000;
171 maxglyph = MEMSIZE - i;
ef0f9059 172 break;
6dded2dd 173#ifdef DEBUGABLE
ef0f9059 174 case 'd':
6dded2dd
DS
175 dbg = atoi(operand(&argc, &argv));
176 if (dbg == 0) error (FATAL, "no debug value");
ef0f9059 177 break;
6dded2dd 178#endif
ef0f9059 179 }
ef0f9059
DS
180 }
181
6dded2dd 182 if (argc < 1)
ef0f9059
DS
183 conv(stdin);
184 else
6dded2dd
DS
185 while (argc-- > 0) {
186 if (strcmp(*argv, "-") == 0)
ef0f9059
DS
187 fp = stdin;
188 else if ((fp = fopen(*argv, "r")) == NULL)
189 error(FATAL, "can't open %s", *argv);
190 conv(fp);
191 fclose(fp);
6dded2dd 192 argv++;
ef0f9059 193 }
6dded2dd 194
ef0f9059 195 t_wrapup();
6dded2dd
DS
196 exit(0);
197}
198
199
200/*----------------------------------------------------------------------------*
201 | Routine: char * operand (& argc, & argv)
202 |
203 | Results: returns address of the operand given with a command-line
204 | option. It uses either "-Xoperand" or "-X operand", whichever
205 | is present. The program is terminated if no option is present.
206 |
207 | Side Efct: argc and argv are updated as necessary.
208 *----------------------------------------------------------------------------*/
209
210char *operand(argcp, argvp)
211int * argcp;
212char ***argvp;
213{
214 if ((**argvp)[2]) return(**argvp + 2); /* operand immediately follows */
215 if ((--*argcp) <= 0) { /* no operand */
2cf235a3 216 error (FATAL, "command-line option operand missing.");
ef0f9059 217 }
6dded2dd 218 return(*(++(*argvp))); /* operand next word */
ef0f9059
DS
219}
220
6dded2dd 221
ef0f9059 222outlist(s) /* process list of page numbers to be printed */
0b2b2a0e 223register char *s;
ef0f9059 224{
0b2b2a0e 225 register int n1, n2;
ef0f9059
DS
226
227 nolist = 0;
228 while (*s) {
229 n1 = 0;
230 if (isdigit(*s))
231 do
232 n1 = 10 * n1 + *s++ - '0';
233 while (isdigit(*s));
234 else
235 n1 = -9999;
236 n2 = n1;
237 if (*s == '-') {
238 s++;
239 n2 = 0;
240 if (isdigit(*s))
241 do
242 n2 = 10 * n2 + *s++ - '0';
243 while (isdigit(*s));
244 else
245 n2 = 9999;
246 }
247 olist[nolist++] = n1;
248 olist[nolist++] = n2;
249 if (*s != '\0')
250 s++;
251 }
252 olist[nolist] = 0;
6dded2dd 253#ifdef DEBUGABLE
ef0f9059
DS
254 if (dbg)
255 for (i=0; i<nolist; i += 2)
256 printf("%3d %3d\n", olist[i], olist[i+1]);
6dded2dd 257#endif
ef0f9059
DS
258}
259
6dded2dd 260
ef0f9059
DS
261in_olist(n) /* is n in olist? */
262int n;
263{
264 int i;
265
266 if (nolist == 0)
267 return(1); /* everything is included */
268 for (i = 0; i < nolist; i += 2)
269 if (n >= olist[i] && n <= olist[i+1])
270 return(1);
271 return(0);
272}
273
6dded2dd 274
ef0f9059
DS
275conv(fp)
276register FILE *fp;
277{
6dded2dd
DS
278 register int c;
279 register int k;
280 int m, n, n1, m1;
ef0f9059
DS
281 char str[100], buf[300];
282
283 while ((c = getc(fp)) != EOF) {
284 switch (c) {
285 case '\n': /* when input is text */
286 case ' ':
287 case 0: /* occasional noise creeps in */
288 break;
289 case '0': case '1': case '2': case '3': case '4':
290 case '5': case '6': case '7': case '8': case '9':
291 /* two motion digits plus a character */
292 hmot((c-'0')*10 + getc(fp)-'0');
293 put1(getc(fp));
294 break;
295 case 'c': /* single ascii character */
296 put1(getc(fp));
297 break;
298 case 'C':
299 fscanf(fp, "%s", str);
300 put1s(str);
301 break;
302 case 'D': /* draw function */
303 fgets(buf, sizeof(buf), fp);
304 switch (buf[0]) {
305 case 'l': /* draw a line */
306 sscanf(buf+1, "%d %d", &n, &m);
6dded2dd 307 drawline(n, m, ".");
ef0f9059
DS
308 break;
309 case 'c': /* circle */
310 sscanf(buf+1, "%d", &n);
311 drawcirc(n);
312 break;
313 case 'e': /* ellipse */
314 sscanf(buf+1, "%d %d", &m, &n);
315 drawellip(m, n);
316 break;
317 case 'a': /* arc */
318 sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
319 drawarc(n, m, n1, m1);
320 break;
321 case 'g': /* gremlin curve */
0b2b2a0e
DS
322 drawwig(buf+1, fp, 0);
323 break;
ef0f9059 324 case '~': /* wiggly line */
0b2b2a0e 325 drawwig(buf+1, fp, 1);
6dded2dd 326 break;
0b2b2a0e 327 case 't': /* line-thickness */
6dded2dd
DS
328 sscanf(buf+1, "%d", &n);
329 drawthick(n);
330 break;
0b2b2a0e 331 case 's': /* line-style */
6dded2dd
DS
332 sscanf(buf+1, "%d", &n);
333 drawstyle(n);
ef0f9059
DS
334 break;
335 default:
6dded2dd 336 error(FATAL, "unknown drawing function %s",buf);
ef0f9059
DS
337 break;
338 }
339 break;
340 case 's':
341 fscanf(fp, "%d", &n); /* ignore fractional sizes */
342 setsize(t_size(n));
343 break;
344 case 'f':
345 fscanf(fp, "%s", str);
346 setfont(t_font(str));
347 break;
348 case 'H': /* absolute horizontal motion */
349 /* fscanf(fp, "%d", &n); */
350 while ((c = getc(fp)) == ' ')
351 ;
352 k = 0;
353 do {
354 k = 10 * k + c - '0';
355 } while (isdigit(c = getc(fp)));
356 ungetc(c, fp);
357 hgoto(k);
358 break;
359 case 'h': /* relative horizontal motion */
360 /* fscanf(fp, "%d", &n); */
361 while ((c = getc(fp)) == ' ')
362 ;
363 k = 0;
364 do {
365 k = 10 * k + c - '0';
366 } while (isdigit(c = getc(fp)));
367 ungetc(c, fp);
368 hmot(k);
369 break;
370 case 'w': /* word space */
371 break;
372 case 'V':
373 fscanf(fp, "%d", &n);
374 vgoto(n);
375 break;
376 case 'v':
377 fscanf(fp, "%d", &n);
378 vmot(n);
379 break;
380 case 'p': /* new page */
381 fscanf(fp, "%d", &n);
382 t_page(n);
383 break;
384 case 'n': /* end of line */
385 while (getc(fp) != '\n')
386 ;
6dded2dd 387 hpos = 0;
ef0f9059
DS
388 break;
389 case '#': /* comment */
390 while (getc(fp) != '\n')
391 ;
392 break;
393 case 'x': /* device control */
0b2b2a0e 394 if (devcntrl(fp)) return;
ef0f9059
DS
395 break;
396 default:
2cf235a3 397 error(FATAL, "unknown input character %o %c", c, c);
ef0f9059
DS
398 }
399 }
400}
401
6dded2dd 402
0b2b2a0e
DS
403int devcntrl(fp) /* interpret device control functions */
404FILE *fp; /* returns -1 upon "stop" command */
ef0f9059
DS
405{
406 char str[20], str1[50], buf[50];
407 int c, n;
408
409 fscanf(fp, "%s", str);
410 switch (str[0]) { /* crude for now */
411 case 'i': /* initialize */
412 fileinit();
413 t_init(0);
414 break;
415 case 'T': /* device name */
ef0f9059 416 case 't': /* trailer */
ef0f9059 417 case 'p': /* pause -- can restart */
ef0f9059 418 break;
0b2b2a0e
DS
419 case 's': /* stop */
420 return -1;
ef0f9059 421 case 'r': /* resolution assumed when prepared */
6dded2dd
DS
422 fscanf(fp, "%d", &n);
423 if (n!=RES) error(FATAL,"Input computed with wrong resolution");
ef0f9059
DS
424 break;
425 case 'f': /* font used */
426 fscanf(fp, "%d %s", &n, str);
427 fgets(buf, sizeof buf, fp); /* in case there's a filename */
428 ungetc('\n', fp); /* fgets goes too far */
429 str1[0] = 0; /* in case there's nothing to come in */
430 sscanf(buf, "%s", str1);
431 loadfont(n, str, str1);
432 break;
433 case 'H': /* char height */
434 fscanf(fp, "%d", &n);
435 t_charht(n);
436 break;
437 case 'S': /* slant */
438 fscanf(fp, "%d", &n);
439 t_slant(n);
440 break;
441 }
442 while ((c = getc(fp)) != '\n') /* skip rest of input line */
443 if (c == EOF)
0b2b2a0e
DS
444 return -1;
445 return 0;
ef0f9059
DS
446}
447
6dded2dd 448
ef0f9059
DS
449fileinit() /* read in font and code files, etc. */
450{
6dded2dd
DS
451 register int i;
452 register int fin;
453 register int nw;
454 register unsigned char *filebase;
455 register unsigned char *p;
456 unsigned char *malloc();
457 char temp[100];
ef0f9059 458
6dded2dd
DS
459 /* open table for device,
460 * read in resolution, size info, font info, etc.
461 * and set params
462 */
ef0f9059 463
6dded2dd 464 sprintf(temp, "%s/devip/DESC.out", fontdir);
ef0f9059
DS
465 if ((fin = open(temp, 0)) < 0)
466 error(FATAL, "can't open tables for %s", temp);
467 read(fin, &dev, sizeof(struct dev));
468 nfonts = dev.nfonts;
469 nsizes = dev.nsizes;
470 nchtab = dev.nchtab;
471 filebase = malloc(dev.filesize); /* enough room for whole file */
472 read(fin, filebase, dev.filesize); /* all at once */
473 pstab = (short *) filebase;
474 chtab = pstab + nsizes + 1;
475 chname = (char *) (chtab + dev.nchtab);
6dded2dd
DS
476 p = (unsigned char *) chname + dev.lchname;
477 for (i = 1; i <= nfonts; i++) {
478 fontbase[i] = (struct font *) p;
479 nw = *p & BMASK; /* 1st thing is width count */
480 p += sizeof(struct font);
481 widtab[i] = p; /* then width table */
482 codetab[i] = p + 2 * nw; /* then code conversion table */
483 fitab[i] = p + 3 * nw; /* then font inclusion table */
484 p += 3 * nw + dev.nchtab + 128 - 32;
485 t_fp(i, fontbase[i]->namefont, fontbase[i]->intname);
486#ifdef DEBUGABLE
487 if (dbg > 1) fontprint(i);
488#endif
ef0f9059 489 }
6dded2dd
DS
490 fontbase[0] = NULL;
491 close(fin); /* no fonts loaded yet */
492 for (i = 0; i <= NFONT; i++) fontdata[i].font = fontdata[i].size = -1;
ef0f9059
DS
493}
494
6dded2dd
DS
495
496#ifdef DEBUGABLE
ef0f9059
DS
497fontprint(i) /* debugging print of font i (0,...) */
498{
6dded2dd 499 int j, n;
ef0f9059
DS
500 char *p;
501
502 printf("font %d:\n", i);
503 p = (char *) fontbase[i];
504 n = fontbase[i]->nwfont & BMASK;
505 printf("base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",
6dded2dd 506 p, n, fontbase[i]->specfont, fontbase[i]->namefont, widtab[i], fitab[i]);
ef0f9059
DS
507 printf("widths:\n");
508 for (j=0; j <= n; j++) {
6dded2dd 509 printf(" %2d", widtab[i][j] & BMASK);
ef0f9059
DS
510 if (j % 20 == 19) printf("\n");
511 }
512 printf("\ncodetab:\n");
513 for (j=0; j <= n; j++) {
514 printf(" %2d", codetab[i][j] & BMASK);
515 if (j % 20 == 19) printf("\n");
516 }
517 printf("\nfitab:\n");
518 for (j=0; j <= dev.nchtab + 128-32; j++) {
519 printf(" %2d", fitab[i][j] & BMASK);
520 if (j % 20 == 19) printf("\n");
521 }
522 printf("\n");
523}
6dded2dd
DS
524#endif
525
ef0f9059
DS
526
527loadfont(n, s, s1) /* load font info for font s on position n (0...) */
528int n;
529char *s, *s1;
530{
531 char temp[60];
6dded2dd 532 int fin, nw;
ef0f9059
DS
533
534 if (n < 0 || n > NFONT)
535 error(FATAL, "illegal fp command %d %s", n, s);
536 if (fontbase[n] != NULL && strcmp(s, fontbase[n]->namefont) == 0)
537 return;
538 if (s1 == NULL || s1[0] == '\0')
6dded2dd 539 sprintf(temp, "%s/devip/%s.out", fontdir, s);
ef0f9059
DS
540 else
541 sprintf(temp, "%s/%s.out", s1, s);
542 if ((fin = open(temp, 0)) < 0) {
543 error(!FATAL, "can't open font table %s", temp);
544 return;
545 }
546 if (fontbase[n] != NULL)
547 free(fontbase[n]);
548 fontbase[n] = (struct font *) malloc(3*255 + dev.nchtab +
549 (128-32) + sizeof(struct font));
550 if (fontbase[n] == NULL)
551 error(FATAL, "Out of space in loadfont %s", s);
552 read(fin, fontbase[n], 3*255 + nchtab+128-32 + sizeof(struct font));
553 close(fin);
ef0f9059 554 nw = fontbase[n]->nwfont & BMASK;
6dded2dd
DS
555 widtab[n] = (unsigned char *) fontbase[n] + sizeof(struct font);
556 codetab[n] = (unsigned char *) widtab[n] + 2 * nw;
557 fitab[n] = (unsigned char *) widtab[n] + 3 * nw;
ef0f9059 558 t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
6dded2dd 559#ifdef DEBUGABLE
ef0f9059 560 if (dbg > 1) fontprint(n);
6dded2dd 561#endif
ef0f9059
DS
562}
563
ef0f9059 564
6dded2dd
DS
565/*VARARGS2*/
566error(f, s, a1, a2, a3, a4, a5, a6, a7)
567int f;
568char *s;
569{
ef0f9059
DS
570 fprintf(stderr, "dip: ");
571 fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
572 fprintf(stderr, "\n");
573 if (f)
2cf235a3 574 exit(2);
ef0f9059
DS
575}
576
577
ef0f9059
DS
578t_init(reinit) /* initialize device */
579int reinit;
580{
ef0f9059 581 if (! reinit) {
6dded2dd 582 drawthick(3); /* set the line thickness parameter */
ef0f9059
DS
583 }
584 hpos = vpos = 0;
585 setsize(t_size(10)); /* start somewhere */
586}
587
6dded2dd
DS
588
589/*----------------------------------------------------------------------------*
590 | Routine: t_page ( page_number )
591 |
592 | Results: mark this page done for printing. If we think we've filled
593 | the imagen too much, delete some of the info in the glyph cache.
594 | This is a good time to do this since it's at the end of a page
595 | and will get done every so often.
596 *----------------------------------------------------------------------------*/
ef0f9059
DS
597
598t_page(pg) /* do whatever new page functions */
599{
6dded2dd
DS
600 register int i;
601 register int threshold;
ef0f9059
DS
602
603 pageno = pg;
6dded2dd 604#ifdef DEBUGABLE
ef0f9059 605 if(dbg)fprintf(stderr, "t_page %d, output=%d\n", pg, output);
6dded2dd
DS
606#endif
607 if (output != 0)
ef0f9059 608 putc(AEND, tf);
ef0f9059 609 output = in_olist(pg);
6dded2dd 610
ef0f9059 611 if (output) {
6dded2dd
DS
612 threshold = BOTTOMTHRESH;
613 while (totglyph >= maxglyph) {
614 for (i = 0; i < NFONT; i++) {
615 if (fontdata[i].font != -1)
616 clearglyphs(i, threshold);
ef0f9059 617 }
6dded2dd
DS
618 threshold += DELTATHRESH;
619 }
ef0f9059
DS
620 }
621 lastx = lasty = -1;
622 t_init(1);
623}
624
ef0f9059
DS
625
626t_size(n) /* convert integer to internal size number*/
627int n;
628{
629 int i;
630
631 if (n <= pstab[0])
632 return(1);
633 else if (n >= pstab[nsizes-1])
6dded2dd 634 return(nsizes-1);
ef0f9059
DS
635 for (i = 0; n > pstab[i]; i++)
636 ;
6dded2dd 637 return(i);
ef0f9059
DS
638}
639
6dded2dd 640
ef0f9059
DS
641t_charht(n) /* set character height to n */
642int n;
643{
644 /* punt for now */
645}
646
6dded2dd 647
ef0f9059
DS
648t_slant(n) /* set slant to n */
649int n;
650{
651 /* punt for now */
652}
653
6dded2dd 654
ef0f9059
DS
655t_font(s) /* convert string to internal font number */
656char *s;
657{
658 int n;
659
660 n = atoi(s);
661 if (n < 0 || n > nfonts)
662 n = 1;
663 return(n);
664}
665
ef0f9059
DS
666
667t_wrapup()
668{
669 putc(AEND, tf);
670 putc(AEOF, tf);
671}
672
ef0f9059 673
ef0f9059 674put1s(s) /* s is a funny char name */
6dded2dd 675register char *s;
ef0f9059
DS
676{
677 static int i = 0;
678
679 if (!output)
680 return;
6dded2dd 681#ifdef DEBUGABLE
ef0f9059 682 if (dbg) printf("%s ", s);
6dded2dd 683#endif
ef0f9059
DS
684 if (strcmp(s, &chname[chtab[i]]) != 0)
685 for (i = 0; i < nchtab; i++)
686 if (strcmp(&chname[chtab[i]], s) == 0)
687 break;
688 if (i < nchtab)
689 put1(i + 128);
690 else
691 i = 0;
692}
693
6dded2dd 694
ef0f9059 695put1(c) /* output char c */
6dded2dd 696register int c;
ef0f9059 697{
6dded2dd
DS
698 register unsigned char *pw;
699 register unsigned char *p;
700 register int i;
701 register int j;
702 register int k;
703 int ofont, code;
ef0f9059
DS
704
705 if (!output)
706 return;
707 c -= 32;
708 if (c <= 0) {
6dded2dd 709#ifdef DEBUGABLE
ef0f9059 710 if (dbg) printf("non-exist 0%o\n", c+32);
6dded2dd 711#endif
ef0f9059
DS
712 return;
713 }
6dded2dd
DS
714 ofont = font;
715 i = fitab[font][c];
ef0f9059
DS
716 if (i != 0) { /* it's on this font */
717 p = codetab[font];
6dded2dd
DS
718 pw = widtab[font];
719 } else { /* on another font */
2cf235a3 720 k = font; /* start with current, then run down the list */
6dded2dd
DS
721 for (j=0; j++ <= nfonts; k = (k+1) % (nfonts+1))
722 if (fontbase[k] != NULL && (i = fitab[k][c]) != 0) {
ef0f9059 723 p = codetab[k];
6dded2dd 724 pw = widtab[k];
ef0f9059
DS
725 setfont(k);
726 break;
727 }
728 }
6dded2dd
DS
729 code = p[i] & BMASK;
730 if (i == 0) {
731#ifdef DEBUGABLE
ef0f9059 732 if (dbg) printf("not found 0%o\n", c+32);
6dded2dd 733#endif
ef0f9059
DS
734 return;
735 }
6dded2dd
DS
736 lastw = (pw[i] * pstab[size] + dev.unitwidth/2) / dev.unitwidth;
737#ifdef DEBUGABLE
ef0f9059
DS
738 if (dbg) {
739 if (isprint(c+32))
740 printf("%c %d\n", c+32, code);
741 else
742 printf("%03o %d\n", c+32, code);
743 } else
6dded2dd
DS
744#endif
745 if (output) xychar(code);
ef0f9059
DS
746 if (font != ofont)
747 setfont(ofont);
748}
749
6dded2dd 750
ef0f9059
DS
751setsize(n) /* set point size to n (internal) */
752int n;
753{
754 size = n;
755}
756
ef0f9059 757
6dded2dd
DS
758/*----------------------------------------------------------------------------*
759 | Routine: t_fp ( number, string, string_internal )
760 |
761 | Results: font position number now contains font 'string', internal
762 | font name (number) is ignored.
763 |
764 | Side Efct: any fonts loaded into fontdata with this font number are
765 | removed. And, to make sure they're not accessed, if lastfont
766 | equals number, it is "disabled" by setting lastfont to -1.
767 *----------------------------------------------------------------------------*/
ef0f9059 768
6dded2dd 769t_fp(n, s, si)
ef0f9059
DS
770int n;
771char *s, *si;
772{
6dded2dd
DS
773 register int i;
774
775 fontname[n] = s;
776 for (i = 0; i <= NFONT; i++) /* release any font files */
777 if (fontdata[i].font == n) { /* for this font */
778 clearglyphs (i, 1000);
779 putc(AFORCE, tf);
780 free (fontdata[i].cdp);
781 free (fontdata[i].glyph);
782 fontdata[i].font = -1;
783 }
784 if (n == lastfont) lastfont = -1;
ef0f9059
DS
785}
786
6dded2dd 787
ef0f9059
DS
788setfont(n) /* set font to n */
789int n;
790{
791 if (!output)
792 return;
793 if (n < 0 || n > NFONT)
794 error(FATAL, "illegal font %d", n);
795 font = n;
796}
797
ef0f9059 798
6dded2dd
DS
799/*----------------------------------------------------------------------------*
800 | Routine: rd1, rd2, rd3, rd4 ( file_pointer )
801 |
802 | Results: gets one, two three or four bytes from a file and interprets
803 | them as integers. Most significant bytes come first.
804 *----------------------------------------------------------------------------*/
ef0f9059 805
6dded2dd
DS
806int rd1(fp)
807FILE *fp;
808{
809 register int i;
ef0f9059 810
6dded2dd
DS
811 if((i = getc(fp)) == EOF) error(FATAL, "font file read error");
812 return i;
813}
ef0f9059 814
6dded2dd
DS
815int rd2(fp)
816FILE *fp;
817{
818 register short i = rd1(fp) << 8;
ef0f9059 819
6dded2dd
DS
820 return i | rd1(fp);
821}
ef0f9059 822
6dded2dd
DS
823int rd3(fp)
824FILE *fp;
ef0f9059 825{
6dded2dd 826 register int i = rd2(fp) << 8;
ef0f9059 827
6dded2dd 828 return i | rd1(fp);
ef0f9059
DS
829}
830
6dded2dd
DS
831int rd4(fp)
832FILE *fp;
ef0f9059 833{
6dded2dd 834 register int i = rd2(fp) << 16;
ef0f9059 835
6dded2dd
DS
836 return i | rd2(fp);
837}
ef0f9059 838
ef0f9059 839
6dded2dd
DS
840/*----------------------------------------------------------------------------*
841 | Routine: getfontdata ( font, size )
842 |
843 | Results: returns the family number of the font/size found. The font
844 | information pointer, fs, is set to point to data for "font"
845 | at point size "size". If no information for that font is
846 | available, the info is read in from the appropriate font file.
847 | The table "fontdata" holds all the fonts, and it is cleared
848 | of a random font/size if necessary.
849 *----------------------------------------------------------------------------*/
850
851int getfontdata(f, s)
852int f;
853int s;
854{
855 char name[100];
856 register FILE *fd;
857 register int i;
858 register int fam;
859 register int bitbase;
860 register glyph_dir *maxgp;
861 register glyph_dir *mingp;
862 register glyph_dir *gp;
863 preamble p;
864
865 /* first check if it's here already */
866 for (fam = 0; fam <= NFONT; fam++)
867 if (fontdata[fam].font == f && fontdata[fam].size == s) {
868 fs = &fontdata[fam];
869 return (fam);
870 }
871 /* find an empty slot */
872 for (fam = 0; fam < NFONT && fontdata[fam].font != -1; fam++);
873 fs = &fontdata[fam];
874 if (fs->font != -1) { /* clear a slot if not empty */
875 clearglyphs(fam, 1000); /* dumb version - always take */
876 putc(AFORCE, tf); /* the last one to replace */
877 free(fs->glyph);
878 free(fs->cdp);
879 }
880 /* open font file */
881 sprintf(name, "%s/%s.%d", bitdir, fontname[f], pstab[s]);
882 if ((fd = fopen(name, "r")) == NULL)
883 error(FATAL, "can't open %s", name);
884 /* check for proper file mark */
2cf235a3
DS
885 for(i = 0; i < FMARK; filemark[i++] = getc(fd));
886 if (strncmp(filemark, "Rast", 4))
6dded2dd
DS
887 error(FATAL, "bad File Mark in %s.", name);
888 /* get preamble */
889 p.p_size = rd2(fd);
890 p.p_version = rd1(fd);
891 if (p.p_version)
892 error(FATAL, "wrong version of Font file: %s.", name);
893 p.p_glyph = rd3(fd);
894 p.p_first = rd2(fd);
895 p.p_last = rd2(fd);
896 /* skip rest of preamble */
897 i = p.p_glyph - 18;
898 while (i--) getc(fd);
899 fs->glyph = (glyph_dir *) /* allocate first */
900 ((char *) malloc((p.p_last - p.p_first + 1) * sizeof(glyph_dir))
901 - (char *) (p.p_first * sizeof(glyph_dir)));
0ed3cde2 902 mingp = maxgp = gp = &(fs->glyph[p.p_first]);
6dded2dd
DS
903 for (i = p.p_first; i++ <= p.p_last; gp++) {
904 gp->g_height = rd2(fd);
905 gp->g_width = rd2(fd);
906 gp->g_up = rd2(fd);
907 gp->g_left = rd2(fd);
908 gp->g_pwidth = rd4(fd);
909 if ((gp->g_bitp = rd3(fd)) > maxgp->g_bitp) /* find the glyphs */
910 maxgp = gp; /* farthest and */
911 else if(gp->g_bitp < mingp->g_bitp) /* nearest to the */
912 mingp = gp; /* start of the file */
ef0f9059 913 }
6dded2dd
DS
914 bitbase = mingp->g_bitp; /* remove file offset in bit pointers */
915 for (gp = fs->glyph, i = p.p_first; i++ <= p.p_last; gp++)
916 gp->g_bitp -= bitbase;
917
918 i = maxgp->g_bitp + maxgp->g_height * ((maxgp->g_width + 7) / 8);
919 fs->cdp = (unsigned char *) malloc(i);
920 lseek(fileno(fd), (long) bitbase, 0);
921 if (read(fileno (fd), fs->cdp, i) != i)
922 error(FATAL, "can't read in %s", name);
923 fclose(fd);
924
925 fs->size = s;
926 fs->font = f;
927 for (i = 0; i < CHARRAY; fs->chused[i++] = 0);
928 return (fam);
ef0f9059
DS
929}
930
6dded2dd 931
ef0f9059 932xychar(c)
6dded2dd 933register int c;
ef0f9059
DS
934{
935 register unsigned char *p;
6dded2dd
DS
936 register glyph_dir *par;
937 register int gsize;
ef0f9059 938
ef0f9059 939
6dded2dd
DS
940 if (c >= CHARRAY) {
941#ifdef DEBUGABLE
942 if (dbg) error(!FATAL, "character out of range: %d 0%o", c, c);
943#endif
944 return;
945 }
ef0f9059 946 if (font != lastfont || size != lastsize) {
6dded2dd 947 family = getfontdata(font, size);
ef0f9059
DS
948 lastsize = size;
949 lastfont = font;
950 }
6dded2dd
DS
951 par = &(fs->glyph[c]);
952 p = fs->cdp + par->g_bitp;
953 if (family != lastfam) {
ef0f9059 954 putc(AF, tf);
6dded2dd 955 putc(lastfam = family ,tf);
ef0f9059
DS
956 }
957
6dded2dd 958 if (fs->chused[c] == 0) { /* 1st use of this character */
ef0f9059 959 totglyph += glspace(par);
6dded2dd
DS
960 if ((fs->chused[c])++ == BMASK) fs->chused[c] = BMASK;
961 putc(ABGLY, tf);
962 putint((family << 7) | c, tf);
963 putint(lastw, tf); /* use troff's width, not */
964 putint(par->g_width, tf); /* the RST character width */
965 putint(par->g_left, tf);
966 putint(par->g_height, tf);
967 putint(par->g_up, tf);
968 gsize = ((par->g_width + 7)/8) * par->g_height;
969 while (gsize--)
ef0f9059
DS
970 putc(*p++, tf);
971 }
972
6dded2dd
DS
973 hvflush();
974 putc(c, tf); /* guaranteed to be in range */
975 lastx += lastw; /* take account of the automatic advance */
ef0f9059
DS
976}
977
ef0f9059 978
6dded2dd
DS
979/*----------------------------------------------------------------------------*
980 | Routine: hvflush ( )
981 |
982 | Results: force current position (hpos, vpos) on the imagen
983 *----------------------------------------------------------------------------*/
ef0f9059 984
6dded2dd
DS
985hvflush()
986{
987 if (vpos != lasty) {
988 putc(ASETV, tf);
989 putint(lasty = vpos, tf);
ef0f9059 990 }
6dded2dd
DS
991 if (hpos != lastx) {
992 putc(ASETH, tf);
993 putint(lastx = hpos, tf);
ef0f9059
DS
994 }
995}
996
6dded2dd
DS
997
998/*----------------------------------------------------------------------------*
999 | Routine: glspace ( glyph )
1000 |
1001 | Results: returns how much space the glyph (defined by the glyph_dir
1002 | entry) will take in the imagen's memory.
1003 *----------------------------------------------------------------------------*/
1004
ef0f9059 1005glspace(par)
6dded2dd 1006glyph_dir *par;
ef0f9059 1007{
6dded2dd
DS
1008 return 19 + ((par->g_width + 15) / 16 ) * (par->g_height);
1009}
ef0f9059 1010
ef0f9059 1011
6dded2dd
DS
1012/*----------------------------------------------------------------------------*
1013 | Routine: clearglyphs ( index, limit )
1014 |
1015 | Results: any glyphs downloaded into the imagen with a "chused" entry
1016 | less than "limit" (and > 0) are marked for deletion and their
1017 | space is "unrecorded" in totglyph.
1018 |
1019 | Bugs: clearglyphs does NOT check index to make sure the family exists
1020 *----------------------------------------------------------------------------*/
ef0f9059 1021
6dded2dd
DS
1022clearglyphs(index, limit)
1023int index;
1024int limit;
ef0f9059 1025{
6dded2dd
DS
1026 register fontset *f = &fontdata[index];
1027 register int j;
1028
1029#ifdef DEBUGABLE
1030 if (dbg) fprintf(stderr, "clear %d family of %d (%d/%d) on page %d\n",
1031 index, limit, totglyph, maxglyph, pageno);
1032#endif
1033 for (j = 0; j < CHARRAY; j++) {
1034 if (f->chused[j] && f->chused[j] < limit) {
1035 putc(ADELG, tf);
1036 putint(index<<7 | j, tf);
1037 totglyph -= glspace (&(f->glyph[j]));
1038 f->chused[j] = 0;
ef0f9059 1039 }
6dded2dd 1040 }
ef0f9059
DS
1041}
1042
ef0f9059
DS
1043
1044putint(n, f)
1045int n;
1046FILE *f;
1047{
1048 putc(n >> 8, f);
1049 putc(n & 0377, f);
1050}