Commit | Line | Data |
---|---|---|
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 | /* | |
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 | cx ascii character x | |
13 | Cxyz funny char xyz. terminated by white space | |
14 | Hn go to absolute horizontal position n | |
15 | Vn go to absolute vertical position n (down is positive) | |
16 | hn go n units horizontally (relative) | |
17 | vn ditto vertically | |
18 | nnc 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) | |
21 | Dt ...\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 ... | |
27 | nb a end of line (information only -- no action needed) | |
28 | b = space before line, a = after | |
6dded2dd | 29 | pn new page begins -- set v to 0 |
ef0f9059 DS |
30 | #...\n comment |
31 | x ...\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 | ||
83 | int MAXX = (RES*8+RES/3); /* size of the page... (not 8-1/2" x 11", */ | |
84 | int MAXY = (RES*10+RES/2+RES/4); /* but 8-1/3" x 10-3/4") */ | |
85 | ||
86 | int output = 0; /* do we do output at all? */ | |
87 | int pageno = -1; /* output page number */ | |
88 | int nolist = 0; /* output page list if > 0 */ | |
89 | int olist[20]; /* pairs of page numbers */ | |
ef0f9059 DS |
90 | |
91 | struct dev dev; | |
92 | struct font *fontbase[NFONT+1]; | |
6dded2dd DS |
93 | short * pstab; |
94 | int nsizes = 1; | |
ef0f9059 | 95 | int nfonts; |
ef0f9059 | 96 | int nchtab; |
6dded2dd DS |
97 | char * chname; |
98 | short * chtab; | |
99 | unsigned char * fitab[NFONT+1]; /* legal characters for each font */ | |
100 | unsigned char * widtab[NFONT+1]; /* width table for each font */ | |
101 | unsigned char * codetab[NFONT+1]; /* device code translation */ | |
102 | char * fontname[NFONT+1]; /* what font is on what position? */ | |
103 | ||
104 | #ifdef DEBUGABLE | |
ef0f9059 | 105 | int dbg = 0; |
6dded2dd DS |
106 | #endif |
107 | ||
108 | FILE * tf = stdout; /* output file pointer */ | |
109 | char * fontdir = FONTDIR; | |
110 | char * bitdir = BITDIR; | |
111 | FILE * fp = stdin; /* input file pointer */ | |
112 | ||
113 | int totglyph= 0; /* total space used by glyphs sent down */ | |
114 | int maxglyph= MEMSIZE - BUFFER; /* maximum space for glyphs */ | |
115 | ||
116 | int size = 1; | |
117 | int font = 1; | |
118 | int family; | |
119 | int hpos; /* current horizontal position (left = 0) */ | |
120 | int vpos; /* current vertical position (down positive) */ | |
121 | int lastw = 0; /* width of last input character */ | |
122 | extern int linethickness; /* line drawing pars: Thickness (pixels) */ | |
123 | extern int style; /* and type (SOLID, DOTTED, . . . ) */ | |
124 | ||
125 | typedef 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 | ||
133 | fontset *fs; /* A global pointer to the current family */ | |
134 | fontset fontdata[NFONT+1]; /* table of family data descripters */ | |
135 | ||
136 | int lastsize = -1; | |
137 | int lastfont = -1; | |
138 | int lastx = -1; | |
139 | int lasty = -1; | |
140 | int lastfam = -1; | |
141 | ||
142 | ||
ef0f9059 DS |
143 | |
144 | main(argc, argv) | |
145 | char *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 | ||
210 | char *operand(argcp, argvp) | |
211 | int * argcp; | |
212 | char ***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 | 222 | outlist(s) /* process list of page numbers to be printed */ |
0b2b2a0e | 223 | register 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 |
261 | in_olist(n) /* is n in olist? */ |
262 | int 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 |
275 | conv(fp) |
276 | register 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 |
403 | int devcntrl(fp) /* interpret device control functions */ |
404 | FILE *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 |
449 | fileinit() /* 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 |
497 | fontprint(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 | |
527 | loadfont(n, s, s1) /* load font info for font s on position n (0...) */ | |
528 | int n; | |
529 | char *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*/ |
566 | error(f, s, a1, a2, a3, a4, a5, a6, a7) | |
567 | int f; | |
568 | char *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 |
578 | t_init(reinit) /* initialize device */ |
579 | int 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 | |
598 | t_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 | |
626 | t_size(n) /* convert integer to internal size number*/ | |
627 | int 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 |
641 | t_charht(n) /* set character height to n */ |
642 | int n; | |
643 | { | |
644 | /* punt for now */ | |
645 | } | |
646 | ||
6dded2dd | 647 | |
ef0f9059 DS |
648 | t_slant(n) /* set slant to n */ |
649 | int n; | |
650 | { | |
651 | /* punt for now */ | |
652 | } | |
653 | ||
6dded2dd | 654 | |
ef0f9059 DS |
655 | t_font(s) /* convert string to internal font number */ |
656 | char *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 | |
667 | t_wrapup() | |
668 | { | |
669 | putc(AEND, tf); | |
670 | putc(AEOF, tf); | |
671 | } | |
672 | ||
ef0f9059 | 673 | |
ef0f9059 | 674 | put1s(s) /* s is a funny char name */ |
6dded2dd | 675 | register 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 | 695 | put1(c) /* output char c */ |
6dded2dd | 696 | register 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 |
751 | setsize(n) /* set point size to n (internal) */ |
752 | int 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 | 769 | t_fp(n, s, si) |
ef0f9059 DS |
770 | int n; |
771 | char *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 |
788 | setfont(n) /* set font to n */ |
789 | int 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 |
806 | int rd1(fp) |
807 | FILE *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 |
815 | int rd2(fp) |
816 | FILE *fp; | |
817 | { | |
818 | register short i = rd1(fp) << 8; | |
ef0f9059 | 819 | |
6dded2dd DS |
820 | return i | rd1(fp); |
821 | } | |
ef0f9059 | 822 | |
6dded2dd DS |
823 | int rd3(fp) |
824 | FILE *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 |
831 | int rd4(fp) |
832 | FILE *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 | ||
851 | int getfontdata(f, s) | |
852 | int f; | |
853 | int 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 | 932 | xychar(c) |
6dded2dd | 933 | register 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 |
985 | hvflush() |
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 | 1005 | glspace(par) |
6dded2dd | 1006 | glyph_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 |
1022 | clearglyphs(index, limit) |
1023 | int index; | |
1024 | int 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 | |
1044 | putint(n, f) | |
1045 | int n; | |
1046 | FILE *f; | |
1047 | { | |
1048 | putc(n >> 8, f); | |
1049 | putc(n & 0377, f); | |
1050 | } |