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