1: 2: /*----------------------------------------------------------------------------- 3: * ipress - most of the code directly dependent on interpress used by dipress 4: * to produce an interpress file from device independent troff 5: * intermediate code. 6: * 7: * William LeFebvre 8: * 9: * Copyright (c) 1984, 1985 Xerox Corp. 10: * 11: * History: 12: * John Mellor-Crummey 28-aug-1985 restructuring and minor modifications 13: * 14: * ed flint 10-may-1985 coerce device.num_char_wid to unsigned char, change 15: * ch argument in outputChar to unsigned int 16: * since we now have > 128 special characters 17: *---------------------------------------------------------------------------*/ 18: 19: 20: #include <stdio.h> 21: #include <ctype.h> 22: #include <signal.h> 23: #include <math.h> 24: #include <sys/types.h> 25: #include <sys/file.h> 26: #include <sys/stat.h> 27: 28: #include "deviceinfo.h" /* typesetter characteristics */ 29: 30: #include "iptokens.h" /* \ */ 31: #include "literal.h" /* > interface levels for interpress */ 32: #include "operator.h" /* / */ 33: 34: #include "defs.h" /* constant and macro definitions */ 35: #include "externs.h" /* declarations for global variables */ 36: 37: 38: 39: /* initialize device */ 40: initDevice() 41: { 42: int lines = 0; 43: int timapf; 44: int ret; 45: register char *ptr; 46: register char **ipp; 47: register char **trp; 48: char temp[60]; 49: struct stat stbuf; 50: 51: if (dbg) printf("initDevice called\n"); 52: 53: /* start the preamble */ 54: ip_select(outputfile); 55: /* special master instructions go here... */ 56: Op(beginBlock); 57: Op(beginBody); 58: 59: /* save scaling transform that uses a mica co-ordinate system */ 60: AppendRational(1L, 100000); 61: Op(scale); 62: AppendInteger((long) F_transform); 63: Op(fset); 64: 65: /* select file that holds page bodies */ 66: ip_select(pagebodyfile); 67: 68: /* open file that maps troff names to interpress names */ 69: (void) sprintf(temp, "%s/dev%s/interpress-fonts", fontdirectory, devicename); 70: if ((timapf = open(temp, O_RDONLY,0)) == -1) 71: reportError(QUIT, "can't open %s (%s)", temp, sys_errlist[errno]); 72: 73: /* read in the whole thing */ 74: ret = fstat(timapf, &stbuf); 75: if (dbg) printf("stat returned %d, errno %d\n", ret, errno); 76: timap = malloc((unsigned)(stbuf.st_size + 1)); 77: if (dbg) printf("reading %d bytes from timapf\n", stbuf.st_size); 78: ret = read(timapf, timap, (int)stbuf.st_size); 79: if (dbg) printf("read returned %d, errno %d, timapf %d\n", ret, errno, timapf); 80: timap[(int)stbuf.st_size] = '\0'; 81: (void) close(timapf); 82: 83: /* count the newlines */ 84: if (dbg) printf("pointer starts at %08x ... ", timap); 85: 86: for (ptr = timap; *ptr != '\0'; ptr++) 87: if (*ptr == '\n') lines++; 88: 89: if (dbg) printf("ends at %08x\n", ptr); 90: if (dbg) printf("found %d lines\n", lines); 91: 92: /* allocate the mapping arrays */ 93: trp = trname = (char **)malloc((unsigned)(lines * 2 * sizeof(char *))); 94: ipp = ipname = trname + lines; 95: 96: /* break out the strings and store pointers in the arrays */ 97: ptr = timap; 98: mapcnt = 0; 99: while (*ptr) 100: { 101: if (dbg) printf("loop: ptr = %08x, *ptr = %c\n", ptr, *ptr); 102: *trp++ = ptr; 103: while (!white(*ptr)) ptr++; 104: *ptr++ = '\0'; 105: while (white(*ptr)) ptr++; 106: *ipp++ = ptr; 107: while (*++ptr != '\n') /* nothing */; 108: *ptr++ = '\0'; 109: mapcnt++; 110: } 111: 112: if (dbg) 113: { 114: int i; 115: 116: for (i = 0; i < lines; i++) 117: printf("%s\t%s\n", trname[i], ipname[i]); 118: } 119: 120: /* reset vertical and horizontal positions */ 121: hor_pos = ver_pos = old_hor = old_ver = 0; 122: 123: /* reset the font information */ 124: bzero((char *) currfonts, sizeof(currfonts)); 125: } 126: 127: setScale(spi) /* set resolution */ 128: 129: int spi; 130: 131: { 132: /* set the scaling variable used in all x and y calculations */ 133: scale = floor(2540.0 / (double)spi + 0.5); 134: if (dbg) printf("setScale(%d) sets scale to %e\n", spi, scale); 135: 136: /* 137: * Set the drawing scale based on the scale. This factor is applied to 138: * all points drawn in the bitmap for graphical objects. It is scaled 139: * down from micas to 508 dpi so that the bitmaps aren't of unwieldy 140: * size, but still retain enough information to look decent on a good 141: * device. 508/2540 == 0.2 142: */ 143: drawscale = scale * .2; 144: if (dbg) printf("setScale(%d) sets drawscale to %e\n", spi, drawscale); 145: } 146: 147: pushCurrentEnv() /* begin a new block */ 148: { 149: statep->ssize = size; 150: statep->sfont = font; 151: statep->shorig = hor_orig; 152: statep->svorig = ver_orig; 153: statep->shpos = hor_pos; 154: statep->svpos = ver_pos; 155: hor_orig = hor_pos; 156: ver_orig = ver_pos; 157: hor_pos = ver_pos = 0; 158: if (statep++ >= state + MAXSTATE) 159: { 160: reportError(QUIT, "{ nested too deep"); 161: } 162: hor_pos = ver_pos = 0; 163: } 164: 165: popSavedEnv() /* pop to previous state */ 166: { 167: if (--statep < state) 168: { 169: reportError(QUIT, "extra }"); 170: } 171: size = statep->ssize; 172: font = statep->sfont; 173: hor_pos = statep->shpos; 174: ver_pos = statep->svpos; 175: hor_orig = statep->shorig; 176: ver_orig = statep->svorig; 177: } 178: 179: newpage(n) /* new page */ 180: int n; 181: { 182: int i; 183: char buff[15]; 184: 185: /* print any pending bitmap */ 186: 187: /* terminate previous page if outputting */ 188: if (outputflag) 189: { 190: print_bitmap(); 191: Op(endBody); 192: } 193: else flush_bitmap(); 194: 195: /* reset vertical positions */ 196: ver_pos = old_ver = 0; 197: 198: /* check new page number against those found in the nPageRanges */ 199: if (nPageRanges == 0) 200: { 201: /* no -o specified -- do all pages */ 202: outputflag = 1; 203: } 204: else 205: { 206: /* see if new page has been selected for output */ 207: outputflag = 0; 208: for (i = 0; i < nPageRanges; i++) 209: { 210: if ((n >= pagerange[i][0]) && (n <= pagerange[i][1])) 211: { 212: outputflag = 1; 213: break; 214: } 215: } 216: } 217: 218: /* start new page */ 219: if (outputflag) 220: { 221: Op(beginBody); 222: (void) sprintf(buff, "Page %d", n); 223: AppendComment(buff); 224: Fget(F_transform); 225: Op(concatt); 226: AppendInteger(2L); 227: AppendInteger((long) I_strokeEnd); 228: Op(iset); 229: } 230: 231: /* font/size no longer valid -- force a new assignment */ 232: oldftsz = -1; 233: } 234: 235: newLine() /* new line (no vertical motion implied) */ 236: { 237: if (dbg == 3) 238: putchar('\n'); 239: flushbuff(); 240: endcorrect(); 241: hor_pos = 0; 242: virgin_line = 1; 243: } 244: 245: internalSize(number) /* convert integer to internal size number */ 246: int number; 247: { 248: int index; 249: 250: if (number >= pointsizeTab[device.num_sizes - 1]) 251: { 252: /* larger than largest -- use largest */ 253: return(device.num_sizes-1); 254: } 255: else if (number <= pointsizeTab[0]) 256: { 257: /* smaller than smallest -- use smallest */ 258: return(0); 259: } 260: 261: /* else find the size in pointsizeTab and return index */ 262: for (index = 0; number > pointsizeTab[index]; index++); 263: return(index); 264: } 265: 266: 267: 268: 269: 270: /* handle device stop command */ 271: resetDevice() 272: { 273: int amt; 274: static int is_reset = 0; 275: char bigbuff[1024]; 276: 277: if (is_reset) return; /* ignore multiple resets */ 278: 279: print_bitmap(); 280: 281: /* this is the absolute last thing that we do */ 282: /* wrap up the preamble and the body */ 283: ip_select(outputfile); 284: Op(endBody); 285: ip_select(pagebodyfile); 286: Op(endBody); 287: Op(endBlock); 288: ip_close(); /* close the body */ 289: 290: /* 291: * Reopen the body and copy it onto the end of the real file (which is 292: * where we have been building the preamble). We don't need to ip_flush 293: * the preamble since that is done everytime we ip_select the body. 294: * Conveniently enough, "tempfilename" still holds the name of the body 295: * temporary. 296: */ 297: pagebodyfile = open(tempfilename, O_RDONLY,0); 298: while ((amt = read(pagebodyfile, bigbuff, sizeof(bigbuff))) != 0) 299: { 300: (void) write(outputfile, bigbuff, amt); 301: } 302: 303: /* close and unlink the body temporary file */ 304: (void) close(pagebodyfile); 305: (void) unlink(tempfilename); 306: 307: /* send the file off to the printer */ 308: tempfilename[strlen(tempfilename) - 1] = '\0'; 309: if (outputfile != 1) 310: { 311: IPprint(tempfilename); 312: } 313: 314: /* we are now reset */ 315: is_reset = 1; 316: } 317: 318: outputString(character) /* print a "funny" character */ 319: char *character; 320: { 321: int i; 322: 323: if (!outputflag) 324: return; 325: if (dbg > 2) printf("\\(%s", character); 326: if (dbg > 3) putchar(' '); 327: for (i = 0; i < device.spec_char_num; i++) 328: if (strcmp(&specCharStrTab[specCharTab[i]], character) == 0) 329: break; 330: if (i < device.spec_char_num) { 331: /* printf(" i = %d so i+128 = %d\n", i, i+128); */ 332: outputChar((unsigned int) i + 128); 333: } 334: else { 335: if (dbg > 3) 336: printf("-- character not found"); 337: } 338: 339: if (dbg > 2) 340: putchar('\n'); 341: } 342: 343: outputChar(character) /* put a character */ 344: unsigned int character; 345: { 346: unsigned char *widp; /* pointer to appropriate width table */ 347: register char *codep; /* pointer to appropriate table of codes */ 348: register int i, old_font, fnt_index; 349: int j, value; 350: 351: if (!outputflag) 352: return; 353: 354: if (character <= 32) 355: { 356: if (dbg) printf("non-existent character 0%o\n", character); 357: charw = charWidthTab[font][0] * pointsizeTab[size-1] / device.width_units; 358: return; 359: } 360: character -= 32; 361: 362: old_font= font; 363: i = fontIndexTab[font][character] & 255; 364: if (i != 0) /* it's on this font */ 365: { 366: codep = charCodeTab[font]; 367: widp = charWidthTab[font]; 368: } 369: else if (specFontPos > 0) /* on special (we hope) */ 370: { 371: /* assertion: i == 0 */ 372: fnt_index= specFontPos; 373: for (j=0; j <= device.num_fonts; j++) 374: { 375: struct font_entry *fb; 376: 377: fnt_index= (fnt_index+1) % (device.num_fonts+1); 378: 379: if ((fb = fontPtr[fnt_index]) != NULL) 380: { 381: if (fb->special_flag && (i = fontIndexTab[fnt_index][character] & 255) != 0) 382: { 383: codep = charCodeTab[fnt_index]; 384: widp = charWidthTab[fnt_index]; 385: setFont(fnt_index); 386: break; 387: } 388: } 389: } 390: /* assertion: if j > device.num_fonts then i == 0 and character was not found */ 391: } 392: 393: value= codep[i] & 255; 394: 395: if (i == 0 || value == 0) 396: { 397: if (dbg) printf("character not found 0%o\n", character+32); 398: return; 399: } 400: 401: /* remember this character's width */ 402: /* This MUST be done before calling showchar */ 403: charw = (widp[i] * pointsizeTab[size-1] + device.width_units/2) / device.width_units; 404: if (dbg == 3) 405: { 406: if (isprint(character+32)) 407: putchar(character+32); 408: } 409: if (dbg > 3) 410: { 411: if (isprint(character+32)) 412: printf("character %c %d\n", character+32, value); 413: else 414: printf("character %03o %d\n", character+32, value); 415: } 416: 417: if (value == 0377) 418: { 419: /* special escape to an extended code */ 420: value = getexcode(i); 421: } 422: 423: if (dbg < 6) 424: showchar(value); 425: 426: if (font != old_font) 427: { 428: setFont(old_font); 429: } 430: } 431: 432: 433: setPointSize(n) /* set point size to n */ 434: 435: int n; /* internal value: index into pointsizeTab */ 436: 437: { 438: size = n; 439: ftsz = ((long)font << 16) | ((long)size); 440: } 441: 442: setFont(n) /* set font to n */ 443: 444: int n; /* internal index */ 445: 446: { 447: font = n; 448: ftsz = ((long)font << 16) | ((long)size); 449: } 450: /* 451: * reportError an error reporting hack that uses dummy parameters 452: * as place holders for arguments that may or may not 453: * exist, fprintf will sort out how many should be there 454: */ 455: /*VARARGS 2*/ 456: reportError(f, s, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) 457: char *s, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6, *arg7, *arg8; 458: { 459: fprintf(stderr, "dipress: "); 460: fprintf(stderr, s, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); 461: fprintf(stderr, "\nerror encountered near line %d\n", linenumber); 462: if (f == QUIT) goodbye(); 463: } 464: 465: 466: 467: 468: /* 469: * Graphics drawing primitives. These use the vector drawing capabilities of 470: * interpress to draw straight lines. All other primitive objects (circle, 471: * ellipse, etc.) are built in a bitmap and printed with a pixel vector. 472: */ 473: 474: drawline(dh, dv) 475: int dh,dv; 476: { 477: 478: if(!outputflag) return; 479: AppendInteger((long) curr_strokewidth); 480: AppendInteger((long) I_strokeWidth); 481: Op(iset); 482: Moveto(xloc(hor_pos), yloc(ver_pos)); 483: hor_pos += dh; 484: ver_pos += dv; 485: Lineto(xloc(hor_pos), yloc(ver_pos)); 486: Op(maskstroke); 487: } 488: 489: /* routines used by interpress dependent routines */ 490: 491: char showbuff[Showbuff_size + 1]; 492: char *showp = showbuff; 493: int showcnt = 0; 494: 495: showchar(ch) /* buffer "ch" for use in a "show" command */ 496: int ch; 497: { 498: char *framep; 499: register int hdiff, vdiff; 500: 501: /* set correct position */ 502: vdiff = ver_pos - old_ver; 503: hdiff = hor_pos - old_hor; 504: if (dbg > 4) 505: { 506: printf("old_hor %d, hor_pos %d, hdiff %d; old_ver %d, ver_pos %d, vdiff %d %s\n", 507: old_hor, hor_pos, hdiff, old_ver, ver_pos, vdiff, 508: virgin_line ? "(virgin)" : ""); 509: } 510: 511: /* NOTE: this expression depends on boolean true being 1! */ 512: /* See K&R, Appendix A, section 7.7, page 190 */ 513: if (ch == '_') goto underbar; 514: switch (((vdiff != 0) << 1) | (hdiff != 0)) 515: { 516: case 0: /* no change */ 517: break; 518: default: 519: underbar: 520: flushbuff(); 521: Setxy(xloc(hor_pos), yloc(ver_pos)); 522: break; 523: } 524: 525: /* 526: * Update old_hor and old_ver. Account for character width in old_hor but not in 527: * hor_pos. If the next hInc call is for the width of the character, the 528: * next time showchar gets called, old_hor will equal hor_pos. 529: */ 530: old_ver = ver_pos; 531: old_hor = hor_pos + charw; 532: 533: /* line is no longer virgin */ 534: virgin_line = 0; 535: 536: /* font and point still the same? */ 537: if (ftsz != oldftsz) 538: { 539: flushbuff(); 540: if ((framep = currfonts[font]->frames) == NULL) 541: { 542: /* previously unused -- give it a frame table */ 543: framep = currfonts[font]->frames = malloc((unsigned)(device.num_sizes * sizeof(char))); 544: bzero(framep, device.num_sizes * sizeof(char)); 545: } 546: 547: if (framep[size] == 0) 548: { 549: /* make a new font */ 550: ip_select(outputfile); 551: SetupFont(currfonts[font]->uname, 552: floor(pointsizeTab[size-1] * 35.28 + .5), 553: frameindex); 554: ip_select(pagebodyfile); 555: framep[size] = frameindex++; 556: } 557: 558: /* switch to new font/size combo */ 559: Setfont(framep[size]); 560: oldftsz = ftsz; 561: } 562: 563: /* adjust for character codes > 0377 */ 564: if (ch > 0377) 565: { 566: if (dbg > 4) 567: { 568: printf("processing large code: 0%o (%d)\n", ch, ch); 569: } 570: 571: if (showcnt + 5 > Showbuff_size) 572: { 573: flushbuff(); 574: } 575: *showp++ = '\377'; 576: *showp++ = (ch & 0177400) >> 8; 577: *showp++ = ch & 255; 578: *showp++ = '\377'; 579: *showp++ = '\0'; 580: showcnt += 5; 581: } 582: else 583: { 584: *showp++ = ch; 585: if (++showcnt > Showbuff_size) 586: { 587: flushbuff(); 588: } 589: } 590: } 591: 592: /* 593: * getexcode(findex) - get the extended code for the character "findex" 594: */ 595: 596: getexcode(findex) 597: int findex; 598: { 599: register int extfd; 600: register int i; 601: register unsigned short *tab; 602: char temp[132]; 603: 604: if (dbg > 4) 605: { 606: printf("getexcode(%d)\n", findex); 607: } 608: 609: if ((tab = currfonts[font]->extab) == NULL) 610: { 611: /* load in the extended code table */ 612: 613: (void) sprintf(temp, "%s/dev%s/%s.out.ext", 614: fontdirectory, devicename, currfonts[font]->name); 615: if (dbg > 4) 616: { 617: printf("opening and reading %s\n", temp); 618: } 619: if ((extfd = open(temp, O_RDONLY,0)) == -1) 620: { 621: reportError(CONTINUE, "can't open %s (%s)", temp, sys_errlist[errno]); 622: return(0); 623: } 624: currfonts[font]->extab = tab = (unsigned short *) 625: malloc( (unsigned)(i = (device.spec_char_num + 128-32) * sizeof(short)) ); 626: (void) read(extfd, (char *)tab, i); /* should test result! */ 627: (void) close(extfd); 628: } 629: 630: if (dbg > 4) 631: { 632: printf("getexcode returning %.7o\n", tab[findex]); 633: } 634: return(tab[findex]); 635: } 636: 637: flushbuff() /* flush and reset "showbuff" */ 638: { 639: if (showcnt == 0) 640: return; 641: 642: if (!in_correct) 643: { 644: startcorrect(); 645: } 646: 647: /* we must do the append_Sequence explicitly, */ 648: /* because showbuff might have nulls in it. */ 649: append_Sequence(sequenceString, showcnt, (unsigned char *)showbuff); 650: Op(show); 651: showp = showbuff; 652: showcnt = 0; 653: } 654: 655: int hstart; 656: 657: startcorrect() 658: { 659: #ifdef CORRECT_BLOCKS 660: Op(correct); 661: Op(beginBody); 662: #endif 663: in_correct = 1; 664: hstart = hor_pos; 665: } 666: 667: endcorrect() 668: { 669: /* append a Setcorrectmeasure operation */ 670: /* "hor_pos" or "old_hor"??? Make it "old_hor" for now */ 671: #ifdef CORRECT_BLOCKS 672: Setcorrectmeasure(xloc(old_hor), 0.0); 673: Op(endBody); 674: #endif 675: in_correct = 0; 676: } 677: 678: /* 679: * IPprint(filename) - send the file "filename" to the interpress printer. 680: * This routine is *very* dependent on local 681: * environments. 682: */ 683: 684: IPprint(filename) 685: char *filename; 686: { 687: if (dbg) 688: { 689: printf("interpress file saved in %s.\n", filename); 690: return; 691: } 692: 693: if (vfork() == 0) 694: { 695: /* is child */ 696: execl("/usr/local/bin/qip", "qip", "-nc", "-nk", filename, 0); 697: exit(1); 698: } 699: } 700: 701: /* bitmap graphics object sizing functions */ 702: 703: g_sizearc(x1, y1, xc, yc, x2, y2) 704: int x1, y1, xc, yc, x2, y2; 705: { 706: int minx; 707: int miny; 708: int maxx; 709: int maxy; 710: int quad1; 711: int quad2; 712: int radius; 713: int axc; 714: int ayc; 715: int i; 716: 717: /* the center and the second point are offsets from the first */ 718: /* calculate actual center and radius */ 719: axc = x1 + xc; 720: ayc = y1 + yc; 721: radius = (int)(hypot((double)xc, (double)yc) + .5); 722: if (dbg > 1) 723: { 724: printf("g_sizearc(%d, %d, %d, %d, %d, %d): radius is %d\n", 725: x1, y1, xc, yc, x2, y2, radius); 726: } 727: 728: /* preset the minmal and maximal points -- this is our first guess */ 729: if ((minx = x1 + xc + x2) > x1) 730: { 731: maxx = minx; 732: minx = x1; 733: } 734: else 735: { 736: maxx = x1; 737: } 738: if ((miny = y1 + yc + y2) > y1) 739: { 740: maxy = miny; 741: miny = y1; 742: } 743: else 744: { 745: maxy = y1; 746: } 747: 748: /* calculate the offset from the center to the first point */ 749: x1 = -xc; 750: y1 = -yc; /* now all three arguments are offsets */ 751: 752: /* calculate the quadrant of each endpoint */ 753: quad1 = quadrant(x1, y1); 754: quad2 = quadrant(x2, y2); 755: if (dbg > 1) 756: { 757: printf("(%d, %d) in quadrant %d ... ", x1, y1, quad1); 758: printf("(%d, %d) in quadrant %d\n", x2, y2, quad2); 759: } 760: 761: /* insure that quad1 < quad2 */ 762: if (quad2 < quad1) 763: { 764: quad2 += 4; 765: } 766: 767: /* compensate for arc at each quadrant boundary */ 768: for (i = quad1 + 1; i <= quad2; i++) 769: { 770: switch (i & 3) 771: { 772: case 0: /* 1st quadrant */ 773: maxx = axc + radius; 774: break; 775: 776: case 1: /* 2nd quadrant */ 777: miny = ayc - radius; 778: break; 779: 780: case 2: /* 3rd quadrant */ 781: minx = axc - radius; 782: break; 783: 784: case 3: /* 4th quadrant */ 785: maxy = ayc + radius; 786: break; 787: } 788: } 789: 790: /* now set the extremes */ 791: if (dbg > 1) 792: { 793: printf("extremes are %d, %d, %d, %d\n", minx, miny, maxx, maxy); 794: } 795: gobj_size(minx, miny, maxx, maxy); 796: } 797: 798: quadrant(dx, dy) 799: int dx,dy; 800: { 801: register int yplus; 802: 803: yplus = dy > 0; 804: if (dx > 0) 805: { 806: return(yplus ? 3 : 0); 807: } 808: else 809: { 810: return(yplus ? 2 : 1); 811: } 812: } 813: 814: 815: g_sizeWigglyLine(str) 816: char *str; 817: { 818: int minx; 819: int miny; 820: int maxx; 821: int maxy; 822: int currx; 823: int curry; 824: int incx; 825: int incy; 826: 827: currx = minx = maxx = hor_pos; 828: curry = miny = maxy = ver_pos; 829: 830: while(white(*str)) str++; /* trim leading white space */ 831: 832: while (*str) 833: { 834: 835: (void) readNumber(&str,&incx); 836: (void) readNumber(&str,&incy); 837: currx += incx; 838: curry += incy; 839: if (currx > maxx) 840: maxx = currx; 841: else if (currx < minx) 842: minx = currx; 843: if (curry > maxy) 844: maxy = curry; 845: else if (curry < miny) 846: miny = curry; 847: } 848: gobj_size(minx, miny, maxx, maxy); 849: }