1 /* dvar.c 1.15 85/08/05 2 * 3 * Varian driver for the new troff 4 * 5 * Authors: BWK(BELL) 6 * VCAT(berkley) 7 * Richard L. Hyde, Perdue University 8 * and David Slattengren, U.C. Berkeley 9 */ 10 11 12 /******************************************************************************* 13 14 output language from troff: 15 all numbers are character strings 16 17 #..\n comment 18 sn size in points 19 fn font as number from 1 to n 20 in stipple `font' as number from 1 to n 21 cx ascii character x 22 Cxyz funny char \(xyz. terminated by white space 23 Hn go to absolute horizontal position n 24 Vn go to absolute vertical position n (down is positive) 25 hn go n units horizontally (relative) 26 vn ditto vertically 27 nnc move right nn, then print c (exactly 2 digits!) 28 (this wart is an optimization that shrinks output file size 29 about 35% and run-time about 15% while preserving ascii-ness) 30 p new page begins -- set v to 0 31 nb a end of line (information only -- no action needed) 32 b = space before line, a = after 33 w paddable word space -- no action needed 34 35 Dt ..\n draw operation 't': 36 Dt d set line thickness to d 37 Ds d set line style (mask) to d 38 Dl x y line from here by x,y 39 Dc d circle of diameter d with left side here 40 De x y ellipse of axes x,y with left side here 41 Da x y r arc counter-clockwise by x,y of radius r 42 D~ x y x y ... B-spline curve by x,y then x,y ... 43 Dg x y x y ... gremlin spline curve by x,y then x,y ... 44 Dp s x y ... polygon by x,y then ... filled with stipple s 45 46 x ..\n device control functions: 47 x i init 48 x T s name of device is s 49 x r n h v resolution is n/inch h = min horizontal motion, v = min vert 50 x p pause (can restart) 51 x s stop -- done for ever 52 x t generate trailer 53 x f n s font position n contains font s 54 x H n set character height to n 55 x S n set slant to N 56 57 Subcommands like "i" are often spelled out like "init". 58 59 *******************************************************************************/ 60 61 62 #include <stdio.h> 63 #include <ctype.h> 64 #include <sys/vcmd.h> 65 #include "dev.h" 66 67 68 /* #define DEBUGABLE /* No, not debugable... */ 69 #define DRIVER /* Yes, we're driving directly */ 70 /* #define FULLPAGE /* No, don't output full pages */ 71 #define NFONTS 65 /* total number of fonts useable */ 72 #define MAXSTATE 6 /* number of environments rememberable */ 73 #define OPENREAD 0 /* mode for openning files */ 74 #define RESTART 1 /* upon exit, return either RESTART */ 75 #define ABORT 2 /* or ABORT */ 76 #define FATAL 1 /* type of error */ 77 #define BMASK 0377 /* byte grabber */ 78 #ifndef FONTDIR 79 #define FONTDIR "/usr/lib/font" /* default place to find font descriptions */ 80 #endif 81 #ifndef BITDIR 82 #define BITDIR "/usr/lib/vfont" /* default place to look for font rasters */ 83 #endif 84 #define MAXWRIT 4096 /* max characters allowed to write at once */ 85 86 #define hmot(n) hgoto(hpos + n) 87 #define vmot(n) vgoto(vpos + n) 88 89 90 char SccsId[]= "dvar.c 1.15 85/08/05"; 91 92 int output = 0; /* do we do output at all? */ 93 int nolist = 0; /* output page list if > 0 */ 94 int olist[20]; /* pairs of page numbers */ 95 int spage = 9999; /* stop every spage pages */ 96 int scount = 0; 97 struct dev dev; 98 struct font *fontbase[NFONTS+1]; 99 short * pstab; /* point size table pointer */ 100 int nsizes; /* number of sizes device is capable of printing */ 101 int nfonts; /* number of fonts device is capable of printing */ 102 int nstips; /* number of stipple fonts device can print */ 103 int nchtab; 104 char * chname; 105 short * chtab; 106 char * fitab[NFONTS+1]; /* font inclusion table - maps ascii to ch # */ 107 char * widtab[NFONTS+1]; /* width table for each font */ 108 char * codetab[NFONTS+1]; /* device codes */ 109 char * fontdir = FONTDIR; /* place to find devxxx directories */ 110 char * bitdir = BITDIR; /* place to find raster fonts and fontmap */ 111 char * fontname[NFONTS+1]; /* table of what font is on what position */ 112 struct { /* table of what font */ 113 char fname[3]; /* name maps to what */ 114 char *ffile; /* filename in bitdirectory */ 115 } fontmap[NFONTS+1]; 116 117 118 #ifdef DEBUGABLE 119 int dbg = 0; 120 #endif 121 int size = -1; /* current point size (internal pstable index) */ 122 int font = -1; /* current font - not using any to start with */ 123 int stip = -1; /* current stipple font - not using any to start with */ 124 int stipmem = 0; /* current member to use from stipple font */ 125 int hpos; /* horizontal position we are to be at next; left = 0 */ 126 int vpos; /* current vertical position (down positive) */ 127 extern linethickness; /* thickness (in pixels) of any drawn object */ 128 extern linmod; /* line style (a bit mask - dotted, etc.) of objects */ 129 int lastw; /* width of last character printed */ 130 131 132 #define DISPATCHSIZE 256 /* must be a power of two */ 133 #define CHARMASK (DISPATCHSIZE-1) 134 #define DSIZ ((sizeof *dispatch)*DISPATCHSIZE) 135 #define OUTFILE fileno (stdout) 136 #define RES 200 /* resolution of the device (dots/in) */ 137 138 #define RASTER_LENGTH 2112 /* device line length */ 139 #define BYTES_PER_LINE (RASTER_LENGTH/8) 140 #ifndef FULLPAGE 141 # define NLINES 1600 /* page width, 8 inches */ 142 #endif 143 #ifdef FULLPAGE 144 # define NLINES 1700 /* page width, 8.5 inches */ 145 #endif 146 #define BUFFER_SIZE (NLINES*BYTES_PER_LINE) /* number of chars in picture */ 147 148 149 int pltmode[] = { VPLOT }; 150 int prtmode[] = { VPRINT }; 151 char buffer1[BUFFER_SIZE]; /* Big line buffers */ 152 char buffer2[BUFFER_SIZE]; 153 char * fill = &buffer1[0]; /* Zero origin in filling buffer */ 154 char * empty = &buffer2[0]; /* Zero origin in emptying buffer */ 155 char * elevel = &buffer2[0]; /* current position in emptying buffer */ 156 int emptypos = NLINES; /* amount of emptying done (initially "done") */ 157 158 159 char * calloc(); 160 char * nalloc(); 161 char * allpanic(); 162 char * operand(); 163 164 struct header { 165 short magic; 166 unsigned short size; 167 short maxx; 168 short maxy; 169 short xtnd; 170 } header; 171 172 struct dispatch{ 173 unsigned short addr; 174 short nbytes; 175 char up; 176 char down; 177 char left; 178 char right; 179 short width; 180 }; 181 182 struct fontdes { 183 int fnum; /* if == -1, then this position is empty */ 184 int psize; 185 struct dispatch *disp; 186 char *bits; 187 } fontdes[NFONTS+1]; /* initialized at program start */ 188 189 struct dispatch *dispatch; 190 struct dispatch *stip_disp; 191 int cfnum = -1; 192 int cpsize = 10; 193 int cfont = 1; 194 char *bits; 195 char *stip_bits; 196 int bordered = 1; /* flag: "do polygons get bordered?" */ 197 int fontwanted = 1; /* flag: "has a new font been requested?" */ 198 int nfontnum = -1; 199 int npsize = 10; 200 201 202 203 main(argc, argv) 204 char *argv[]; 205 { 206 register FILE *fp; 207 register int i; 208 209 for (i = 0; i <= NFONTS; fontdes[i++].fnum = -1); 210 while (--argc > 0 && **++argv == '-') { 211 switch ((*argv)[1]) { 212 case 'F': 213 bitdir = operand(&argc, &argv); 214 break; 215 case 'f': 216 fontdir = operand(&argc, &argv); 217 break; 218 case 'o': 219 outlist(operand(&argc, &argv)); 220 break; 221 #ifdef DEBUGABLE 222 case 'd': 223 dbg = atoi(operand(&argc, &argv)); 224 if (dbg == 0) dbg = 1; 225 break; 226 #endif 227 case 's': 228 spage = atoi(operand(&argc, &argv)); 229 if (spage <= 0) 230 spage = 9999; 231 break; 232 } 233 } 234 235 #ifdef DRIVER 236 ioctl(OUTFILE, VSETSTATE, pltmode); 237 #endif 238 239 if (argc < 1) 240 conv(stdin); 241 else 242 while (argc--) { 243 if (strcmp(*argv, "-") == 0) 244 fp = stdin; 245 else if ((fp = fopen(*argv, "r")) == NULL) 246 error(FATAL, "can't open %s", *argv); 247 conv(fp); 248 fclose(fp); 249 argv++; 250 } 251 exit(0); 252 } 253 254 255 /*----------------------------------------------------------------------------* 256 | Routine: char * operand (& argc, & argv) 257 | 258 | Results: returns address of the operand given with a command-line 259 | option. It uses either "-Xoperand" or "-X operand", whichever 260 | is present. The program is terminated if no option is present. 261 | 262 | Side Efct: argc and argv are updated as necessary. 263 *----------------------------------------------------------------------------*/ 264 265 char *operand(argcp, argvp) 266 int * argcp; 267 char ***argvp; 268 { 269 if ((**argvp)[2]) return(**argvp + 2); /* operand immediately follows */ 270 if ((--*argcp) <= 0) /* no operand */ 271 error (FATAL, "command-line option operand missing.\n"); 272 return(*(++(*argvp))); /* operand next word */ 273 } 274 275 276 outlist(s) /* process list of page numbers to be printed */ 277 char *s; 278 { 279 int n1, n2, i; 280 281 nolist = 0; 282 while (*s) { 283 n1 = 0; 284 if (isdigit(*s)) 285 do 286 n1 = 10 * n1 + *s++ - '0'; 287 while (isdigit(*s)); 288 else 289 n1 = -9999; 290 n2 = n1; 291 if (*s == '-') { 292 s++; 293 n2 = 0; 294 if (isdigit(*s)) 295 do 296 n2 = 10 * n2 + *s++ - '0'; 297 while (isdigit(*s)); 298 else 299 n2 = 9999; 300 } 301 olist[nolist++] = n1; 302 olist[nolist++] = n2; 303 if (*s != '\0') 304 s++; 305 } 306 olist[nolist] = 0; 307 #ifdef DEBUGABLE 308 if (dbg) 309 for (i=0; i<nolist; i += 2) 310 fprintf(stderr,"%3d %3d\n", olist[i], olist[i+1]); 311 #endif 312 } 313 314 conv(fp) 315 register FILE *fp; 316 { 317 register int c, k; 318 int m, n, n1, m1; 319 char str[100], buf[300]; 320 321 while ((c = getc(fp)) != EOF) { 322 switch (c) { 323 case '\n': /* when input is text */ 324 case ' ': 325 case 0: /* occasional noise creeps in */ 326 break; 327 case '{': /* push down current environment */ 328 t_push(); 329 break; 330 case '}': 331 t_pop(); 332 break; 333 case '0': case '1': case '2': case '3': case '4': 334 case '5': case '6': case '7': case '8': case '9': 335 /* two motion digits plus a character */ 336 hmot((c-'0')*10 + getc(fp)-'0'); 337 put1(getc(fp)); 338 break; 339 case 'c': /* single ascii character */ 340 put1(getc(fp)); 341 break; 342 case 'C': 343 fscanf(fp, "%s", str); 344 put1s(str); 345 break; 346 case 't': /* straight text */ 347 fgets(buf, sizeof(buf), fp); 348 t_text(buf); 349 break; 350 case 'D': /* draw function */ 351 if (fgets(buf, sizeof(buf), fp) == NULL) 352 error(FATAL, "unexpected end of input");; 353 switch (buf[0]) { 354 case 'l': /* draw a line */ 355 sscanf(buf+1, "%d %d", &n, &m); 356 drawline(n, m); 357 break; 358 case 'c': /* circle */ 359 sscanf(buf+1, "%d", &n); 360 drawcirc(n); 361 break; 362 case 'e': /* ellipse */ 363 sscanf(buf+1, "%d %d", &m, &n); 364 drawellip(m, n); 365 break; 366 case 'a': /* arc */ 367 sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1); 368 drawarc(n, m, n1, m1); 369 break; 370 case 'P': /* unbordered polygon */ 371 bordered = 0; /* unset border flag */ 372 case 'p': /* polygon */ 373 sscanf(buf+1, "%d", &m); /* get stipple */ 374 n = 1; /* number first */ 375 while (buf[++n] == ' '); 376 while (isdigit(buf[++n])); 377 setfill(m); /* set up stipple */ 378 drawwig(buf+n, fp, -1); /* draw polygon */ 379 bordered = 1; /* ALWAYS set after */ 380 break; 381 case '~': /* wiggly line */ 382 drawwig(buf+1, fp, 1); 383 break; 384 case 'g': /* gremlin spline */ 385 drawwig(buf+1, fp, 0); 386 break; 387 case 't': /* line thickness */ 388 sscanf(buf+1, "%d", &n); 389 drawthick(n); 390 break; 391 case 's': /* line style */ 392 sscanf(buf+1, "%d", &n); 393 drawstyle(n); 394 break; 395 default: 396 error(FATAL, "unknown drawing function %s", buf); 397 break; 398 } 399 break; 400 case 's': 401 fscanf(fp, "%d", &n); /* ignore fractional sizes */ 402 setsize(t_size(n)); 403 break; 404 case 'f': 405 fscanf(fp, "%s", str); 406 setfont(t_font(str)); 407 break; 408 case 'i': 409 fscanf(fp, "%d", &n); 410 setstip(n); 411 break; 412 case 'H': /* absolute horizontal motion */ 413 /* fscanf(fp, "%d", &n); */ 414 while ((c = getc(fp)) == ' ') 415 ; 416 k = 0; 417 do { 418 k = 10 * k + c - '0'; 419 } while (isdigit(c = getc(fp))); 420 ungetc(c, fp); 421 hgoto(k); 422 break; 423 case 'h': /* relative horizontal motion */ 424 while ((c = getc(fp)) == ' ') 425 ; 426 k = 0; 427 do { 428 k = 10 * k + c - '0'; 429 } while (isdigit(c = getc(fp))); 430 ungetc(c, fp); 431 hmot(k); 432 break; 433 case 'w': /* word space */ 434 break; 435 case 'V': 436 fscanf(fp, "%d", &n); 437 vgoto(n); 438 break; 439 case 'v': 440 fscanf(fp, "%d", &n); 441 vmot(n); 442 break; 443 case 'p': /* new page */ 444 fscanf(fp, "%d", &n); 445 t_page(n); 446 break; 447 case 'n': /* end of line */ 448 t_newline(); 449 450 case '#': /* comment */ 451 do 452 c = getc(fp); 453 while (c != '\n' && c != EOF); 454 break; 455 case 'x': /* device control */ 456 if (devcntrl(fp)) return; 457 break; 458 default: 459 error(FATAL, "unknown input character %o %c", c, c); 460 } 461 if (emptypos < NLINES) { /* for each input operation */ 462 slop_lines(1); /* put out an output line */ 463 #ifdef DRIVER 464 if (emptypos == NLINES) { 465 ioctl(OUTFILE, VSETSTATE, prtmode); 466 if (write(OUTFILE, "\f", 2) != 2) 467 exit(RESTART); 468 ioctl(OUTFILE, VSETSTATE, pltmode); 469 } 470 #endif 471 } 472 } 473 } 474 475 int devcntrl(fp) /* interpret device control functions */ 476 FILE *fp; /* returns -1 upon "stop" command */ 477 { 478 char str[20], str1[50], buf[50]; 479 int c, n; 480 481 fscanf(fp, "%s", str); 482 switch (str[0]) { /* crude for now */ 483 case 'i': /* initialize */ 484 fileinit(); 485 t_init(); 486 break; 487 case 't': /* trailer */ 488 break; 489 case 'p': /* pause -- can restart */ 490 t_reset('p'); 491 break; 492 case 's': /* stop */ 493 t_reset('s'); 494 return -1; 495 case 'r': /* resolution assumed when prepared */ 496 fscanf(fp, "%d", &n); 497 if (n!=RES) error(FATAL,"Input computed for wrong printer"); 498 break; 499 case 'f': /* font used */ 500 fscanf(fp, "%d %s", &n, str); 501 fgets(buf, sizeof buf, fp); /* in case there's a filename */ 502 ungetc('\n', fp); /* fgets goes too far */ 503 str1[0] = 0; /* in case nothing comes in */ 504 sscanf(buf, "%s", str1); 505 loadfont(n, str, str1); 506 break; 507 /* these don't belong here... */ 508 case 'H': /* char height */ 509 fscanf(fp, "%d", &n); 510 t_charht(n); 511 break; 512 case 'S': /* slant */ 513 fscanf(fp, "%d", &n); 514 t_slant(n); 515 break; 516 } 517 while ((c = getc(fp)) != '\n') /* skip rest of input line */ 518 if (c == EOF) 519 return -1; 520 return 0; 521 } 522 523 /* fileinit: read in font and code files, etc. 524 Must open table for device, read in resolution, 525 size info, font info, etc. and set params. 526 Also read in font name mapping. 527 */ 528 529 fileinit() 530 { 531 register int i; 532 register int fin; 533 register int nw; 534 register char *filebase; 535 register char *p; 536 register FILE *fp; 537 char temp[100]; 538 539 /* first, read in font map file. The file must be of Format: 540 XX FILENAME (XX = troff font name) 541 with one entry per text line of the file. 542 Extra stuff after FILENAME is ignored */ 543 544 sprintf(temp, "%s/fontmap", bitdir); 545 if ((fp = fopen(temp, "r")) == NULL) 546 error(FATAL, "Can't open %s", temp); 547 for (i = 0; i <= NFONTS && fgets(temp, 100, fp) != NULL; i++) { 548 sscanf(temp, "%2s", fontmap[i].fname); 549 p = &temp[0]; 550 while (*p != ' ' && *p != ' ') p++; 551 while (*p == ' ' || *p == ' ') p++; 552 filebase = p; 553 for (nw = 1; *p != '\n' && *p != ' ' && *p != '\t'; p++) nw++; 554 fontmap[i].ffile = nalloc(1, nw); 555 sscanf(filebase, "%s", fontmap[i].ffile); 556 } 557 fontmap[++i].fname[0] = '0'; /* finish off with zeros */ 558 fontmap[i].ffile = (char *) 0; 559 fclose(fp); 560 #ifdef DEBUGABLE 561 if(dbg) { 562 fprintf(stderr, "font map:\n"); 563 for (i = 0; fontmap[i].ffile; i++) 564 fprintf(stderr,"%s = %s\n", fontmap[i].fname, fontmap[i].ffile); 565 } 566 #endif 567 568 sprintf(temp, "%s/devva/DESC.out", fontdir); 569 if ((fin = open(temp, 0)) < 0) 570 error(FATAL, "can't open tables for %s", temp); 571 read(fin, &dev, sizeof(struct dev)); 572 nfonts = dev.nfonts; 573 nstips = dev.nstips; 574 nsizes = dev.nsizes; 575 nchtab = dev.nchtab; 576 filebase = calloc(1, dev.filesize); /* enough room for whole file */ 577 read(fin, filebase, dev.filesize); /* all at once */ 578 pstab = (short *) filebase; 579 chtab = pstab + nsizes + 1; 580 chname = (char *) (chtab + dev.nchtab); 581 p = chname + dev.lchname; 582 for (i = 1; i <= nfonts; i++) { 583 fontbase[i] = (struct font *) p; 584 nw = *p & BMASK; /* 1st thing is width count */ 585 p += sizeof(struct font); 586 widtab[i] = p; 587 codetab[i] = p + 2 * nw; 588 fitab[i] = p + 3 * nw; 589 p += 3 * nw + dev.nchtab + 128 - 32; 590 t_fp(i, fontbase[i]->namefont, fontbase[i]->intname); 591 #ifdef DEBUGABLE 592 if (dbg > 1) fontprint(i); 593 #endif 594 } 595 for (i = 1; i <= nstips; i++) { /* add in stipple "filenames" */ 596 if (nfonts + i <= NFONTS) 597 t_fp(nfonts + i, p, (char *)0); 598 p += strlen(p) + 1; 599 } 600 fontbase[0] = (struct font *) 601 calloc(1,3*255 + dev.nchtab + (128-32) + sizeof (struct font)); 602 widtab[0] = (char *) fontbase[0] + sizeof (struct font); 603 fontbase[0]->nwfont = 255; 604 close(fin); 605 606 } 607 608 609 #ifdef DEBUGABLE 610 fontprint(i) /* debugging print of font i (0,...) */ 611 { 612 int j, n; 613 char *p; 614 615 fprintf(stderr,"font %d:\n", i); 616 p = (char *) fontbase[i]; 617 n = fontbase[i]->nwfont & BMASK; 618 fprintf(stderr, 619 "base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",p, 620 n,fontbase[i]->specfont,fontbase[i]->namefont,widtab[i],fitab[i]); 621 fprintf(stderr,"widths:\n"); 622 for (j=0; j <= n; j++) { 623 fprintf(stderr," %2d", widtab[i][j] & BMASK); 624 if (j % 20 == 19) fprintf(stderr,"\n"); 625 } 626 fprintf(stderr,"\ncodetab:\n"); 627 for (j=0; j <= n; j++) { 628 fprintf(stderr," %2d", codetab[i][j] & BMASK); 629 if (j % 20 == 19) fprintf(stderr,"\n"); 630 } 631 fprintf(stderr,"\nfitab:\n"); 632 for (j=0; j <= dev.nchtab + 128-32; j++) { 633 fprintf(stderr," %2d", fitab[i][j] & BMASK); 634 if (j % 20 == 19) fprintf(stderr,"\n"); 635 } 636 fprintf(stderr,"\n"); 637 } 638 #endif 639 640 641 loadfont(n, s, s1) /* load font info for font s on position n (0...) */ 642 int n; 643 char *s, *s1; 644 { 645 char temp[60]; 646 register int fin; 647 register int nw; 648 register int norig; 649 650 if (n < 0 || n > NFONTS) 651 error(FATAL, "illegal fp command %d %s", n, s); 652 if (strcmp(s, fontbase[n]->namefont) == 0) 653 return; 654 655 for (fin = 1; fin <= NFONTS; fin++) /* first check to see if the */ 656 if (strcmp(s, fontbase[fin]->namefont) == 0) { /* font is loaded */ 657 register char *c; /* somewhere else */ 658 659 #define ptrswap(x, y) { c = (char*) (x); x = y; y = c; } 660 #define ptrfswap(x, y) { c = (char*) (x); x = y; y = (struct font *) c; } 661 662 ptrfswap(fontbase[n], fontbase[fin]); 663 ptrswap(codetab[n], codetab[fin]); 664 ptrswap(widtab[n], widtab[fin]); 665 ptrswap(fitab[n], fitab[fin]); 666 t_fp(n, fontbase[n]->namefont, fontbase[n]->intname); 667 t_fp(fin, fontbase[fin]->namefont, fontbase[fin]->intname); 668 return; 669 } 670 671 if (s1 == NULL || s1[0] == '\0') 672 sprintf(temp, "%s/devva/%s.out", fontdir, s); 673 else 674 sprintf(temp, "%s/%s.out", s1, s); 675 if ((fin = open(temp, 0)) < 0) 676 error(FATAL, "can't open font table %s", temp); 677 norig = fontbase[n]->nwfont & BMASK; 678 read(fin, fontbase[n], 3*norig + nchtab+128-32 + sizeof(struct font)); 679 if ((fontbase[n]->nwfont & BMASK) > norig) 680 error(FATAL, "Font %s too big for position %d", s, n); 681 close(fin); 682 nw = fontbase[n]->nwfont & BMASK; 683 widtab[n] = (char *) fontbase[n] + sizeof(struct font); 684 codetab[n] = (char *) widtab[n] + 2 * nw; 685 fitab[n] = (char *) widtab[n] + 3 * nw; 686 t_fp(n, fontbase[n]->namefont, fontbase[n]->intname); 687 fontbase[n]->nwfont = norig; /* to later use full original size */ 688 #ifdef DEBUGABLE 689 if (dbg > 1) fontprint(n); 690 #endif 691 } 692 693 694 /*VARARGS1*/ 695 error(f, s, a1, a2, a3, a4, a5, a6, a7) { 696 fprintf(stderr, "dvar: "); 697 fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7); 698 fprintf(stderr, "\n"); 699 if (f) exit(ABORT); 700 } 701 702 703 t_init() /* initialize device */ 704 { 705 int i; 706 707 hpos = vpos = 0; 708 709 setsize(t_size(10)); /* start somewhere */ 710 setfont(1); 711 } 712 713 714 struct state { 715 int ssize; 716 int sfont; 717 int shpos; 718 int svpos; 719 int sstyle; 720 int sthick; 721 }; 722 struct state state[MAXSTATE]; 723 struct state *statep = state; 724 725 t_push() /* begin a new block */ 726 { 727 statep->ssize = size; 728 statep->sfont = font; 729 statep->sstyle = linmod; 730 statep->sthick = linethickness; 731 statep->shpos = hpos; 732 statep->svpos = vpos; 733 if (statep++ >= state+MAXSTATE) 734 error(FATAL, "{ nested too deep"); 735 } 736 737 t_pop() /* pop to previous state */ 738 { 739 if (--statep < state) 740 error(FATAL, "extra }"); 741 size = statep->ssize; 742 font = statep->sfont; 743 hpos = statep->shpos; 744 vpos = statep->svpos; 745 linmod = statep->sstyle; 746 linethickness = statep->sthick; 747 } 748 749 t_page(n) /* do whatever new page functions */ 750 { 751 int i; 752 753 754 if (emptypos < NLINES) { /* finish off last page, if */ 755 slop_lines(NLINES - emptypos); /* it's not done yet */ 756 #ifdef DRIVER 757 ioctl(OUTFILE, VSETSTATE, prtmode); 758 if (write(OUTFILE, "\f", 2) != 2) 759 exit(RESTART); 760 ioctl(OUTFILE, VSETSTATE, pltmode); 761 #endif 762 } 763 if (output) { 764 emptypos = 0; /* set emptying to be started */ 765 elevel = fill; /* swap buffer pointers */ 766 fill = empty; 767 empty = elevel; 768 } 769 770 vpos = 0; 771 output = 1; 772 if (nolist == 0) 773 return; /* no -o specified */ 774 output = 0; 775 for (i = 0; i < nolist; i += 2) 776 if (n >= olist[i] && n <= olist[i+1]) { 777 output = 1; 778 break; 779 } 780 } 781 782 t_newline() /* do whatever for the end of a line */ 783 { 784 hpos = 0; /* because we're now back at the left margin */ 785 } 786 787 t_size(n) /* convert integer to internal size number*/ 788 int n; 789 { 790 int i; 791 792 if (n <= pstab[0]) 793 return(0); 794 else if (n >= pstab[nsizes - 1]) 795 return(nsizes - 1); 796 for (i = 0; n > pstab[i]; i++) 797 ; 798 return(i); 799 } 800 801 t_charht(n) /* set character height to n */ 802 int n; 803 { 804 #ifdef DEBUGABLE 805 if (dbg) error(!FATAL, "can't set height on varian"); 806 #endif 807 } 808 809 t_slant(n) /* set slant to n */ 810 int n; 811 { 812 #ifdef DEBUGABLE 813 if (dbg) error(!FATAL, "can't set slant on varian"); 814 #endif 815 } 816 817 t_font(s) /* convert string to internal font number */ 818 char *s; 819 { 820 int n; 821 822 n = atoi(s); 823 if (n < 0 || n > nfonts) 824 n = 1; 825 return(n); 826 } 827 828 t_text(s) /* print string s as text */ 829 char *s; 830 { 831 int c; 832 char str[100]; 833 834 if (!output) 835 return; 836 while (c = *s++) { 837 if (c == '\\') { 838 switch (c = *s++) { 839 case '\\': 840 case 'e': 841 put1('\\'); 842 break; 843 case '(': 844 str[0] = *s++; 845 str[1] = *s++; 846 str[2] = '\0'; 847 put1s(str); 848 break; 849 } 850 } else { 851 put1(c); 852 } 853 hmot(lastw); 854 #ifdef DEBUGABLE 855 if (dbg) fprintf(stderr,"width = %d\n", lastw); 856 #endif 857 } 858 } 859 860 861 t_reset(c) 862 { 863 if (c == 's') { 864 t_page(); 865 output = 0; 866 t_page(); 867 #ifdef DRIVER 868 ioctl(OUTFILE, VSETSTATE, prtmode); 869 if (write(OUTFILE, "\f", 2) != 2) 870 exit(RESTART); 871 #endif 872 } 873 } 874 875 876 /*----------------------------------------------------------------------------* 877 | Routine: hgoto (horizontal_spot) 878 | 879 | Results: hpos is set to n. If n overlaps in either direction, it wraps 880 | around to the other end of the page. 881 *----------------------------------------------------------------------------*/ 882 883 hgoto(n) 884 int n; 885 { 886 if (n < 0) 887 n += NLINES; 888 else if (n >= NLINES) 889 n -= NLINES; 890 hpos = n; 891 } 892 893 894 /*----------------------------------------------------------------------------* 895 | Routine: vgoto (vertical_spot) 896 | 897 | Results: vpos is set to n. If n overlaps in either direction, it wraps 898 | around to the other end of the page. 899 *----------------------------------------------------------------------------*/ 900 901 vgoto(n) 902 int n; 903 { 904 if (n < 0) 905 n += RASTER_LENGTH; 906 else if (n > RASTER_LENGTH) 907 n -= RASTER_LENGTH; 908 vpos = n; 909 } 910 911 put1s(s) /* s is a funny char name */ 912 char *s; 913 { 914 int i; 915 916 if (!output) 917 return; 918 #ifdef DEBUGABLE 919 if (dbg) fprintf(stderr,"%s ", s); 920 #endif 921 for (i = 0; i < nchtab; i++) 922 if (strcmp(&chname[chtab[i]], s) == 0) 923 break; 924 if (i < nchtab) 925 put1(i + 128); 926 } 927 928 put1(c) /* output char c */ 929 int c; 930 { 931 char *pw; 932 register char *p; 933 register int i, k; 934 int j, ofont, code; 935 936 if (!output) 937 return; 938 c -= 32; 939 if (c <= 0) { 940 #ifdef DEBUGABLE 941 if (dbg) fprintf(stderr,"non-exist 0%o\n", c + 32); 942 #endif 943 lastw = (widtab[font][0] * pstab[size] + dev.unitwidth/2) 944 / dev.unitwidth; 945 return; 946 } 947 k = ofont = font; 948 i = fitab[font][c] & BMASK; 949 if (i != 0) { /* it's on this font */ 950 p = codetab[font]; /* get the printing value of ch */ 951 pw = widtab[font]; /* get the width */ 952 } else { /* on another font - run down the font list */ 953 for (j=0; j++ <= nfonts; k = (k+1) % (nfonts+1)) { 954 if (fitab[k] == 0) 955 continue; 956 if ((i=fitab[k][c] & BMASK) != 0) { 957 p = codetab[k]; 958 pw = widtab[k]; 959 setfont(k); 960 break; 961 } 962 } 963 } 964 965 if (i == 0) { 966 #ifdef DEBUGABLE 967 if (dbg) fprintf(stderr,"not found 0%o\n", c+32); 968 #endif 969 return; 970 } 971 code = p[i] & BMASK; 972 #ifdef DEBUGABLE 973 if (dbg) { 974 if (isprint(c+32)) 975 fprintf(stderr,"%c %d\n", c+32, code); 976 else 977 fprintf(stderr,"%03o %d\n", c+32, code); 978 } 979 #endif 980 outc(code); /* character is < 254 */ 981 if (font != ofont) 982 setfont(ofont); 983 lastw = ((pw[i]&077) * pstab[size] + dev.unitwidth/2) / dev.unitwidth; 984 } 985 986 987 988 setsize(n) /* set point size to n (internal) */ 989 int n; 990 { 991 992 if (n == size) 993 return; /* already there */ 994 if (vloadfont(font, pstab[n]) != -1) 995 size = n; 996 } 997 998 t_fp(n, s, si) /* font position n now contains font s, intname si */ 999 int n; /* internal name is ignored */ 1000 char *s, *si; 1001 { 1002 register int i; 1003 1004 1005 /* first convert s to filename if possible */ 1006 for (i = 0; fontmap[i].ffile != (char *) 0; i++) { 1007 #ifdef DEBUGABLE 1008 if(dbg>1)fprintf(stderr,"testing :%s:%s:\n",s,fontmap[i].fname); 1009 #endif 1010 if (strcmp(s, fontmap[i].fname) == 0) { 1011 s = fontmap[i].ffile; 1012 #ifdef DEBUGABLE 1013 if(dbg)fprintf(stderr, "found :%s:\n",fontmap[i].ffile); 1014 #endif 1015 break; 1016 } 1017 } 1018 fontname[n] = s; 1019 for(i = 0;i <= NFONTS;i++) /* free the bits of that font */ 1020 if (fontdes[i].fnum == n){ 1021 nfree(fontdes[i].bits); 1022 fontdes[i].fnum = -1; 1023 } 1024 } 1025 1026 1027 setfont(n) /* set font to n */ 1028 int n; 1029 { 1030 if (n < 0 || n > nfonts) 1031 error(FATAL, "illegal font %d", n); 1032 if (vloadfont(n,pstab[size]) != -1) 1033 font = n; 1034 } 1035 1036 1037 setstip(n) /* set stipple font to n */ 1038 int n; 1039 { 1040 if (n < 1 || n > nstips) 1041 error(FATAL, "illegal stipple %d", n); 1042 stip = n; 1043 } 1044 1045 1046 vloadfont(fnum, fsize) 1047 register int fnum; 1048 register int fsize; 1049 { 1050 register int i; 1051 1052 fontwanted = 0; 1053 if (fnum == cfnum && fsize == cpsize) 1054 return(0); 1055 for (i = 0; i < NFONTS; i++) { 1056 if (fontdes[i].fnum == fnum && fontdes[i].psize == fsize) { 1057 cfnum = fontdes[i].fnum; 1058 cpsize = fontdes[i].psize; 1059 dispatch = &fontdes[i].disp[0]; 1060 bits = fontdes[i].bits; 1061 cfont = i; 1062 return (0); 1063 } 1064 } 1065 /* this is a new font */ 1066 if (fnum < 0 || fnum > NFONTS || fontname[fnum] == 0) { 1067 error(!FATAL,"error: illegal font %d, size %d\n", fnum, fsize); 1068 return(-1); 1069 } 1070 /* Need to verify the existance of that font/size here*/ 1071 nfontnum = fnum; 1072 npsize = fsize; 1073 fontwanted++; 1074 return (0); 1075 } 1076 1077 1078 getfont() 1079 { 1080 register int fnum; 1081 register int fsize; 1082 register int fontd; 1083 register int d; 1084 register int sizehunt = size; 1085 char cbuf[BUFSIZ]; 1086 1087 fnum = nfontnum; 1088 fsize = npsize; 1089 /* try to open font file - if unsuccessful, hunt for */ 1090 /* a file of same style, different size to substitute */ 1091 d = -1; /* direction to look in pstab (smaller first) */ 1092 do { 1093 sprintf(cbuf, "%s/%s.%dr", bitdir, fontname[fnum], fsize); 1094 fontd = open(cbuf, OPENREAD); 1095 if (fontd == -1) { /* File wasn't found. Try another ps */ 1096 sizehunt += d; 1097 if (sizehunt < 0) { /* past beginning - look higher */ 1098 d = 1; 1099 sizehunt = size + 1; 1100 } 1101 if (sizehunt > nsizes) { /* past top - forget it */ 1102 d = 0; 1103 } else { 1104 fsize = pstab[sizehunt]; 1105 } 1106 } 1107 } while (fontd == -1 && d != 0); 1108 1109 if (fontd == -1) { /* completely unsuccessful */ 1110 perror(cbuf); 1111 error(!FATAL,"fnum = %d, psize = %d, name = %s", 1112 fnum, npsize, fontname[fnum]); 1113 fontwanted = 0; 1114 return (-1); 1115 } 1116 if (read(fontd, &header, sizeof (header)) != sizeof (header) 1117 || header.magic != 0436) 1118 fprintf(stderr, "%s: Bad font file", cbuf); 1119 else { 1120 cfont = relfont(); 1121 if ((bits=nalloc(header.size+DSIZ+1,1))== NULL) 1122 if ((bits=allpanic(header.size+DSIZ+1))== NULL) { 1123 error(FATAL,"%s: ran out of memory", cbuf); 1124 } 1125 1126 /* 1127 * have allocated one chunk of mem for font, dispatch. 1128 * get the dispatch addr, align to word boundary. 1129 */ 1130 1131 d = (int) bits+header.size; 1132 d += 1; 1133 d &= ~1; 1134 if (read (fontd, d, DSIZ) != DSIZ 1135 || read (fontd, bits, header.size) != header.size) 1136 fprintf(stderr, "bad font header"); 1137 else { 1138 close(fontd); 1139 cfnum = fontdes[cfont].fnum = fnum; 1140 cpsize = fontdes[cfont].psize = fsize; 1141 fontdes [cfont].bits = bits; 1142 fontdes [cfont].disp = (struct dispatch *) d; 1143 dispatch = &fontdes[cfont].disp[0]; 1144 fontwanted = 0; 1145 return (0); 1146 } 1147 } 1148 close(fontd); 1149 fontwanted = 0; 1150 return(-1); 1151 } 1152 1153 /* 1154 * "release" a font position - find an empty one, if possible 1155 */ 1156 1157 relfont() 1158 { 1159 register int newfont; 1160 1161 for (newfont = 0; newfont < NFONTS; newfont++) 1162 if (fontdes [newfont].fnum == -1) 1163 break; 1164 if (fontdes [newfont].fnum != -1) { 1165 nfree (fontdes [newfont].bits); 1166 #ifdef DEBUGABLE 1167 if (dbg) fprintf (stderr, "freeing position %d\n", newfont); 1168 } else { 1169 if (dbg) 1170 fprintf (stderr, "taking, not freeing, position %d\n", newfont); 1171 #endif 1172 } 1173 fontdes[newfont].fnum = -1; 1174 return (newfont); 1175 } 1176 1177 char *allpanic (nbytes) 1178 int nbytes; 1179 { 1180 register int i; 1181 1182 for (i = 0; i <= NFONTS; i++) { 1183 if (fontdes[i].fnum != -1) nfree(fontdes[i].bits); 1184 fontdes[i].fnum = -1; 1185 cfnum = cpsize = -1; 1186 } 1187 return(nalloc(nbytes,1)); 1188 } 1189 1190 int M[] = { 0xffffffff, 0xfefefefe, 0xfcfcfcfc, 0xf8f8f8f8, 1191 0xf0f0f0f0, 0xe0e0e0e0, 0xc0c0c0c0, 0x80808080, 0x0 }; 1192 int N[] = { 0x00000000, 0x01010101, 0x03030303, 0x07070707, 1193 0x0f0f0f0f, 0x1f1f1f1f, 0x3f3f3f3f, 0x7f7f7f7f, 0xffffffff }; 1194 int strim[] = { 0xffffffff, 0xffffff00, 0xffff0000, 0xff000000, 0 }; 1195 1196 outc(code) 1197 int code; /* character to print */ 1198 { 1199 register struct dispatch *dis; /* ptr to character font record */ 1200 register char *addr; /* addr of font data */ 1201 int llen; /* length of each font line */ 1202 int nlines; /* number of font lines */ 1203 register char *scanp; /* ptr to output buffer */ 1204 int scanp_inc; /* increment to start of next buffer */ 1205 int offset; /* bit offset to start of font data */ 1206 register int i; /* loop counter */ 1207 register int count; /* font data ptr */ 1208 register unsigned fontdata; /* font data temporary */ 1209 register int off8; /* offset + 8 */ 1210 1211 if (fontwanted) 1212 getfont(); 1213 dis = dispatch + code; 1214 if (dis->nbytes) { 1215 addr = bits + dis->addr; 1216 llen = (dis->up + dis->down + 7) >> 3; 1217 nlines = dis->right + dis->left; 1218 scanp = fill + (hpos + 1 - dis->left) * BYTES_PER_LINE 1219 - (1 + ((dis->down + vpos - 1) >> 3)); 1220 if (scanp < fill) 1221 scanp += BUFFER_SIZE; 1222 scanp_inc = BYTES_PER_LINE - llen; 1223 off8 = ((dis->down + vpos - 1) &07); 1224 offset = off8 - 8; 1225 for (i = 0; i < nlines; i++) { 1226 if (scanp >= fill + BUFFER_SIZE) 1227 scanp -= BUFFER_SIZE; 1228 count = llen; 1229 if (scanp + count < fill + BUFFER_SIZE) { 1230 do { 1231 fontdata = *(unsigned *)addr; 1232 addr += 4; 1233 if (count < 4) 1234 fontdata &= ~strim[count]; 1235 *(unsigned*)scanp |=(fontdata << offset) & ~M[off8]; 1236 scanp++; 1237 *(unsigned*)scanp |=(fontdata << off8) & ~N[off8]; 1238 scanp += 3; 1239 count -= 4; 1240 } while (count > 0); 1241 } 1242 scanp += scanp_inc+count; 1243 addr += count; 1244 } 1245 return; 1246 } 1247 return; 1248 } 1249 1250 1251 /*----------------------------------------------------------------------------* 1252 | Routine: setfill(stipple_number) 1253 | 1254 | Results: sets the fill-pattern pointers (stip_disp and 1255 | stip_bits) for a particular stipple. Takes stipple 1256 | font from current "stip" number. 1257 *----------------------------------------------------------------------------*/ 1258 1259 setfill(number) 1260 int number; 1261 { 1262 int curfont; /* places to save current text font */ 1263 int cursize; 1264 1265 /* set global stipmem for polygon */ 1266 if (number < 0 || number >= DISPATCHSIZE) 1267 stipmem = 0; 1268 else 1269 stipmem = number; 1270 1271 curfont = cfnum; /* get pointers to */ 1272 cursize = cpsize; /* the inuse font */ 1273 if (vloadfont(nfonts + stip, 0)) { 1274 stip_disp = (struct dispatch *) NULL; /* stipple not here */ 1275 } else { 1276 if (fontwanted) { 1277 if (getfont()) { 1278 stip_disp = (struct dispatch *) NULL; 1279 } else { 1280 stip_disp = dispatch; /* save for polygon routine */ 1281 stip_bits = bits; 1282 } 1283 } else { 1284 stip_disp = dispatch; /* save for polygon routine */ 1285 stip_bits = bits; 1286 } 1287 } 1288 if (curfont >= 0) vloadfont(curfont, cursize); 1289 } 1290 1291 1292 slop_lines(nlines) 1293 int nlines; 1294 1295 /* Output "nlines" lines from the buffer, and clear that section of the */ 1296 /* buffer. Also updates the pointers to the emptying buffer */ 1297 1298 { 1299 unsigned usize; 1300 1301 usize = BYTES_PER_LINE * nlines; 1302 vwrite(elevel, usize); 1303 vclear(elevel, usize); 1304 elevel += usize; 1305 emptypos += nlines; 1306 } 1307 1308 vwrite(buf,usize) 1309 char *buf; 1310 unsigned usize; 1311 { 1312 register int tsize = 0; 1313 1314 while (usize){ 1315 buf += tsize; 1316 tsize = usize > MAXWRIT ? MAXWRIT : usize; 1317 #ifdef DEBUGABLE 1318 if (dbg)fprintf(stderr,"buf = %d size = %d\n",buf,tsize); 1319 #endif 1320 if ((tsize = write(OUTFILE, buf, tsize)) < 0) { 1321 perror("dvar: write failed"); 1322 exit(RESTART); 1323 } 1324 usize -= tsize; 1325 } 1326 } 1327 1328 vclear (ptr, nbytes) 1329 char *ptr; 1330 unsigned nbytes; 1331 { 1332 register tsize = 0; 1333 1334 while (nbytes){ 1335 if ((unsigned)(16*1024) < nbytes) { 1336 tsize = 16 * 1024; 1337 } else 1338 tsize = nbytes; 1339 nbytes -= tsize; 1340 #ifdef DEBUGABLE 1341 if (dbg) fprintf(stderr,"clearing ptr = %d size = %d\n",ptr,tsize); 1342 #endif 1343 clear(ptr,tsize); 1344 ptr += tsize; 1345 } 1346 } 1347 1348 /*ARGSUSED*/ 1349 clear(lp, nbytes) 1350 int *lp; 1351 int nbytes; 1352 { 1353 #ifdef vax 1354 asm("movc5 $0,(sp),$0,8(ap),*4(ap)"); 1355 #else 1356 register int i = nbytes; 1357 register int *cp = lp; 1358 1359 while (i-- > 0) 1360 *(cp++) = 0; 1361 #endif 1362 } 1363 1364 char * 1365 nalloc(i, j) 1366 int i, j; 1367 { 1368 register char *cp; 1369 1370 cp = calloc(i, j); 1371 #ifdef DEBUGABLE 1372 if (dbg) fprintf(stderr, "allocated %d bytes at %x\n", i * j, cp); 1373 #endif 1374 return(cp); 1375 } 1376 1377 nfree(cp) 1378 char *cp; 1379 { 1380 #ifdef DEBUGABLE 1381 if (dbg) fprintf(stderr, "freeing at %x\n", cp); 1382 #endif 1383 free(cp); 1384 } 1385 1386 1387 /* 1388 * Points should be in the range 0 <= x < RASTER_LENGTH, 0 <= y < NLINES. 1389 * The origin is the top left-hand corner with increasing x towards the 1390 * right and increasing y going down. X and Y should be sent as (0,0) being 1391 * at the bottom left. The output array is NLINES x BYTES_PER_LINE pixels. 1392 */ 1393 point(x, y) 1394 register int x; 1395 register int y; 1396 { 1397 if ((unsigned)(y=(RASTER_LENGTH-1)-y)<RASTER_LENGTH && (unsigned)x<NLINES) { 1398 *(fill + x * BYTES_PER_LINE + (y >> 3)) |= 1 << (7 - (y & 07)); 1399 } 1400 } 1401 1402 1403 #define pv(x) ((polyvector *)x) 1404 1405 typedef struct poly { 1406 struct poly *next; /* doublely-linked lists of vectors */ 1407 struct poly *prev; 1408 int param; /* bressenham line algorithm parameter */ 1409 short dy; /* delta-y for calculating line */ 1410 short dx; /* delta-x for calculating line */ 1411 short curry; /* current y in this vector */ 1412 short endx; /* where vector ends */ 1413 } polyvector; 1414 1415 1416 /*----------------------------------------------------------------------------* 1417 | Routine: polygon ( x_coordinates, y_coordinates, num_of_points ) 1418 | 1419 | Results: draws a polygon starting at (x[1], y[1]) going through 1420 | each of (x_coordinates, y_coordinates), and fills it 1421 | with a stipple pattern from stip_disp and stip_bits, 1422 | which point to the stipple font. The pattern is defined 1423 | by "stip" and "stipmem". 1424 | 1425 | The scan-line algorithm implemented scans from left to 1426 | right (low x to high x). It also scans, within a line, 1427 | from bottom to top (high y to low y). 1428 | 1429 | polygons are clipped to page boundary. 1430 | 1431 | Bugs: stipple pattern MUST be a power of two bytes "wide" and 1432 | square. The square restriction comes from the fact that 1433 | the varian and versatec are respectively rotated. 1434 *----------------------------------------------------------------------------*/ 1435 1436 polygon(x, y, npts) 1437 int x[]; 1438 int y[]; 1439 int npts; 1440 { 1441 int nextx; /* at what x value the next vector starts */ 1442 int maxx, minx, maxy, miny; /* finds bounds of polygon */ 1443 polyvector *activehead; /* doing fill, is active edge list */ 1444 polyvector *waitinghead; /* edges waiting to be active */ 1445 register polyvector *vectptr; /* random vector */ 1446 register int i; /* random register */ 1447 1448 char *topstipple; /* points to beginning of stipple glyph */ 1449 char *leftstipple; /* points to beginning of line of stipple */ 1450 char *bottompage; /* points to the edge of a raster line */ 1451 int bytewidth; /* glyph width in bytes */ 1452 int mask; /* mask to pick off pixel index into stipple */ 1453 int bytemask; /* mask to pick off byte index into stipple */ 1454 1455 1456 if (bordered) { 1457 for (i = 1; i < npts; i++) /* first draw outlines */ 1458 HGtline(x[i], y[i], x[i+1], y[i+1]); 1459 } 1460 1461 /* if no stipple, don't fill */ 1462 if (stip_disp == (struct dispatch *) NULL || stip_bits == (char *) NULL) 1463 return; 1464 1465 stip_disp += stipmem; /* set up parameters for */ 1466 if (!stip_disp->nbytes) { /* tiling with the stipple */ 1467 #ifdef DEBUGABLE 1468 error(!FATAL, "member not found: member %d, stipple %d", stipmem, stip); 1469 #endif 1470 return; 1471 } 1472 topstipple = stip_bits + stip_disp->addr; 1473 bytewidth = stip_disp->up + stip_disp->down; 1474 for (i = 1 << 30; i && i != bytewidth; i = i >> 1) 1475 ; 1476 if (i==0 || bytewidth<8 || bytewidth != stip_disp->right+stip_disp->left) { 1477 error(!FATAL, "invalid stipple: number %d, member %d", stip, stipmem); 1478 return; 1479 } 1480 mask = bytewidth - 1; 1481 bytewidth = bytewidth >> 3; 1482 bytemask = bytewidth - 1; 1483 1484 /* allocate space for raster-fill algorithm*/ 1485 if ((vectptr = pv( nalloc(sizeof(polyvector), npts + 6) )) == NULL) { 1486 error(!FATAL, "unable to allocate space for polygon"); 1487 return; 1488 } 1489 #ifdef DEBUGABLE 1490 if (dbg) fprintf(stderr, "polygon, %d points\n", npts); 1491 #endif 1492 1493 waitinghead = vectptr; 1494 minx = maxx = x[1]; 1495 miny = maxy = y[1]; 1496 (vectptr++)->prev = pv( NULL ); /* put dummy entry at start */ 1497 waitinghead->next = vectptr; 1498 vectptr->prev = waitinghead; 1499 i = 1; /* starting point of coords */ 1500 if (y[1] != y[npts] || x[1] != x[npts]) { 1501 y[0] = y[npts]; /* close polygon if it's not */ 1502 x[0] = x[npts]; 1503 i = 0; 1504 } 1505 while (i < npts) { /* set up the vectors */ 1506 register int j; /* indexes to work off of */ 1507 register int k; 1508 1509 if (miny > y[i]) miny = y[i]; /* remember limits */ 1510 else if (maxy < y[i]) maxy = y[i]; 1511 if (maxx < x[i]) maxx = x[i]; 1512 else if (minx > x[i]) minx = x[i]; 1513 1514 j = i; /* j "points" to the higher (lesser) point */ 1515 k = ++i; 1516 if (x[j] == x[k]) /* ignore vertical lines */ 1517 continue; 1518 1519 if (x[j] > x[k]) { 1520 j++; 1521 k--; 1522 } 1523 vectptr->next = vectptr + 1; 1524 vectptr->param = x[j]; /* starting point of vector */ 1525 vectptr->dy = y[k] - y[j]; /* line-calculating parameters */ 1526 vectptr->dx = x[k] - x[j]; 1527 vectptr->curry = y[j]; /* starting point */ 1528 (vectptr++)->endx = x[k]; /* ending point */ 1529 vectptr->prev = vectptr - 1; 1530 } 1531 /* set now because we didn't know minx before */ 1532 leftstipple = topstipple + (minx & mask) * bytewidth; 1533 bottompage = fill + minx * BYTES_PER_LINE; 1534 waitinghead->param = minx - 1; 1535 /* if no useable vectors, quit */ 1536 if (vectptr == waitinghead + 1) 1537 goto leavepoly; 1538 1539 vectptr->param = maxx + 1; /* dummy entry at end, too */ 1540 vectptr->next = pv( NULL ); 1541 1542 activehead = ++vectptr; /* two dummy entries for active list */ 1543 vectptr->curry = maxy + 1; /* head */ 1544 vectptr->endx = maxx + 1; 1545 vectptr->param = vectptr->dx = vectptr->dy = 0; 1546 activehead->next = ++vectptr; 1547 activehead->prev = vectptr; 1548 1549 vectptr->prev = activehead; /* tail */ 1550 vectptr->next = activehead; 1551 vectptr->curry = miny - 1; 1552 vectptr->endx = maxx + 1; 1553 vectptr->param = vectptr->dx = vectptr->dy = 0; 1554 1555 1556 /* main loop -- gets vectors off the waiting list, */ 1557 /* then displays spans while updating the vectors in */ 1558 /* the active list */ 1559 while (minx <= maxx) { 1560 i = maxx + 1; /* this is the NEXT time to get a new vector */ 1561 for (vectptr = waitinghead->next; vectptr != pv( NULL ); ) { 1562 if (minx == vectptr->param) { 1563 /* the entry in waiting list (vectptr) is */ 1564 /* ready to go into active list. Need to */ 1565 /* convert some vector stuff and sort the */ 1566 /* entry into the list. */ 1567 register polyvector *p; /* random vector pointers */ 1568 register polyvector *v; 1569 1570 /* convert this */ 1571 if (vectptr->dy < 0) /* entry to active */ 1572 vectptr->param = (vectptr->dy >> 1) - (vectptr->dx >> 1); 1573 else 1574 vectptr->param = -((vectptr->dx >> 1) + (vectptr->dy >> 1)); 1575 1576 p = vectptr; /* remove from the */ 1577 vectptr = vectptr->next; /* waiting list */ 1578 vectptr->prev = p->prev; 1579 p->prev->next = vectptr; 1580 /* find where it goes */ 1581 /* in the active list */ 1582 /* (sorted greatest first) */ 1583 for (v = activehead->next; v->curry > p->curry; v = v->next) 1584 ; 1585 p->next = v; /* insert into active list */ 1586 p->prev = v->prev; /* before the one it stopped on */ 1587 v->prev = p; 1588 p->prev->next = p; 1589 } else { 1590 if (i > vectptr->param) { 1591 i = vectptr->param; 1592 } 1593 vectptr = vectptr->next; 1594 } 1595 } 1596 nextx = i; 1597 1598 /* print the polygon while there */ 1599 /* are no more vectors to add */ 1600 while (minx < nextx) { 1601 /* remove any finished vectors */ 1602 vectptr = activehead->next; 1603 do { 1604 if (vectptr->endx <= minx) { 1605 vectptr->prev->next = vectptr->next; 1606 vectptr->next->prev = vectptr->prev; 1607 } 1608 } while ((vectptr = vectptr->next) != activehead); 1609 1610 /* draw the span */ 1611 if (((unsigned) minx) < NLINES) { 1612 vectptr = activehead->next; 1613 while (vectptr->next != activehead) { 1614 register int start; /* get the beginning */ 1615 register int length; /* and the end of span */ 1616 register char *glyph; 1617 register char *raster; 1618 1619 start = (RASTER_LENGTH - 1) - vectptr->curry; 1620 vectptr = vectptr->next; 1621 length = RASTER_LENGTH - vectptr->curry; 1622 vectptr = vectptr->next; 1623 1624 /* bound the polygon to the page */ 1625 if (start >= RASTER_LENGTH) 1626 break; 1627 if (start < 0) start = 0; 1628 if (length > RASTER_LENGTH) length = RASTER_LENGTH; 1629 length -= start; /* length is in pixels */ 1630 1631 i = start & 7; 1632 start = start >> 3; /* start is in bytes */ 1633 raster = bottompage + start; 1634 glyph = leftstipple + (start & bytemask); 1635 1636 if (i) { /* do any piece of byte */ 1637 register char data; /* that hangs on the front */ 1638 1639 data = (*(glyph++)) & (0x7f >> --i); 1640 length -= 7 - i; 1641 if (length < 0) { /* less than one byte wide? */ 1642 data &= 0xff << -length; 1643 length = 0; /* force clean stoppage */ 1644 } 1645 *(raster++) |= data; 1646 /* update glyph ptr after first byte */ 1647 if (!(++start & bytemask)) 1648 glyph = leftstipple; 1649 } 1650 /* fill the line of raster */ 1651 while ((length -= 8) >= 0) { 1652 *(raster++) |= *(glyph++); 1653 if (!(++start & bytemask)) 1654 glyph = leftstipple; 1655 } 1656 if (length & 7) { /* add any part hanging off the end */ 1657 *raster |= (*glyph) & (0xff << -length); 1658 } 1659 } 1660 } 1661 1662 #ifdef DEBUGABLE 1663 if (dbg) { 1664 vectptr = activehead; 1665 do { 1666 fprintf (stderr, "%d ", vectptr->curry); 1667 vectptr = vectptr->next; 1668 } while (vectptr != activehead); 1669 } 1670 #endif 1671 /* update the vectors */ 1672 vectptr = activehead->next; 1673 do { 1674 if (vectptr->dy > 0) { 1675 while (vectptr->param >= 0) { 1676 vectptr->param -= vectptr->dx; 1677 vectptr->curry++; 1678 } 1679 vectptr->param += vectptr->dy; 1680 } else if (vectptr->dy < 0) { 1681 while (vectptr->param >= 0) { 1682 vectptr->param -= vectptr->dx; 1683 vectptr->curry--; 1684 } 1685 vectptr->param -= vectptr->dy; 1686 } 1687 /* must sort the vectors if updates */ 1688 /* caused them to cross */ 1689 /* also move to next vector here */ 1690 if (vectptr->curry > vectptr->prev->curry) { 1691 register polyvector *v; /* vector to move */ 1692 register polyvector *p; /* vector to put it after */ 1693 1694 v = vectptr; 1695 p = v->prev; 1696 while (v->curry > p->curry) /* find the */ 1697 p = p->prev; /* right vector */ 1698 1699 vectptr = vectptr->next; /* remove from spot */ 1700 vectptr->prev = v->prev; 1701 v->prev->next = vectptr; 1702 1703 v->prev = p; /* put in new spot */ 1704 v->next = p->next; 1705 p->next = v; 1706 v->next->prev = v; 1707 } else { 1708 vectptr = vectptr->next; 1709 } 1710 } while (vectptr != activehead); 1711 #ifdef DEBUGABLE 1712 if (dbg) fprintf(stderr, "line done\n"); 1713 #endif 1714 1715 if (++minx & mask) { 1716 leftstipple += bytewidth; 1717 } else { 1718 leftstipple = topstipple; 1719 } 1720 bottompage += BYTES_PER_LINE; 1721 } /* while (minx < nextx) */ 1722 } /* while (minx <= maxx) */ 1723 1724 leavepoly: 1725 nfree(waitinghead); 1726 } /* polygon function */ 1727