1 /* dip.c 1.11 (Berkeley) 84/06/01 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 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 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 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 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 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 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 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 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 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*/ 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 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 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 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 688 t_charht(n) /* set character height to n */ 689 int n; 690 { 691 /* punt for now */ 692 } 693 694 695 t_slant(n) /* set slant to n */ 696 int n; 697 { 698 /* punt for now */ 699 } 700 701 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 714 t_wrapup() 715 { 716 putc(AEND, tf); 717 putc(AEOF, tf); 718 } 719 720 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 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 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 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 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 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 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 873 int rd2(fp) 874 FILE *fp; 875 { 876 register short i = rd1(fp) << 8; 877 878 return i | rd1(fp); 879 } 880 881 int rd3(fp) 882 FILE *fp; 883 { 884 register int i = rd2(fp) << 8; 885 886 return i | rd1(fp); 887 } 888 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. The font 902 | information pointer, fs, is set to point to data for "font" 903 | at point size "size". If no information for that font is 904 | available, the info is read in from the appropriate font file. 905 | The table "fontdata" holds all the fonts, and it is cleared 906 | of a random font/size if necessary. 907 *----------------------------------------------------------------------------*/ 908 909 int getfontdata(f, s) 910 int f; 911 int s; 912 { 913 char name[100]; 914 register FILE *fd; 915 register int i; 916 register int fam; 917 register int bitbase; 918 register glyph_dir *maxgp; 919 register glyph_dir *gp; 920 preamble p; 921 922 /* first check if it's here already */ 923 for (fam = 0; fam <= NFONT; fam++) 924 if (fontdata[fam].font == f && fontdata[fam].size == s) { 925 fs = &fontdata[fam]; 926 return (fam); 927 } 928 /* find an empty slot */ 929 for (fam = 0; fam < NFONT && fontdata[fam].font != -1; fam++); 930 fs = &fontdata[fam]; 931 if (fs->font != -1) { /* clear a slot if not empty */ 932 clearglyphs(fam, 1000); /* dumb version - always take */ 933 putc(AFORCE, tf); /* the last one to replace */ 934 free(fs->glyph); 935 free(fs->cdp); 936 } 937 /* open font file */ 938 sprintf(name, "%s/%s.%d", bitdir, fontname[f], pstab[s]); 939 if ((fd = fopen(name, "r")) == NULL) 940 error(FATAL, "can't open %s", name); 941 /* check for proper file mark */ 942 for(i = 0; i < FMARK; filemark[i++] = getc(fd)); 943 if (strncmp(filemark, "Rast", 4)) 944 error(FATAL, "bad File Mark in %s.", name); 945 /* get preamble */ 946 p.p_size = rd2(fd); 947 p.p_version = rd1(fd); 948 if (p.p_version) 949 error(FATAL, "wrong version of Font file: %s.", name); 950 p.p_glyph = rd3(fd); 951 fs->first = p.p_first = rd2(fd); 952 fs->last = p.p_last = rd2(fd); 953 /* skip rest of preamble */ 954 i = p.p_glyph - 18; 955 while (i--) getc(fd); 956 fs->glyph = (glyph_dir *) /* allocate first */ 957 ((char *) malloc((p.p_last - p.p_first + 1) * sizeof(glyph_dir)) 958 - (char *) (p.p_first * sizeof(glyph_dir))); 959 maxgp = gp = &(fs->glyph[p.p_first]); 960 bitbase = maxgp->g_bitp; 961 for (i = p.p_first; i++ <= p.p_last; gp++) { 962 gp->g_height = rd2(fd); 963 gp->g_width = rd2(fd); 964 gp->g_up = rd2(fd); 965 gp->g_left = rd2(fd); 966 gp->g_pwidth = rd4(fd); 967 if ((gp->g_bitp = rd3(fd)) > maxgp->g_bitp) /* find the glyphs */ 968 maxgp = gp; /* farthest from and */ 969 else if(gp->g_bitp < bitbase) /* nearest to the */ 970 bitbase = gp->g_bitp; /* start of the file */ 971 } 972 /* remove file offset in bit pointers */ 973 for (gp = fs->glyph, i = p.p_first; i++ <= p.p_last; gp++) 974 gp->g_bitp -= bitbase; 975 976 i = maxgp->g_bitp + maxgp->g_height * ((maxgp->g_width + 7) / 8); 977 fs->cdp = (unsigned char *) malloc(i); 978 lseek(fileno(fd), (long) bitbase, 0); 979 if (read(fileno (fd), fs->cdp, i) != i) 980 error(FATAL, "can't read in %s", name); 981 fclose(fd); 982 983 fs->size = s; 984 fs->font = f; 985 for (i = 0; i < CHARRAY; fs->chused[i++] = 0); 986 return (fam); 987 } 988 989 990 /*----------------------------------------------------------------------------* 991 | Routine: setfill(stipple_number) 992 | 993 | Results: sends the appropriate command to set the fill-pattern 994 | for a particular stipple. Sends the glyph if necessary, 995 | and does nothing if the pattern is the same. Takes stipple 996 | font from current "stip" number. 997 *----------------------------------------------------------------------------*/ 998 999 setfill(number) 1000 register int number; 1001 { 1002 register int fam; 1003 register int gsize; 1004 register glyph_dir *par; 1005 register unsigned char *p; 1006 register fontset *savefs; 1007 1008 if (stip == laststip && number == laststipmem) 1009 return; 1010 1011 savefs = fs; /* getfontdata sets fs, so we have to */ 1012 /* save it before calling getfontdata */ 1013 fam = getfontdata(nfonts + stip, nsizes); 1014 laststip = stip; 1015 laststipmem = number; /* must be set before call to polygon */ 1016 1017 if (!number || number < fs->first || number > fs->last) { 1018 nostipbits: 1019 fs = savefs; /* forget it if it's out of range */ 1020 laststipmem = 0; /* force NO stipple */ 1021 return; 1022 } 1023 if (fs->chused[number] == 0) { /* stipple not down-loaded */ 1024 par = &(fs->glyph[number]); 1025 if (!par->g_bitp) 1026 goto nostipbits; 1027 totglyph += glspace(par); 1028 putc(ABGLY, tf); 1029 putint((fam << 7) | number, tf); 1030 putint(par->g_pwidth, tf); 1031 putint(par->g_width, tf); 1032 putint(par->g_left, tf); 1033 putint(par->g_height, tf); 1034 putint(par->g_up, tf); 1035 gsize = ((par->g_width + 7)/8) * par->g_height; 1036 p = fs->cdp + par->g_bitp; 1037 while (gsize--) 1038 putc(*p++, tf); 1039 } 1040 /* mark that it's been used */ 1041 if (fs->chused[number] != BMASK) 1042 fs->chused[number]++; 1043 putc(ASTEXTURE, tf); /* set the texture */ 1044 putint((fam << 7) | number, tf); 1045 fs = savefs; /* return fs to proper spot */ 1046 } 1047 1048 1049 xychar(c) 1050 register int c; 1051 { 1052 register unsigned char *p; 1053 register glyph_dir *par; 1054 register int gsize; 1055 1056 1057 if (c >= CHARRAY) { 1058 #ifdef DEBUGABLE 1059 if (dbg) error(!FATAL, "character out of range: %d 0%o", c, c); 1060 #endif 1061 return; 1062 } 1063 if (font != lastfont || size != lastsize) { 1064 family = getfontdata(font, size); 1065 lastsize = size; 1066 lastfont = font; 1067 } 1068 par = &(fs->glyph[c]); 1069 p = fs->cdp + par->g_bitp; 1070 if (family != lastfam) { 1071 putc(AF, tf); 1072 putc(lastfam = family ,tf); 1073 } 1074 1075 if (fs->chused[c] == 0) { /* 1st use of this character */ 1076 totglyph += glspace(par); 1077 putc(ABGLY, tf); 1078 putint((family << 7) | c, tf); 1079 putint(lastw, tf); /* use troff's width, not */ 1080 putint(par->g_width, tf); /* the RST character width */ 1081 putint(par->g_left, tf); 1082 putint(par->g_height, tf); 1083 putint(par->g_up, tf); 1084 gsize = ((par->g_width + 7)/8) * par->g_height; 1085 while (gsize--) 1086 putc(*p++, tf); 1087 } 1088 /* note that character's been used */ 1089 if (fs->chused[c] != BMASK) 1090 fs->chused[c]++; 1091 hvflush(); 1092 putc(c, tf); /* guaranteed to be in range */ 1093 lastx += lastw; /* take account of the automatic advance */ 1094 } 1095 1096 1097 /*----------------------------------------------------------------------------* 1098 | Routine: hvflush ( ) 1099 | 1100 | Results: force current position (hpos, vpos) on the imagen 1101 *----------------------------------------------------------------------------*/ 1102 1103 hvflush() 1104 { 1105 if (vpos != lasty) { 1106 putc(ASETV, tf); 1107 putint(lasty = vpos, tf); 1108 } 1109 if (hpos != lastx) { 1110 putc(ASETH, tf); 1111 putint(lastx = hpos, tf); 1112 } 1113 } 1114 1115 1116 /*----------------------------------------------------------------------------* 1117 | Routine: glspace ( glyph ) 1118 | 1119 | Results: returns how much space the glyph (defined by the glyph_dir 1120 | entry) will take in the imagen's memory. 1121 *----------------------------------------------------------------------------*/ 1122 1123 glspace(par) 1124 glyph_dir *par; 1125 { 1126 return 19 + ((par->g_width + 15) / 16 ) * (par->g_height); 1127 } 1128 1129 1130 /*----------------------------------------------------------------------------* 1131 | Routine: clearglyphs ( index, limit ) 1132 | 1133 | Results: any glyphs downloaded into the imagen with a "chused" entry 1134 | less than "limit" (and > 0) are marked for deletion and their 1135 | space is "unrecorded" in totglyph. 1136 | 1137 | Bugs: clearglyphs does NOT check index to make sure the family exists 1138 *----------------------------------------------------------------------------*/ 1139 1140 clearglyphs(index, limit) 1141 int index; 1142 int limit; 1143 { 1144 register fontset *f = &fontdata[index]; 1145 register int j; 1146 1147 #ifdef DEBUGABLE 1148 if (dbg) fprintf(stderr, "clear %d family of %d (%d/%d) on page %d\n", 1149 index, limit, totglyph, maxglyph, pageno); 1150 #endif 1151 for (j = 0; j < CHARRAY; j++) { 1152 if (f->chused[j] && f->chused[j] < limit) { 1153 putc(ADELG, tf); 1154 putint(index<<7 | j, tf); 1155 totglyph -= glspace (&(f->glyph[j])); 1156 f->chused[j] = 0; 1157 } 1158 } 1159 } 1160 1161 1162 putint(n, f) 1163 int n; 1164 FILE *f; 1165 { 1166 putc(n >> 8, f); 1167 putc(n & 0377, f); 1168 } 1169