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