/* Output from p2c, the Pascal-to-C translator */ /* From input file "textyl.p" */ #include "defs.h" #include "globals.h" #include "tables.h" extern int abs PP((int)); /*---------------------------------------------------------- TeXtyl line-drawing interface for TeX. copyright (c) 1987 John S. Renner All rights reserved. ABSTRACT: TeXtyl reads in a DVI file, and processes 'specials' that refer to graphics capabilities that it knows about, like line, spline, ThickThinSpline, and musical beams and slurs. TeXtyl then outputs a new DVI file, with the special-macros expanded and converted to DVI-commands for character setting. DEPENDENCIES: Few assumptions about Pascal are assumed. All identifiers are unique to eight characters. There are notes to indicate system-dependencies. I assume the standard definition of "READ(fil, x)" to be equivalent to "x := fil^; GET(fil)" , and "WRITE(fil, x)" == "fil^ := x; PUT(fil)" . Arrays are passed by reference (VAR) for efficiency. See also the "sysdependent" procedure; Problem areas, or areas for expansion are marked with ### -------------------------------------------------------------*/ /*-Revision History: Jun. 1986 v1.0 Basic version of TeXtyl Dec. 1986 v1.1 Added adaptive subdivision for spline interpolation. Added Cardinal basis. Mar. 1987 v1.2 Added F and W flags for beginfigure to allow required and/or actual dimensions to interface with files output by the DP drawing program from Carnegie-Mellon also various fixes Apr. 1987 v1.3 Added linestyles (dotted, dashed, dotdashed) Aug. 1991 Translated to C with p2c, then hacked a bit. (Ken Yap) */ /* ===========================TYPES============================= */ /* ---- PUBLIC types ---- */ typedef int MusIndex; typedef int SplineSegments[MAXSPLINESEGS][2]; /* ----- Private Types ---- */ typedef struct FontInfRec { int32 Cht, Cdp, Cwd; double Angle; } FontInfRec; /* vector font info */ typedef struct VectFontInfRec { VectKind vkind; int32 DesSize, PenSize; VThickness psize; int32 MaxVectLen; charstring FontName; int32 Cksum; int Isdefined; int32 DVIFontNum; FontInfRec FontInfo[128]; } VectFontInfRec; /* music font info */ typedef struct MusFontInfRec { int32 DesSize, Family; charstring FontName; int32 Cksum; int Isdefined; int32 DVIFontNum, Staffsize, ghu, gvu; FontInfRec FontInfo[128]; } MusFontInfRec; /* * representation of list of fonts that have to be defined * before we output the BOP of the page we just scanned */ typedef struct ToBeDefinedRec { char which; int32 indx; } ToBeDefinedRec; /* ==============================VARS============================ */ /* ----- Private vars */ static int32 ourxpos; /* internal x-position on page */ static int32 ourypos; /* internal y-position on page */ static VectFontInfRec *VFontTable[SizVFontTable]; static MusFontInfRec *MFontTable[SizMFontTable]; /* the font tables, and the number of fonts defined in each */ static int32 VFontsDefd, MFontsDefd, LFontsDefd; static int GDVIFN = 301; /* dvi font number currently in use */ /* table of fonts yet To-Be-Defined */ static ToBeDefinedRec TBD[MAXTBDs]; static int32 FTBDs; /* number of fonts to be defined for current page */ static Item *pageitems; /* * list of primitives in current use in the current figure on the current page */ static int32 specstart = 0; /* * the place in the DVI buffer where the start of the special begins. * this is so that we know how far to back up and over-write * the old \special macro string with the cmds of our 'macro-expansion' */ static int32 multifigure; /* depth of definition recursion of figures */ static int skiptsclamp; /* DEBUG: should we skip post-clamping ties */ static int ErrorOccurred; /* global flag in case some error happened */ /* ----- End private vars */ static short tfm[TFMSIZE + 101]; static char s = 0; struct stackrec { int32 sh, sv, sw, sx, sy, sz; } stack[STACKSIZE + 1]; static int32 inwidth[256]; static int32 tfmchecksum; static double conv, trueconv; static int32 numerator, denominator; static double mag, magfactor; static int32 maxv, maxh, maxs, maxpages = 10000, totalpages; static double resolution = 300.0; static int inpostamble; static int32 newbackptr = -1, oldbackptr = -1, p, k; /* forward declarations */ static void definebeams PP((MusFontInfRec ** M)); static void definevectors PP((VectFontInfRec ** Vec)); static jmp_buf _JL666; static int opentfmfile(tfmname) charstring tfmname; { charstring thefilename; char *path, *p, *q, *getenv PP((char *)); if ((path = getenv("TEXFONTS")) == 0) path = DEFTEXFONTS; if (tfmfile != NULL) { fclose(tfmfile); tfmfile = NULL; } for (p = path; p != 0 && tfmfile == NULL; p = q ? q + 1 : 0) { if ((q = strchr(p, ':')) == 0) strcpy(thefilename, p); else strncpy(thefilename, p, q - p); strcat(thefilename, "/"); if (strcmp(thefilename, "./") == 0) thefilename[0] = '\0'; strcat(thefilename, tfmname); tfmfile = fopen(thefilename, "r"); } return (tfmfile != NULL); } void jumpout() { longjmp(_JL666, 1); /* global label */ } void complain(severity) int severity; { fprintf(logfile, "Error in fig#%ld on page %ld\n", pgfigurenum, currpagenum); switch (severity) { case ERRNOTBAD: putc(ERRSIGNAL, logfile); break; case ERRBAD: putc(ERRSIGNAL, logfile); ErrorOccurred = true; break; case ERRREALBAD: fprintf(logfile, "%c! ", ERRSIGNAL); ErrorOccurred = true; break; } } double float_(i) int32 i; { return ((double) i); } static int tolowercase(let) int let; { return (isupper(let) ? tolower(let) : let); } #define streq(a,b,n) (!strncmp((a),(b),(n))) /* * Move the current DVI position to posx, posy by moving relatively from our current position and store the new position */ void isetpos(posx, posy) int posx, posy; { ScaledPts dy, dx; int32 numbytes; dx = posx - ourxpos; dy = posy - ourypos; numbytes = 1; if (dx < 128 && dx >= -128) numbytes = 1; else if (dx < 32768 && dx >= -32768) numbytes = 2; else if (dx < TWO23 && dx >= -TWO23) numbytes = 3; else if (dx < TWO31 && dx >= -TWO31) numbytes = 4; else { complain(ERRREALBAD); fprintf(logfile, "Panic: dx is too big/small in isetpos: %12ld\n", dx); } cmd1byte(RIGHTLEFT + numbytes - 1); /* number of bytes in its arg list */ cmdSigned(dx, numbytes); numbytes = 1; if (dy < 128 && dy >= -128) numbytes = 1; else if (dy < 32768 && dy >= -32768) numbytes = 2; else if (dy < TWO23 && dy >= -TWO23) numbytes = 3; else if (dy < TWO31 && dy >= -TWO31) numbytes = 4; else { complain(ERRREALBAD); fprintf(logfile, "Panic: dy is too big/small in isetpos: %12ld\n", dy); } cmd1byte(DOWNUP + numbytes - 1); cmdSigned(dy, numbytes); ourxpos = posx; ourypos = posy; } /* put out a character */ static void iputchar(charno) int charno; { cmd1byte(PUT1); cmd1byte(charno); } /* * set the font number, but only if it is different than the last one * we accessed. */ void isetfont(DVINum) int DVINum; { if (ourfontnum == DVINum) return; cmd1byte(USEFONT); cmd2byte(DVINum); ourfontnum = DVINum; } /* Assumes that the correct font is currently set */ static void Tyldot(dotx, doty) int32 dotx, doty; { if (dotx != 0 && doty != 0) isetpos(dotx, doty); iputchar(DOTCHAR); } /* * ### Note: "pageitems" could be extended to be a list * { of macrodefinitions which contain primitives , and { then could be * instanced. E.g., a library of common { figures callable from \special level */ void pushItem(depth, newthing) int depth; Item *newthing; { Item *i, *p; if (pageitems == NULL) { if (newthing->kind == Afigure) { pageitems = newthing; return; } pageitems = NewItem(Afigure); pageitems->UU.U8.depthnumber = depth; } /* Assume that pageitems points to Afigure */ /* traverse the list */ i = pageitems; /* point to front of list for now */ p = i->UU.U8.body->things; while (p != NULL) { if (depth == i->UU.U8.depthnumber) { /* simple push */ /* * Note: this is the case when pushing another figure item onto * an already-existing list. We push the * newfigure with a depth of (fig^.depthnumber - 1) because * it really is part of the higer-level figure */ break; } if (depth <= i->UU.U8.depthnumber) continue; /* there MUST be a figure with a higher number deeper */ while (p->kind != Afigure && p->nextitem != NULL) p = p->nextitem; if (p->kind == Afigure) { i = p; p = i->UU.U8.body->things; } else { complain(ERRREALBAD); fprintf(logfile, "OOPS p^.kind isnt a figure. It must be near endoflist\n"); } } /* * we have the correct front of list-list, and i points to Afigure item */ newthing->nextitem = p; i->UU.U8.body->things = newthing; } static double Tgetfixword(k) int k; { short a; int32 f; a = tfm[k + 100] * 16 + tfm[k + 101] / 16; f = ((tfm[k + 101] & 15) * 256 + tfm[k + 102]) * 256 + tfm[k + 103]; if (a <= 2047) return (a + (double) f / TWO20); a = 4096 - a; if (f > 0) { f = TWO20 - f; a--; } return (a + (double) f / TWO20); } static int32 TgetSigned(k) int k; { int32 i; i = tfm[k + 100]; if (i < 128) i -= 256; return (((i * 256 + tfm[k + 101]) * 256 + tfm[k + 102]) * 256 + tfm[k + 103]); } /* * open a .tfm file and return the parameters in it. * Used only in conjuction with the vector and music fonts */ static void gettfm(tfmfilnam, dessize, p1, p2, p3, p4, p5, p6, p7, cksum) charstring tfmfilnam; int32 *dessize, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *cksum; { int32 tfmptr, lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np, charbase, widthbase, heightbase, depthbase, italicbase, ligkernbase, kernbase, extenbase, parambase; ScaledPts tempdesignsize; *p1 = 0; *p2 = 0; *p3 = 0; *p4 = 0; *p5 = 0; *p6 = 0; *p7 = 0; *cksum = -1; if (!opentfmfile(tfmfilnam)) { complain(ERRREALBAD); fprintf(logfile, "%s---not loaded, TFM file can't be opened!\n", tfmfilnam); jumpout(); } tfm[100] = Tgetc(); tfm[101] = Tgetc(); lf = tfm[100] * 256 + tfm[101]; if (lf * 4 - 1 > TFMSIZE) { complain(ERRREALBAD); fprintf(logfile, "The tfm file:%s is bigger than I can handle!\n", tfmfilnam); return; } for (tfmptr = 102; tfmptr <= lf * 4 + 99; tfmptr++) tfm[tfmptr] = Tgetc(); tfmptr = 2; lh = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; bc = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; ec = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; nw = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; nh = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; nd = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; ni = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; nl = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; nk = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; ne = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; np = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101]; tfmptr += 2; if (lf != lh + ec - bc + nw + nh + nd + ni + nl + nk + ne + np + 7) { complain(ERRREALBAD); fprintf(logfile, "%s: subfile sizes don't add up to the stated total!\n", tfmfilnam); fprintf(logfile, "Sorry, but I can't go on; are you sure this is a TFM?\n"); return; } if (bc > ec + 1 || ec > 255) { complain(ERRREALBAD); fprintf(logfile, "The character code range %ld..%ld is illegal!\n", bc, ec); fprintf(logfile, "Sorry, but I can't go on; are you sure this is a TFM?\n"); return; } charbase = lh - bc + 6; widthbase = charbase + ec + 1; heightbase = widthbase + nw; depthbase = heightbase + nh; italicbase = depthbase + nd; ligkernbase = italicbase + ni; kernbase = ligkernbase + nl; extenbase = kernbase + nk; parambase = extenbase + ne - 1; *dessize = (int32) floor(Tgetfixword(28) * SPPERPT + 0.5); /* now in ScaledPts */ tempdesignsize = (int32) floor(*dessize * magfactor + 0.5); *cksum = TgetSigned(24); /* return the special 7 parameters for the font */ *p1 = (int32) floor(Tgetfixword((parambase + 1) * 4) * tempdesignsize + 0.5); *p2 = (int32) floor(Tgetfixword((parambase + 2) * 4) * tempdesignsize + 0.5); *p3 = (int32) floor(Tgetfixword((parambase + 3) * 4) * tempdesignsize + 0.5); *p4 = (int32) floor(Tgetfixword((parambase + 4) * 4) * tempdesignsize + 0.5); *p5 = (int32) floor(Tgetfixword((parambase + 5) * 4) * tempdesignsize + 0.5); *p6 = (int32) floor(Tgetfixword((parambase + 6) * 4) * tempdesignsize + 0.5); *p7 = (int32) floor(Tgetfixword((parambase + 7) * 4) * tempdesignsize + 0.5); } static void initVnMnLtables() { int32 i; for (i = 0; i < SizVFontTable; i++) VFontTable[i] = NULL; for (i = 0; i < SizMFontTable; i++) MFontTable[i] = NULL; for (i = 0; i < SizLFontTable; i++) LFontTable[i] = NULL; VFontsDefd = 0; MFontsDefd = 0; LFontsDefd = 0; } static void fonttobedefined(kind, findex) char kind; int findex; { FTBDs++; /* * reset this to zero after outputting 1. fontdefs 2. bop * 3. contents of dvi page 4. eop */ TBD[FTBDs - 1].which = kind; TBD[FTBDs - 1].indx = findex; } static void enterfont(fontnum, ck, scalefact, dessiz, nam) int32 fontnum, ck, scalefact, dessiz; charstring nam; { int32 n, len; cmd1byte(FONTDEF); cmd2byte(fontnum); cmd4byte(ck); cmd4byte(scalefact); cmd4byte(dessiz); cmd1byte(USESTDAREA); cmd1byte(len = strlen(nam) - 4);/* skip the length of the .tfm suffix */ for (n = 0; n < len; n++) /* skip the .tfm suffix */ cmd1byte(nam[n]); } static void Outputfont(fontnum, ck, scalefact, dessiz, nam) int32 fontnum, ck, scalefact, dessiz; charstring nam; { int32 n, len; OutputByte(FONTDEF); Output2Byte(fontnum); Output4Byte(ck); Output4Byte(scalefact); Output4Byte(dessiz); OutputByte(USESTDAREA); /* dont output the default dir prefix, nor the .tfm suffix */ OutputByte(len = strlen(nam) - 4); for (n = 0; n < len; n++) OutputByte(nam[n]); } void defineNewfonts() { /* * this needs to be done before first access to a font * on a page later someone else will have to re-define all of them * in the postamble */ int32 i, f, FORLIM; VectFontInfRec *WITH; MusFontInfRec *WITH1; LabFontInfRec *WITH2; FORLIM = FTBDs; for (i = 0; i < FORLIM; i++) { if (TBD[i].which == 'V') { f = TBD[i].indx; WITH = VFontTable[f - 1]; /* with */ if (WITH->Isdefined) continue; Outputfont(WITH->DVIFontNum, WITH->Cksum, WITH->DesSize, WITH->DesSize, WITH->FontName); WITH->Isdefined = true; } /* if */ else if (TBD[i].which == 'M') { f = TBD[i].indx; WITH1 = MFontTable[f - 1]; /* with */ if (WITH1->Isdefined) continue; Outputfont(WITH1->DVIFontNum, WITH1->Cksum, WITH1->DesSize, WITH1->DesSize, WITH1->FontName); WITH1->Isdefined = true; } else if (TBD[i].which == 'L') { f = TBD[i].indx; WITH2 = LFontTable[f - 1]; /* with */ if (WITH2->Isdefined) /* ### is this right? */ continue; Outputfont(WITH2->DVIFontNum, WITH2->Cksum, WITH2->DesSize, WITH2->DesSize, WITH2->FontName); WITH2->Isdefined = true; } else { complain(ERRREALBAD); fprintf(logfile, "Unknown type of font to be defined:\"%c\"\n", TBD[i].which); } } } static int32 GetMusFont(stfsiz, fam) int32 stfsiz, fam; { charstring mustfmnam; MusIndex i; ScaledPts design, p1, p2, p3, p4, linesp, gwidth, p7; int32 cksm, FORLIM; MusFontInfRec *WITH; /* see if it already exists */ FORLIM = MFontsDefd; for (i = 1; i <= FORLIM; i++) { /* loop through since there are few */ WITH = MFontTable[i - 1]; if (WITH->Staffsize == stfsiz && WITH->Family == fam) return (i); } sprintf(mustfmnam, "mus%c%c.tfm", stfsiz + '0', fam + '0'); gettfm(mustfmnam, &design, &p1, &p2, &p3, &p4, &linesp, &gwidth, &p7, &cksm); MFontsDefd++; if (MFontsDefd > SizMFontTable) { complain(ERRREALBAD); fprintf(logfile, "%s---not loadable. Size of Music Font table too small\n", mustfmnam); jumpout(); } i = MFontsDefd; MFontTable[i - 1] = (MusFontInfRec *) xmalloc(sizeof(MusFontInfRec)); WITH = MFontTable[i - 1]; WITH->Staffsize = stfsiz; WITH->Family = fam; WITH->DesSize = design; strcpy(WITH->FontName, mustfmnam); WITH->Cksum = cksm; WITH->ghu = (int32) floor(gwidth / QNOTEGHUS + 0.5); WITH->gvu = (int32) floor(linesp / QNOTEGVUS + 0.5); WITH->DVIFontNum = GDVIFN++; WITH->Isdefined = false; /* call someone to do the defns of cdp, cht, cwd foreach beam */ definebeams(&MFontTable[i - 1]); fonttobedefined('M', i); return (i); } int32 GetVectFont(size, vk) VThickness size; VectKind vk; { charstring vectfmnam; VecIndex i; ScaledPts design, p1, p2, w0, w1, maxveclen, p6, p7; int32 cksm, r, FORLIM; VectFontInfRec *WITH; /* see if it already exists */ FORLIM = VFontsDefd; for (i = 1; i <= FORLIM; i++) { /* with */ WITH = VFontTable[i - 1]; if (WITH->psize == size && WITH->vkind == vk) return (i); } switch (vk) { case VKCirc: r = 'c'; break; case VKVert: r = 'v'; break; case VKHort: r = 'h'; break; } sprintf(vectfmnam, "%cvec%d.tfm", r, size); gettfm(vectfmnam, &design, &p1, &p2, &w0, &w1, &maxveclen, &p6, &p7, &cksm); VFontsDefd++; if (VFontsDefd > SizVFontTable) { complain(ERRREALBAD); fprintf(logfile, "%s---not loadable. Size of Vector Font table too small\n", vectfmnam); jumpout(); } i = VFontsDefd; VFontTable[i - 1] = (VectFontInfRec *) xmalloc(sizeof(VectFontInfRec)); WITH = VFontTable[i - 1]; WITH->vkind = vk; WITH->psize = size; WITH->DesSize = design; if (vk == VKVert) WITH->PenSize = w1; else WITH->PenSize = w0; WITH->PenSize = (int32) floor(size * (MAXVECLENsp / 16.0) + 0.5); WITH->MaxVectLen = maxveclen; strcpy(WITH->FontName, vectfmnam); WITH->Cksum = cksm; WITH->Isdefined = false; WITH->DVIFontNum = GDVIFN++; definevectors(&VFontTable[i - 1]); /* someone asked for it, so they must want it, and we should fntdef it */ fonttobedefined('V', i); return (i); } /*----------------------------------------------------------*/ int32 GetLabFont(style) int32 style; { charstring labtfmnam; int32 i, cksm, FORLIM; ScaledPts design, p1, space, p3, p4, p5, p6, p7; LabFontInfRec *WITH; if (style > MAXLABELFONTS) style = 1; FORLIM = LFontsDefd; for (i = 1; i <= FORLIM; i++) { WITH = LFontTable[i - 1]; if (WITH->internalnumber == style) return (i); } switch (style) { case 1: /* cmtt10 */ strcpy(labtfmnam, "cmtt10"); break; case 2: /* cmb10 */ strcpy(labtfmnam, "cmb10"); break; case 3: /* cmsl10 */ strcpy(labtfmnam, "cmsl10"); break; case 4: /* cmtt8 */ strcpy(labtfmnam, "cmtt8"); break; case 5: /* cmsl8 */ strcpy(labtfmnam, "cmsl8"); break; } strcat(labtfmnam, ".tfm"); gettfm(labtfmnam, &design, &p1, &space, &p3, &p4, &p5, &p6, &p7, &cksm); LFontsDefd++; if (LFontsDefd > SizLFontTable) { complain(ERRREALBAD); fprintf(logfile, "%s---not loadable. Size of Label Font table too small\n", labtfmnam); jumpout(); } i = LFontsDefd; LFontTable[i - 1] = (LabFontInfRec *) xmalloc(sizeof(LabFontInfRec)); WITH = LFontTable[i - 1]; /* with */ strcpy(WITH->FontName, labtfmnam); WITH->Cksum = cksm; WITH->DesSize = design; WITH->internalnumber = style; WITH->spacewidth = space; WITH->DVIFontNum = GDVIFN++; WITH->Isdefined = false; fonttobedefined('L', i); return (i); } static double vectangle(dx, dy) int32 dx, dy; { if (dx != 0) return (atan(dy / (double) dx) * RADTODEG); else return (dy > 0 ? 90.0 : -90.0); } static void definevectors(Vec) VectFontInfRec **Vec; { /* var Vec: pVectFontInfRec */ int i; double units; VectFontInfRec *V; FontInfRec *F; struct vecinfo *v; V = *Vec; units = V->MaxVectLen / 16.0; for (i = 0, F = V->FontInfo, v = vectab; i < 128; ++i, ++F, ++v) { F->Cht = floor(v->Cht * units + 0.5); F->Cdp = floor(v->Cdp * units + 0.5); F->Cwd = floor(v->Cwd * units + 0.5); F->Angle = v->Angle; } } /* * If, for some reason, you do not want to deal with music capabilities, * replace the body of this procedure with just a begin * end; pair and also the TylBeam proc. */ static void definebeams(M) MusFontInfRec **M; { /* var M : pMusFontInfRec */ } #define UnitRadius 16777216/* TWO24 scaledpts */ /* * use pre-calculated coordinates of a circle that has a given unit-radius. * Scale those points to fit the desired radius */ void defineCircleCpts(rad, centx, centy, CircleCpt, numpts) int32 rad, centx, centy; int32 (*CircleCpt)[2]; int32 *numpts; { double ratio; if (rad == 0) { complain(ERRBAD); fprintf(logfile, "Error in fig#%ld on page %ld\n", pgfigurenum, currpagenum); fprintf(logfile, "Zero length radius for circle! Setting to 1 sp\n"); rad = 1; } ratio = float_(rad) / float_(UnitRadius); *numpts = 16; CircleCpt[1][0] = (int32) floor(ratio * 16777216.00000 + 0.5) + centx; CircleCpt[1][1] = centy;/* round (ratio * 0.00000) */ CircleCpt[2][0] = (int32) floor(ratio * 15500126.47492 + 0.5) + centx; CircleCpt[2][1] = (int32) floor(ratio * 6420362.60441 + 0.5) + centy; CircleCpt[3][0] = (int32) floor(ratio * 11863283.20303 + 0.5) + centx; CircleCpt[3][1] = (int32) floor(ratio * 11863283.20303 + 0.5) + centy; CircleCpt[4][0] = (int32) floor(ratio * 6420362.60441 + 0.5) + centx; CircleCpt[4][1] = (int32) floor(ratio * 15500126.47492 + 0.5) + centy; CircleCpt[5][0] = centx;/* round (ratio * -0.00000) */ CircleCpt[5][1] = (int32) floor(ratio * 16777216.00000 + 0.5) + centy; CircleCpt[6][0] = (int32) floor(0.5 - ratio * 6420362.60441) + centx; CircleCpt[6][1] = (int32) floor(ratio * 15500126.47492 + 0.5) + centy; CircleCpt[7][0] = (int32) floor(0.5 - ratio * 11863283.20303) + centx; CircleCpt[7][1] = (int32) floor(ratio * 11863283.20303 + 0.5) + centy; CircleCpt[8][0] = (int32) floor(0.5 - ratio * 15500126.47492) + centx; CircleCpt[8][1] = (int32) floor(ratio * 6420362.60441 + 0.5) + centy; CircleCpt[9][0] = (int32) floor(0.5 - ratio * 16777216.00000) + centx; CircleCpt[9][1] = centy;/* round (ratio * -0.00000) */ CircleCpt[10][0] = (int32) floor(0.5 - ratio * 15500126.47492) + centx; CircleCpt[10][1] = (int32) floor(0.5 - ratio * 6420362.60441) + centy; CircleCpt[11][0] = (int32) floor(0.5 - ratio * 11863283.20303) + centx; CircleCpt[11][1] = (int32) floor(0.5 - ratio * 11863283.20303) + centy; CircleCpt[12][0] = (int32) floor(0.5 - ratio * 6420362.60441) + centx; CircleCpt[12][1] = (int32) floor(0.5 - ratio * 15500126.47492) + centy; CircleCpt[13][0] = centx; /* round (ratio * 0.00000) */ CircleCpt[13][1] = (int32) floor(0.5 - ratio * 16777216.00000) + centy; CircleCpt[14][0] = (int32) floor(ratio * 6420362.60441 + 0.5) + centx; CircleCpt[14][1] = (int32) floor(0.5 - ratio * 15500126.47492) + centy; CircleCpt[15][0] = (int32) floor(ratio * 11863283.20303 + 0.5) + centx; CircleCpt[15][1] = (int32) floor(0.5 - ratio * 11863283.20303) + centy; CircleCpt[16][0] = (int32) floor(ratio * 15500126.47492 + 0.5) + centx; CircleCpt[16][1] = (int32) floor(0.5 - ratio * 6420362.60441) + centy; /* create the pre-list phantom */ CircleCpt[0][0] = CircleCpt[16][0]; CircleCpt[0][1] = CircleCpt[16][1]; } #undef UnitRadius /* * compute control points for an arc going from startangle to stopangle, centered at (centx, centy) */ void definearcpts(rad, centx, centy, startang, stopang, cpts, nknots) int32 rad, centx, centy, startang, stopang; int32 (*cpts)[2]; int32 *nknots; { int32 n; double a, b, curr, delta; int32 i; a = startang * DEGTORAD; b = stopang * DEGTORAD; n = 16; if (a > b) a -= 2 * PI; delta = fabs(b - a) / n; if (a == b) { complain(ERRNOTBAD); fprintf(logfile, "Error in compute arc points:: should be a circle\n"); } curr = a; i = 1; while (curr <= b) { /* make arc about (centx,centy) */ cpts[i][0] = (int32) floor(rad * cos(curr) + 0.5) + centx; cpts[i][1] = (int32) floor(rad * sin(curr) + 0.5) + centy; i++; curr += delta; } /* * go one point beyond -- around the arc so that we can have * good smoothness for this phantom point */ cpts[i][0] = (int32) floor(rad * cos(b + delta) + 0.5) + centx; cpts[i][1] = (int32) floor(rad * sin(b + delta) + 0.5) + centy; /* and one phantom point before the list */ cpts[0][0] = (int32) floor(rad * cos(a - delta) + 0.5) + centx; cpts[0][1] = (int32) floor(rad * sin(a - delta) + 0.5) + centy; *nknots = i - 1; } static int isaletter(b) int b; { return (isalpha(b) || b == '@' || b == '"'); } static int getnumber(cpp) char **cpp; { int n; int isneg; n = 0; isneg = false; for ( ; **cpp != '\0' && (!isdigit(**cpp)); ++*cpp) if (**cpp == '-') isneg = true; while (isspace(**cpp)) /* Skip spaces */ ++*cpp; for ( ; **cpp != '\0' && isdigit(**cpp); ++*cpp) n = n * 10 + **cpp - '0'; return (isneg ? -n : n); } static int getletter(cpp) char **cpp; { char *cp; cp = *cpp; /* non letter */ for (cp = *cpp; *cp != '\0' && !isaletter(*cp) && !isspace(*cp); ++cp) ; if (*cp != '\0' && (isaletter(*cp) || (isspace(*cp) && !isdigit(*cp)))) { *cpp = cp + 1; return (*cp); } return (' '); } static int getanything(cpp) char **cpp; { char c; if ((c = **cpp) != '\0') { ++*cpp; return (c); } return (' '); } /***************************************************** The following routines look for key - letter tokens that indicate certain attributes for a primitive. Currently, the letters used are: Sfor scaled-points measurement Pfor printers points Mmillimeters measurement Cuse a Circular vector for drawing HHorizontal-pen vector VVertical vector BB-spline IInterpolating B-spline KCatmull-Rom spline DCardinal spline UOpen spline Oclosed spline Xput marks on spline control pts TTransformation marker RRegular beam characters GGrace Beam characters @Specify center-point for arc/circle LLine-style Ffor beginfigure: Fit figure to wid/ht Wfor beginfigure: figure was created at this wid & ht ***************************************************/ static void gettransforms(sc1, sc2, r, tr1, tr2, cpp) double *sc1, *sc2, *r; int32 *tr1, *tr2; char **cpp; { char *cp; *sc1 = 1.0; *sc2 = 1.0; *tr1 = 0; *tr2 = 0; *r = 0.0; for (cp = *cpp; *cp != '\0'; ++cp) { if (*cp == 't' || *cp == 'T') { if (!isaletter(cp[-1]) && !isaletter(cp[1])) { /* get transform parameters and modify ptr */ *cpp = cp; *sc1 = getnumber(cpp) / 100.0; *sc2 = getnumber(cpp) / 100.0; *tr1 = getnumber(cpp); *tr2 = getnumber(cpp); *r = float_(getnumber(cpp)); /* degrees about primitive center */ if (*r < 0.0) *r += 360.0; break; } } } } static int findmarker(set, cp) char *set; char *cp; { for ( ; *cp != '\0'; ++cp) { if (strchr(set, *cp)) if (!isaletter(cp[-1]) && !isaletter(cp[1])) return (tolowercase(*cp)); } return (0); } #define findscale(p) findmarker("sSpPmM", p) #define findvectkind(p) findmarker("cChHvV", p) #define findlinestyle(p) findmarker("lL", p) #define findbeamkind(p) findmarker("rRgG", p) #define findsplinekind(p) findmarker("bBiIkKdD", p) #define findsplclosure(p) findmarker("oOuU", p) #define findatsign(p) findmarker("@", p) #define finddotmark(p) findmarker("xX", p) #define findfigdimens(p) findmarker("wW", p) #define findfitsizes(p) findmarker("fF", p) static double thescaleof(scal) int32 scal; { if (scal == 's') return (1 * magfactor); if (scal == 'p') return (SPPERPT * magfactor); if (scal == 'm') return (SPPERMM * magfactor); if (scal == 0) return (SPPERPT * magfactor); } static VectKind thevectorof(vkin) int32 vkin; { if (vkin == 'c') return VKCirc; if (vkin == 'v') return VKVert; if (vkin == 'h') return VKHort; if (vkin == 0) return VKCirc; } static LineStyle thestyleof(linest) int32 linest; { static LineStyle styletab[4] = {solid, dotted, dashed, dotdash}; if (linest > 3 || linest < 0) linest = 0; return (styletab[linest]); } static void tylspecials(cp) char *cp; { /* * specnum is the DVI-number of the special * nbytes is the number of parameter bytes */ int32 siz, numknots; /* Lots of temp vars that we use */ int32 x1, y1, x2, y2; double sx100, sy100, rot, SPscale; ScaledPts transx, transy, minx, miny, maxx, maxy; ControlPoints cpts; VThickness thk; LineStyle patt; ThickAryType TTary; VectKind vk; BeamKind bk; int32 markdiam, radius, ang1, ang2; charstring phrase; int32 style; char nam[5]; /* the first parameter of the \special */ char let; int32 i; Item *pi; int32 maxthk, minthk; SplineKind splinetype; int isclosedspline; int free PP((char *)); /* Lets look for a primitive to tyl */ for ( ; !isaletter(*cp) && *cp != '\0'; ++cp) ; /* get the name of the primitive */ for (i = 0; isaletter(*cp); ++cp) if (i < 4) nam[i++] = tolowercase(*cp); nam[i] = '\0'; /* --- BEGINFIGURE ---- */ if (streq(nam, "beginfigure", 3)) { multifigure++; i = findscale(cp); SPscale = thescaleof(i); gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp); /* * store all the primitives on pageitems, and dont output them * until we get a endfigure. this way, we can take * care of dealing with all the primitives according to some * global tranformation for the whole figure */ pi = NewItem(Afigure); pi->UU.U8.figtheta = rot; pi->UU.U8.fsx = sx100; pi->UU.U8.fsy = sy100; pi->UU.U8.fdx = (int32) floor(transx * SPscale + 0.5); pi->UU.U8.fdy = (int32) floor(transy * SPscale + 0.5); pi->UU.U8.depthnumber = multifigure; /* we're at a new level */ i = findfigdimens(cp); if (i != 0) { pi->UU.U8.preWid = (int32) floor(getnumber(&cp) * SPscale + 0.5); pi->UU.U8.preHt = (int32) floor(getnumber(&cp) * SPscale + 0.5); } i = findfitsizes(cp); if (i != 0) { /* with */ pi->UU.U8.postWid = (int32) floor(getnumber(&cp) * SPscale + 0.5); pi->UU.U8.postHt = (int32) floor(getnumber(&cp) * SPscale + 0.5); } BackupInBuf(DVIMark() - specstart); pushItem(multifigure - 1, pi); return; } /* ---- ENDFIGURE ---- */ if (streq(nam, "endfigure", 3)) { multifigure--; if (multifigure < 0) { complain(ERRBAD); fprintf(logfile, "Warning: Too many \"endfigure\"s !"); multifigure = 0; } BackupInBuf(DVIMark() - specstart); if (multifigure == 0) { /* go do our set of figures (within figures...) */ figurehandle(pageitems, pageitems, 1); free((char *)pageitems);/* #### should maybe garbage collect here */ pageitems = NULL; } /* if */ return; } /* --- LINE --- */ if (streq(nam, "line", 3)) { i = findscale(cp); SPscale = thescaleof(i); gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp); thk = getnumber(&cp); /* get the vector thickness */ if (thk < 1) { complain(ERRBAD); fprintf(logfile, "?? Thickness not found. Setting to 1\n"); thk = 1; } i = findvectkind(cp); vk = thevectorof(i); i = findlinestyle(cp); if (i != 0) patt = thestyleof(getnumber(&cp)); else patt = solid; x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5); y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5); x2 = (int32) floor(getnumber(&cp) * SPscale + 0.5); y2 = (int32) floor(getnumber(&cp) * SPscale + 0.5); minx = min(x1, x2); maxx = max(x1, x2); miny = min(y1, y2); maxy = max(y1, y2); BackupInBuf(DVIMark() - specstart); cmd1byte(OURFONTFLAG); linehandle(multifigure, SPscale, x1, y1, x2, y2, 0, 0, thk, vk, patt, minx, maxx, miny, maxy, transx, transy, sx100, sy100, rot); } /* line */ else if (streq(nam, "spline", 3) || streq(nam, "ttspline", 3)) { i = findscale(cp); SPscale = thescaleof(i); gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp); if (streq(nam, "spline", 3)) { thk = getnumber(&cp); if (thk < 1) { complain(ERRBAD); fprintf(logfile, "Spline Thickness not found. Setting to 1\n"); thk = 1; } } i = findvectkind(cp); vk = thevectorof(i); i = findlinestyle(cp); if (i != 0) patt = thestyleof(getnumber(&cp)); else patt = solid; i = findsplinekind(cp); if (i == 'b') splinetype = BSPL; else if (i == 'i') splinetype = INTBSPL; else if (i == 'k') splinetype = CATROM; else if (i == 'd') splinetype = CARD; else if (i == 0) splinetype = CATROM; i = findsplclosure(cp); if (i == 'o') isclosedspline = true; else if (i == 'u') isclosedspline = false; else if (i == 0) isclosedspline = false; i = finddotmark(cp); if (i == 'x') markdiam = getnumber(&cp); else if (i == 0) markdiam = 0; numknots = min(getnumber(&cp), (int32) MAXCTLPTS); if (numknots < 1) { complain(ERRBAD); fprintf(logfile, "Number of spline/ttspline knot points not found. Setting to 1\n"); numknots = 1; } minx = TWO24; miny = TWO24; maxx = -TWO24; maxy = -TWO24; for (i = 0; i <= numknots + 3; i++) { cpts[i][0] = 0; cpts[i][1] = 0; } /* for */ for (i = 1; i <= numknots; i++) { x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5); cpts[i][0] = x1; if (x1 < minx) minx = x1; if (x1 > maxx) maxx = x1; y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5); cpts[i][1] = y1; if (y1 < miny) miny = y1; if (y1 > maxy) maxy = y1; } /* for */ if (streq(nam, "ttspline", 3)) { for (i = 1; i <= numknots; i++) TTary[i] = getnumber(&cp); } BackupInBuf(DVIMark() - specstart); cmd1byte(OURFONTFLAG); if (streq(nam, "spline", 3)) splinehandle(multifigure, SPscale, splinetype, isclosedspline, markdiam, cpts, numknots, 0, 0, thk, vk, patt, minx, maxx, miny, maxy, transx, transy, sx100, sy100, rot); else ttsplhandle(multifigure, SPscale, splinetype, isclosedspline, markdiam, cpts, TTary, numknots, 0, 0, vk, patt, minx, maxx, miny, maxy, transx, transy, sx100, sy100, rot); } else if (streq(nam, "beam", 4)) { i = findscale(cp); SPscale = thescaleof(i); /* no transforms */ siz = getnumber(&cp); /* the staffsize */ i = findbeamkind(cp); if (i == 'g') bk = grace; else if (i == 'r') bk = regular; else if (i == 0) bk = regular; x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5); y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5); x2 = (int32) floor(getnumber(&cp) * SPscale + 0.5); y2 = (int32) floor(getnumber(&cp) * SPscale + 0.5); BackupInBuf(DVIMark() - specstart); cmd1byte(OURFONTFLAG); beamhandle(multifigure, siz, bk, x1, y1, x2, y2); } else if (streq(nam, "tieslur", 3)) { i = findscale(cp); SPscale = thescaleof(i); minthk = getnumber(&cp); if (minthk < 1) { complain(ERRBAD); fprintf(logfile, "Tie/Slur Min Thickness not found. Setting to 1\n"); minthk = 1; } maxthk = getnumber(&cp); if (maxthk < 1) { complain(ERRBAD); fprintf(logfile, "Tie/Slur MaxThickness not found. Setting to 1\n"); maxthk = 1; } numknots = min(getnumber(&cp), (int32) MAXCTLPTS); if (numknots < 1) { complain(ERRBAD); fprintf(logfile, "Tie/Slur Number of knot points not found. Setting to 1. Should be 5\n"); numknots = 1; } for (i = 1; i <= numknots; i++) { cpts[i][0] = (int32) floor(getnumber(&cp) * SPscale + 0.5); cpts[i][1] = (int32) floor(getnumber(&cp) * SPscale + 0.5); } /* for */ BackupInBuf(DVIMark() - specstart); cmd1byte(OURFONTFLAG); tieslurhandle(multifigure, cpts, numknots, (int) minthk, (int) maxthk); } else if (streq(nam, "arc", 3)) { i = findscale(cp); SPscale = thescaleof(i); gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp); thk = getnumber(&cp); if (thk < 1) { complain(ERRBAD); fprintf(logfile, "Arc Thickness not found. Setting to 1\n"); thk = 1; } i = findvectkind(cp); vk = thevectorof(i); i = findlinestyle(cp); if (i != 0) patt = thestyleof(getnumber(&cp)); else patt = solid; radius = (int32) floor(getnumber(&cp) * SPscale + 0.5); if (radius == 0) radius = (int32) floor(1 * SPscale + 0.5); i = findatsign(cp); if (i != 0) { x2 = (int32) floor(getnumber(&cp) * SPscale + 0.5); y2 = (int32) floor(getnumber(&cp) * SPscale + 0.5); } else { x2 = 0; y2 = 0; /* assume center at origin */ } ang1 = getnumber(&cp); if (abs(ang1) > 360) { ang1 %= 360; /* * p2c: x.p, line 5570: Note: Using % for possibly-negative arguments [317] */ } ang2 = getnumber(&cp); if (abs(ang2) > 360) { ang2 %= 360; /* * p2c: x.p, line 5573: Note: Using % for possibly-negative arguments [317] */ } minx = TWO24; miny = TWO24; maxx = -TWO24; maxy = -TWO24; if (ang1 == ang2) /* a circle */ defineCircleCpts(radius, x2, y2, cpts, &numknots); else /* a real arc */ definearcpts(radius, x2, y2, ang1, ang2, cpts, &numknots); for (i = 1; i <= numknots; i++) { x1 = cpts[i][0]; if (x1 < minx) minx = x1; if (x1 > maxx) maxx = x1; y1 = cpts[i][1]; if (y1 < miny) miny = y1; if (y1 > maxy) maxy = y1; } /* for */ BackupInBuf(DVIMark() - specstart); cmd1byte(OURFONTFLAG); arccirclehandle(multifigure, SPscale, x2, y2, radius, ang1, ang2, cpts, numknots, 0, 0, thk, vk, patt, minx, maxx, miny, maxy, transx, transy, sx100, sy100, rot); } else if (streq(nam, "label", 3)) { i = findscale(cp); SPscale = thescaleof(i); style = getnumber(&cp); /* font style number */ if (style < 1 || style > MAXLABELFONTS) { complain(ERRBAD); fprintf(logfile, "Label style bad? Setting to Style 1\n"); style = 1; } x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5); y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5); let = getletter(&cp); while (let != '"') let = getletter(&cp); let = getanything(&cp); /* get next letter or whatever */ for (i = 0; let != '"'; ++i) { /* get the label phrase */ phrase[i] = let; let = getanything(&cp); /* getletter; */ } phrase[i] = '\0'; BackupInBuf(DVIMark() - specstart); cmd1byte(OURFONTFLAG); labelhandle(multifigure, SPscale, x1, y1, 0, 0, style, phrase, 0, 0); } else if (streq(nam, "param", 3)) { i = getnumber(&cp); /* addressable param number */ fprintf(logfile, " I do not know what internal parameter #%ld is\n", i); /* else */ BackupInBuf(DVIMark() - specstart); } else { complain(ERRNOTBAD); fprintf(logfile, "Sorry, I don't know how to tyl %s\n", nam); } } static int otherspecials(cp) char *cp; { fprintf(logfile, "Special: %s\n", cp); return (1); } static void mainhandlespecials(specnum, nbytes) int32 specnum, nbytes; { /* * specnum is the DVI-number of the special * nbytes is the number of parameter bytes */ char sysnam[4]; char *cp, *buf; int32 i; char *malloc PP((unsigned)); int free PP((char *)); specstart = DVIMark() - specnum + 237; ourxpos = h; ourypos = v; /* note the global DVI (h,v) coords */ cp = buf = malloc((unsigned)(nbytes + 1)); for (i = 0; i < nbytes; ++i) cp[i] = Dget1byte(); cp[i] = '\0'; while (isspace(*cp)) ++cp; /* get the name of the system --- Hopefully 'tyl' */ for (i = 0; *cp != '\0' && *cp != ' '; ++cp) if (i < 3) sysnam[i++] = tolowercase(*cp); sysnam[i] = '\0'; /* end of string */ if (streq(sysnam, "tyl", 3)) tylspecials(cp); else if (otherspecials(buf)) ; else fprintf(logfile, "Unknown special ignored: %s\n", buf); free((char *)buf); } /* * ================================================== * * The routines below assume coordinates are already in 4th Quadrant DVI-space * * ===================================================== */ /* * returns 0 if dy.dx not in font 1 if ok 2 if ok and caller should use two of the "code"s coding scheme requires 0<= [dx, dy] * <= 16 AND that max(dx, abs(dy)) is in [0,1,2,4,8,16] */ static int32 outvector(dx, dy, code) int32 dx, dy, *code; { int32 c, result; if (dx < 0) return (0); result = 0; /* init for potential failure */ *code = -1; if (dy < 0) c = dy + dx - max(dx, -dy) * 9 + 160; else c = dy - dx - max(dx, dy) * 7 + 160; /* * here translate to OUR coding scheme and return the correct number * this is needed because "c" thinks the char range * is 0 to 160, while we have only 128 chars */ if (c == 0) { /* special cases */ *code = 63; result = 2; } else if (c == 64) { *code = 95; result = 2; } else { result = 1; /* just one char is fine */ if (c >= 1 && c <= 63) /* c - 33 */ *code = c - 1; else if (c >= 80 && c <= 112) *code = c - 17; else if (c >= 120 && c <= 136) *code = c - 24; else if (c >= 140 && c <= 148) *code = c - 27; else if (c >= 150 && c <= 154) *code = c - 28; else if (c == 160) *code = 127; } return result; } /* take care of a Manhattan (horizontal /vertical) line */ static void hvline(lx, by, rx, ty, fontindex) int32 lx, by, rx, ty, fontindex; { int32 t, rth, x, y, width, height; rth = VFontTable[fontindex - 1]->PenSize; /* thickness of vector in sp */ if (lx == rx) { /* Vertical line */ if (ty > by) { t = by; by = ty; ty = t; /* swap */ } x = (int32) floor(lx - rth / 2.0 + 0.5); y = by; width = rth; height = by - ty; } else { /* Horizontal line */ if (ty < by) { t = by; by = ty; ty = t; /* swap */ } if (lx > rx) { t = lx; lx = rx; rx = t; /* swap */ } x = lx; y = by + rth / 2; /* + rth for {h,v}-space */ width = rx - lx; height = rth; } isetpos(x, y); cmd1byte(PUTRULE); cmd4byte(height); cmd4byte(width); /* * output two dots on ends of the rules at lx, by and rx, ty */ /* the font has already been set before these calls */ Tyldot(lx, by); Tyldot(rx, ty); isetpos(rx, ty); } /* Local variables for diagonal: */ struct LOC_diagonal { int32 xl, yb, xr, yt, curx, cury; double slope; ScaledPts mxveclen; }; /* compute maximum length vector character that we can use */ static void getincr(outdx, outdy, LINK) int32 *outdx, *outdy; struct LOC_diagonal *LINK; { int32 radius, x, y, sign; radius = LINK->mxveclen;/* radius of semi-square */ /* * make sure the pt is outside of the semi-square, scaling down radius if necessary */ while (LINK->xr - LINK->curx < radius && abs(LINK->yt - LINK->cury) < radius) radius /= 2; if (LINK->slope < 0.0) /* <0 since in 4th quad by now */ sign = -1; else sign = 1; if (LINK->xr == LINK->curx) { *outdx = 0; *outdy = sign * radius; return; } if (LINK->yt == LINK->cury) { *outdx = abs(radius); *outdy = 0; return; } /* * compute the intersection with the semi-square, choose whichever slope is best */ if (fabs(LINK->slope) < 1.0) { /* mostly horizontal */ *outdx = abs(radius); y = LINK->yb + (int32) floor((LINK->curx + abs(radius) - LINK->xl) * LINK->slope + 0.5); *outdy = y - LINK->cury; } else { /* mostly vertical */ x = LINK->xl + (int32) floor((LINK->cury + sign * radius - LINK->yb) / LINK->slope + 0.5); *outdx = x - LINK->curx; *outdy = sign * radius; } if (abs(*outdy) > abs(LINK->yt - LINK->cury)) /* truncate */ *outdy = LINK->yt - LINK->cury; if (*outdx > LINK->xr - LINK->curx) /* truncate */ *outdx = LINK->xr - LINK->curx; if (*outdx < 0) *outdx = 0; /* * method to find the exact intersection of the line segment with the semi-circle, used to determine the x and y * values:: we do this by using the arctangent of the slope as the angle 'a' from the x-axis. Then use the relation y = * r cos a, and x = r sin a we can be smart about all this trig stuff by using the relation : sin (arctan a) = 1/sqrt(1 * + a^2) cos (arctan a) = a/sqrt(1 + a^2) Thus: q := (1.0 / sqrt (slope * slope + 1.0)); outdx := round (q * radius); * outdy := round (q * radius * slope); * * Unfortunately, we cannot access the Vector Font coding scheme because the outdx, outdy 's produced here do no conform * to the condition max (dx, abs(dy)) in [0,1,2,4,8,16] when converted to vector-font sizes with sptovecs (see the * 'diagonal' proc.). */ } static void diagonal(xl_, yb_, xr_, yt_, fontindex) int32 xl_, yb_, xr_, yt_, fontindex; { struct LOC_diagonal V; int32 t, dx, dy, code; double sptovecs; ScaledPts rho; V.xl = xl_; V.yb = yb_; V.xr = xr_; V.yt = yt_; if (V.xr != V.xl) /* some illegal value */ V.slope = (double) (V.yt - V.yb) / (V.xr - V.xl); else V.slope = BIGREAL; if (V.xl > V.xr) { t = V.xl; V.xl = V.xr; V.xr = t; t = V.yb; V.yb = V.yt; V.yt = t; } /* swap */ V.curx = V.xl; V.cury = V.yb; V.mxveclen = VFontTable[fontindex - 1]->MaxVectLen; rho = V.mxveclen / 16; /* minimum radius of vector fonts */ if (rho == 0) { complain(ERRREALBAD); fprintf(logfile, "Diagonal: Min radius of vector font is zero. setting to 1\n"); rho = 1; } if (abs(V.xl - V.xr) <= rho && abs(V.yb - V.yt) <= rho) { /* pretty much a null line */ Tyldot(V.xl, V.yb); return; } sptovecs = 1.0 / rho; /* conversion for scaled pts to vectorfont units */ code = -1; /* initialize to a bogus number */ /* * this conditional really has to have "or" instead of "and", because of lines that are nearly* horizontal or vertical */ while (V.xr - V.curx >= rho || abs(V.yt - V.cury) >= rho) { getincr(&dx, &dy, &V); /* * Get the vector character code corresponding to this approximate incremental amount */ t = outvector((int32) floor(dx * sptovecs + 0.5), (int32) floor(dy * sptovecs + 0.5), &code); /* * Now that we have the character code, go find out its actual physical dimensions for the real dy/dx amounts */ if (dy > 0) dy = VFontTable[fontindex - 1]->FontInfo[code].Cdp; else dy = -VFontTable[fontindex - 1]->FontInfo[code].Cht; dx = VFontTable[fontindex - 1]->FontInfo[code].Cwd; switch (t) { case 0: complain(ERRREALBAD); fprintf(logfile, "Error in Diagonal:: bad dydx\n"); break; case 1: isetpos(V.curx, V.cury); iputchar(code); break; case 2: isetpos(V.curx, V.cury); iputchar(code); isetpos(V.curx + dx / 2, V.cury + dy / 2); iputchar(code); break; } /* case */ V.curx += dx; V.cury += dy; } /* while */ /* * Get the approximate incremental amount. We use this dy/dx pair in order to index into our vector font coding scheme */ if (code >= 0 && V.xr - V.curx >= rho && abs(V.yt - V.cury) >= rho) iputchar(code); /* not null line */ } /* Local variables for tylBrokenLine: */ struct LOC_tylBrokenLine { int32 fontindex; LineStyle line_type; int useXaxis; int32 a0, b0, a1, b1, a2, a3, b2, b3, gap, dot, dash; double s, z; int32 J, frame, Dotgap, Dotdot, Dashgap, Dashdash, DDotgap, DDotdot, DDotdash; }; static void spread(lt, extra, T, LINK) LineStyle lt; int32 extra, T; struct LOC_tylBrokenLine *LINK; { if (T == 0) { /* only partial frame fits */ if (LINK->useXaxis) diagonal(LINK->a0, LINK->b0, LINK->a1, LINK->b1, LINK->fontindex); else diagonal(LINK->b0, LINK->a0, LINK->b1, LINK->a1, LINK->fontindex); return; } LINK->J = 0; LINK->s = float_(LINK->b1 - LINK->b0) / float_(LINK->a1 - LINK->a0); LINK->z = float_(extra) / float_(T); switch (lt) { case dotted: do { LINK->a2 = LINK->a0 + LINK->J * LINK->frame; if (extra > 0) LINK->a2 += (int32) floor(LINK->J * LINK->z + 0.5); LINK->a3 = LINK->a2 + LINK->dot; LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5); LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5); if (LINK->a3 <= LINK->a1) { if (LINK->useXaxis) diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex); else diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex); } LINK->J++; } while (LINK->a3 < LINK->a1); break; case dashed: do { LINK->a2 = LINK->a0 + LINK->J * LINK->frame; if (extra > 0) LINK->a2 += (int32) floor(LINK->J * LINK->z + 0.5); LINK->a3 = LINK->a2 + LINK->dash; LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5); LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5); if (LINK->a3 <= LINK->a1) { if (LINK->useXaxis) diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex); else diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex); } LINK->J++; } while (LINK->a3 < LINK->a1); break; case dotdash: do { LINK->a2 = LINK->a0 + LINK->J * LINK->frame; if (extra > 0) LINK->a2 += (int32) floor(LINK->J * LINK->z + 0.5); LINK->a3 = LINK->a2 + LINK->dash; LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5); LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5); if (LINK->a3 <= LINK->a1) { if (LINK->useXaxis) diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex); else diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex); LINK->a2 = LINK->a3 + LINK->gap; if (extra > 0) LINK->a2 += (int32) floor(LINK->z * 0.5 + 0.5); LINK->a3 = LINK->a2 + LINK->dot; LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5); LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5); if (LINK->a3 <= LINK->a1) { if (LINK->useXaxis) diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex); else diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex); } } LINK->J++; } while (LINK->a3 < LINK->a1); break; } } /* spread */ static void balance(lt, extra, T, LINK) LineStyle lt; int32 extra, T; struct LOC_tylBrokenLine *LINK; { if (T == 0) { /* only partial frame fits */ if (LINK->useXaxis) diagonal(LINK->a0, LINK->b0, LINK->a1, LINK->b1, LINK->fontindex); else diagonal(LINK->b0, LINK->a0, LINK->b1, LINK->a1, LINK->fontindex); return; } LINK->J = 0; LINK->s = float_(LINK->b1 - LINK->b0) / float_(LINK->a1 - LINK->a0); switch (lt) { case dashed: do { LINK->a2 = LINK->a0 + LINK->J * LINK->frame - extra / 2; LINK->a3 = LINK->a2 + LINK->dash; if (LINK->J == 0) LINK->a2 = LINK->a0; if (LINK->a3 > LINK->a1) LINK->a3 = LINK->a1; LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5); LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5); if (LINK->a3 <= LINK->a1) { if (LINK->useXaxis) diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex); else diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex); } LINK->J++; } while (LINK->a3 < LINK->a1); break; case dotdash: do { LINK->a2 = LINK->a0 + LINK->J * LINK->frame - extra / 2; LINK->a3 = LINK->a2 + LINK->dash; if (LINK->J == 0) LINK->a2 = LINK->a0; if (LINK->a3 > LINK->a1) LINK->a3 = LINK->a1; LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5); LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5); if (LINK->a3 <= LINK->a1) { if (LINK->useXaxis) diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex); else diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex); LINK->a2 = LINK->a3 + LINK->gap; LINK->a3 = LINK->a2 + LINK->dot; LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5); LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5); if (LINK->a3 <= LINK->a1) { if (LINK->useXaxis) diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex); else diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex); } } LINK->J++; } while (LINK->a3 < LINK->a1); break; } } /* balance */ static int32 project(I, LINK) int32 I; struct LOC_tylBrokenLine *LINK; { int32 K; /* gives the projection of lengths onto axes */ K = (int32) floor(I * float_(abs(LINK->a1 - LINK->a0)) / LINK->s + 0.5); if (K == 0) K = 1; return K; } static void setlengths(findex, LINK) int32 findex; struct LOC_tylBrokenLine *LINK; { /* sets the "optimal" sizes for textured lines */ int32 penrad; VThickness siz; penrad = VFontTable[findex - 1]->PenSize; siz = VFontTable[findex - 1]->psize; LINK->Dotdot = penrad / siz; LINK->Dotgap = penrad * 6; LINK->Dashdash = penrad * 6; LINK->Dashgap = penrad * 6; LINK->DDotdash = penrad * 6; LINK->DDotgap = penrad * 4; LINK->DDotdot = penrad / siz; } static void setframesize(LINK) struct LOC_tylBrokenLine *LINK; { switch (LINK->line_type) { /* length of frame depends on type of broken line */ case solid: LINK->frame = 0; break; case dotted: LINK->frame = LINK->gap + LINK->dot; break; case dashed: LINK->frame = LINK->gap + LINK->dash; break; case dotdash: LINK->frame = LINK->gap * 2 + LINK->dot + LINK->dash; break; } } static void tylBrokenLine(x0, y0, x1, y1, fontindex_, line_type_) int32 x0, y0, x1, y1, fontindex_; LineStyle line_type_; { struct LOC_tylBrokenLine V; double fit; int32 T, a1ma0; V.fontindex = fontindex_; V.line_type = line_type_; if (x0 == x1 && y0 == y1) { diagonal(x0, y0, x1, y1, V.fontindex); /* null line */ return; } setlengths(V.fontindex, &V); if (abs(y1 - y0) > abs(x1 - x0)) { /* longer axis is used as base */ V.useXaxis = false; V.a0 = y0; V.b0 = x0; V.a1 = y1; V.b1 = x1; } else { V.useXaxis = true; V.a0 = x0; V.b0 = y0; V.a1 = x1; V.b1 = y1; } /* the distance between a0 and a1 is now greater than that between b0 and b1. */ /* redefine distances as integral units along axes */ V.s = distance(float_(V.a0), float_(V.b0), float_(V.a1), float_(V.b1)); switch (V.line_type) { case solid: /* blank case */ break; case dotted: V.gap = project(V.Dotgap, &V); V.dot = project(V.Dotdot, &V); break; case dashed: V.gap = project(V.Dashgap, &V); V.dash = project(V.Dashdash, &V); break; case dotdash: V.gap = project(V.DDotgap, &V); V.dot = project(V.DDotdot, &V); V.dash = project(V.DDotdash, &V); break; } /* * ensure direction of line is from smaller to larger along the longer axis */ if (V.a0 > V.a1) { V.J = V.a0; V.a0 = V.a1; V.a1 = V.J; V.J = V.b0; V.b0 = V.b1; V.b1 = V.J; } setframesize(&V); a1ma0 = V.a1 - V.a0; /* fit is the number of frames that fit in line */ if (V.frame != 0) fit = float_(a1ma0) / float_(V.frame); else fit = 1.0; if (fit >= 1.0) T = (int32) floor(fit + 0.5); else { /* change frame elements (dot, dash, gap) since frame is too large */ switch (V.line_type) { case dotted: V.gap += a1ma0 - V.frame; if (V.gap < V.dot) return; /* exit */ setframesize(&V); break; case dashed: case dotdash: /* idea:decrease gap; if too small then shrink dash and refigure gap */ if (V.frame - a1ma0 > V.gap / 2) { V.dash = (int32) floor(V.dash * fit * 0.80 + 0.5); V.gap = (int32) floor(V.gap * fit + 0.5); setframesize(&V); } V.gap += a1ma0 - V.frame; if (V.line_type == dotdash) V.gap /= 2; if (V.gap < V.dot) return; /* exit */ setframesize(&V); break; } /* case */ T = 1; /* NOW it will fit */ } /* else */ switch (V.line_type) { case solid: if (V.useXaxis) diagonal(V.a0, V.b0, V.a1, V.b1, V.fontindex); else diagonal(V.b0, V.a0, V.b1, V.a1, V.fontindex); break; case dotted: /* dotted lines begin and end on a dot */ if (T * V.frame + V.dot == a1ma0) spread(dotted, 0, T, &V); else if (T * V.frame + V.dot > a1ma0) { /* * gap := gap - ((T*frame+dot)-a1ma0); { */ spread(dotted, a1ma0 - T * V.frame - V.dot, T, &V); /* * spread(dotted, a1ma0 - (T-1)*frame - dot, T-1); { */ } else spread(dotted, a1ma0 - T * V.frame - V.dot, T, &V); break; case dashed: /* * dashed lines begin and end on dash : the beginning and ending dashes are at least half the dash length * int32. */ if (T * V.frame + V.dash == a1ma0) spread(dashed, 0, T, &V); else if (T * V.frame + V.dash > a1ma0) balance(dashed, T * V.frame + V.dash - a1ma0, T, &V); else spread(dashed, a1ma0 - T * V.frame - V.dash, T, &V); break; case dotdash: /* * if ending on a dash then beginning and ending dashes are half the dash length long - final dots are full * dot length */ if (T * V.frame + V.dash == a1ma0) spread(dotdash, 0, T, &V); else if (T * V.frame + V.dash + V.gap + V.dot == a1ma0) spread(dotdash, 0, T, &V); else if (T * V.frame + V.dash > a1ma0) balance(dotdash, T * V.frame + V.dash - a1ma0, T, &V); else if (T * V.frame + V.dash + V.gap + V.dot > a1ma0) spread(dotdash, a1ma0 - T * V.frame - V.dash, T, &V); else spread(dotdash, a1ma0 - T * V.frame - V.dash - V.gap - V.dot, T, &V); break; } } void clampthickness(thic) VThickness *thic; { /* * #### this is just a simple clamp really should be something like: while not (thic in set_of_appropriate_thicknesses) * do modify thic and try again */ if (*thic <= LoVThick) *thic = LoVThick + 1; while (((1 << (*thic)) & 0x1ffe) == 0 && *thic <= HiVThick) (*thic)++; if (*thic > HiVThick) *thic = HiVThick; } static void slurclamp(thic, totpts) VThickness *thic; int32 totpts; { /* * this post-clamps the sampled thicknesses calculated over the whole of the spline */ int32 i, oneseventh, middle, startval, endval; double deltaval, val, incrval, alpha, alphaincr; /* * $$ NOTE:: How does the ttspline interpolation of thicknesses compare to the below results?? Can we avoid having it * done elsewhere and concentrate on it here?? */ oneseventh = (int32) floor(totpts / 7.0 + 0.5); for (i = 1; i <= oneseventh; i++) thic[i] = thic[1]; for (i = oneseventh * 6; i <= totpts; i++) thic[i] = thic[totpts]; middle = (int32) floor(totpts / 2.0 + 0.5); for (i = oneseventh * 3; i <= oneseventh * 4; i++) thic[i] = thic[middle]; startval = thic[oneseventh - 1]; endval = thic[oneseventh * 3 + 1]; deltaval = (endval - startval) * 2.0 / (oneseventh * 2); alphaincr = PI / (oneseventh * 2 + 1); alpha = PI; val = float_(startval); for (i = oneseventh; i < oneseventh * 3; i++) { /* interpolate: ease in from minthick to middlethickness */ alpha += alphaincr; incrval = (cos(alpha) + 1.0) / 2.0 * deltaval; val += incrval; thic[i] = (int32) floor(val + 0.5); } startval = thic[oneseventh * 4 - 1]; endval = thic[oneseventh * 6 + 1]; deltaval = (endval - startval) * 2.0 / (oneseventh * 2); alphaincr = PI / (oneseventh * 2 + 1); alpha = 0.0; val = float_(startval); for (i = oneseventh * 4 + 1; i <= oneseventh * 6; i++) { /* ease out from middle thickness to min thick at far end */ alpha += alphaincr; incrval = (cos(alpha) + 1.0) / 2.0 * deltaval; val += incrval; thic[i] = (int32) floor(val + 0.5); } } void layline(xl, yb, xr, yt, fontindex, pattern, useVecfontOnly) int32 xl, yb, xr, yt, fontindex; LineStyle pattern; int useVecfontOnly; { int32 t; if (xr < xl) { t = xr; xr = xl; xl = t; t = yb; yb = yt; yt = t; } isetfont(VFontTable[fontindex - 1]->DVIFontNum); /* * we may want to require using a vector font only, instead of a combination of vectors and TeX-rules. It may look * better this way. */ if (useVecfontOnly) { tylBrokenLine(xl, yb, xr, yt, fontindex, pattern); return; } if ((xl != xr || yb != yt) && (xl == xr || yb == yt)) { /* Null or diagonal lines */ /* * if (pattern = solid) then hvline (xl, yb, xr, yt, fontindex) (* make use of rules *) else USENORULES */ tylBrokenLine(xl, yb, xr, yt, fontindex, pattern); return; } if (pattern == solid) diagonal(xl, yb, xr, yt, fontindex); else tylBrokenLine(xl, yb, xr, yt, fontindex, pattern); /* be smart about the lines */ } #define DontDoThicks false #define VectorsOnly true /* Local variables for layAspline: */ struct LOC_layAspline { VThickness thick; }; void layAspline(thetype, isclosed, isanArc, domarks, cpts, numpts, thick_, vkind, patt) SplineKind thetype; int isclosed, isanArc; int32 domarks; int32(*cpts)[2]; int32 numpts; VThickness thick_; VectKind vkind; LineStyle patt; { struct LOC_layAspline V; SplineSegments pointList; int32 i, xs, ys; ThickAryType tt1, tt2; VecIndex F; int32 FORLIM; V.thick = thick_; clampthickness(&V.thick); for (i = 0; i <= numpts + 3; i++) tt1[i] = V.thick; /* do any marks if necessary to show the control points */ if (domarks > 0) { F = GetVectFont((int) domarks, VKCirc); isetfont(VFontTable[F - 1]->DVIFontNum); for (i = 1; i <= numpts; i++) Tyldot(cpts[i][0], cpts[i][1]); } drawSpline(thetype, isclosed, isanArc, patt, numpts, cpts, pointList, DontDoThicks, tt1, tt2); F = GetVectFont(V.thick, vkind); xs = pointList[0][0]; ys = pointList[0][1]; FORLIM = lastPoint; for (i = 1; i < FORLIM; i++) { layline(xs, ys, pointList[i][0], pointList[i][1], F, patt, VectorsOnly); xs = pointList[i][0]; ys = pointList[i][1]; } if (isclosed) /* complete the motion */ layline(pointList[lastPoint - 1][0], pointList[lastPoint - 1] [1], pointList[0][0], pointList[0][1], F, patt, VectorsOnly); } #define NotAnArc false #define DoThicksToo true #define VectorsOnly true void layNspline(thetype, isclosed, isitaslur, domarks, cpts, numpts, thickmatrix, vkind, patt) SplineKind thetype; int isclosed, isitaslur; int32 domarks; int32(*cpts)[2]; int32 numpts; VThickness *thickmatrix; VectKind vkind; LineStyle patt; { SplineSegments pointList; int32 i, xs, ys; VThickness ts; ThickAryType tt; VecIndex F; int32 FORLIM; /* do any marks if necessary to show the control points */ if (domarks > 0) { F = GetVectFont((int) domarks, VKCirc); isetfont(VFontTable[F - 1]->DVIFontNum); for (i = 1; i <= numpts; i++) Tyldot(cpts[i][0], cpts[i][1]); } drawSpline(thetype, isclosed, NotAnArc, patt, numpts, cpts, pointList, DoThicksToo, thickmatrix, tt); if (isitaslur && !skiptsclamp) slurclamp(tt, lastPoint); /* which kind of clamping to use */ xs = pointList[0][0]; ys = pointList[0][1]; ts = tt[1]; FORLIM = lastPoint; for (i = 1; i < FORLIM; i++) { clampthickness(&ts); F = GetVectFont(ts, vkind); layline(xs, ys, pointList[i][0], pointList[i][1], F, patt, VectorsOnly); xs = pointList[i][0]; ys = pointList[i][1]; ts = tt[i + 1]; } if (!isclosed) return; ts = tt[lastPoint]; clampthickness(&ts); F = GetVectFont(ts, vkind); layline(pointList[lastPoint - 1][0], pointList[lastPoint - 1] [1], pointList[0][0], pointList[0][1], F, patt, VectorsOnly); } /* && start dvidvi section */ /*-----------------------------------------------------*/ static void initialize() { initVnMnLtables(); multifigure = 0; pgfigurenum = 0; TotBytesWritten = 0; ourq = 0; currpagenum = 0; FTBDs = 0; InitDVIBuf(); inpostamble = false; didnewfonts = false; skiptsclamp = false; ErrorOccurred = false; } /*-----------------------------------------------------*/ static int inTFM(z) int32 z; { int32 k, lh, nw, alpha, beta, FORLIM; fontinfo *WITH; readtfmword(); lh = b2 * 256 + b3; readtfmword(); font[nf].bc = b0 * 256 + b1; font[nf].ec = b2 * 256 + b3; if (font[nf].ec < font[nf].bc) font[nf].bc = font[nf].ec + 1; readtfmword(); nw = b0 * 256 + b1; if (nw == 0 || nw > 256) return (false); for (k = 1; k <= lh + 3; k++) { if (feof(tfmfile)) return (false); readtfmword(); if (k == 4) { if (b0 < 128) tfmchecksum = ((b0 * 256 + b1) * 256 + b2) * 256 + b3; else tfmchecksum = (((b0 - 256) * 256 + b1) * 256 + b2) * 256 + b3; } } FORLIM = font[nf].ec - font[nf].bc; for (k = 0; k <= FORLIM; k++) { readtfmword(); if (b0 > nw) return (false); font[nf].widths[k] = b0; } alpha = z * 16; beta = 16; while (z >= TWO23) { z /= 2; beta /= 2; } for (k = 0; k < nw; k++) { readtfmword(); inwidth[k] = ((b3 * z / 256 + b2 * z) / 256 + b1 * z) / beta; if (b0 > 0) { if (b0 < 255) return (false); inwidth[k] -= alpha; } } if (inwidth[0] != 0) return (false); WITH = &font[nf]; /* with */ FORLIM = WITH->ec - WITH->bc; for (k = 0; k <= FORLIM; k++) { if (WITH->widths[k] == 0) { WITH->widths[k + WITH->bc] = TWO31; /* pixelwidths[k + bc] := 0; */ } else { WITH->widths[k + WITH->bc] = inwidth[WITH->widths[k]]; /* pixelwidths[k + bc] := round(conv * widths[k]); */ } } return (true); } static void Fastdefinefont(fn) int32 fn; { int32 p, k, n; (void) Dsign4byte(); (void) Dsign4byte(); (void) Dsign4byte(); p = Dget1byte(); n = Dget1byte(); for (k = 1; k <= p + n; k++) (void) Dget1byte(); } /* Fastdefinefont */ static void definefont(e) int32 e; { char f; int32 p, k, n, c, q, d; charstring tfmname; if (nf == MAXFONTS) { complain(ERRREALBAD); fprintf(logfile, "TeXtyl capacity exceeded (max fonts=%d)!\n", MAXFONTS); jumpout(); } font[nf].num = e; f = 0; while (font[f].num != e)/* find first occurrence */ f++; c = Dsign4byte(); font[nf].checksum = c; q = Dsign4byte(); font[nf].scaledsize = q; d = Dsign4byte(); font[nf].designsize = d; p = Dget1byte(); n = Dget1byte(); for (k = 0; k < p + n; k++) font[nf].name[k] = Dget1byte(); font[nf].name[k] = '\0'; if (f != nf) /* f = nf */ return; strcpy(tfmname, font[nf].name); strcat(tfmname, ".tfm"); if (!opentfmfile(tfmname)) { complain(ERRREALBAD); fprintf(logfile, "%s---not loaded, TFM file can't be opened!\n", tfmname); jumpout(); return; } if (q <= 0 || q >= TWO27) { complain(ERRREALBAD); fprintf(logfile, "%s---not loaded, bad scale (%d)!\n", tfmname, q); return; } if (d <= 0 || d >= TWO27) { complain(ERRREALBAD); fprintf(logfile, "%s---not loaded, bad design size (%d)!\n", tfmname, d); return; } if (!inTFM(q)) { /* intfm */ complain(ERRREALBAD); fprintf(logfile, "%s---not loaded, TFM file is bad\n", tfmname); return; } /* intfm */ font[nf].space = q / 6; if (c != 0 && tfmchecksum != 0 && c != tfmchecksum) { fprintf(logfile, "Problem in fig#%d on page %d\n", pgfigurenum, currpagenum); fprintf(logfile, "%s---beware: check sums do not agree!\n", tfmname); fprintf(logfile, " (%d vs. %d)\n", c, tfmchecksum); } d = (int32) floor(100.0 * conv * q / (trueconv * d) + 0.5); nf++; font[nf].space = 0; } static int32 firstpar(o) int o; { int32 fpar; if (0 <= o && o <= 127) fpar = o; else if (171 <= o && o <= 234) fpar = o - 171; else switch (o) { case 128: case 133: case 235: case 239: case 243: fpar = Dget1byte(); break; case 129: case 134: case 236: case 240: case 244: fpar = Dget2byte(); break; case 130: case 135: case 237: case 241: case 245: fpar = Dget3byte(); break; case 143: case 148: case 153: case 157: case 162: case 167: fpar = Dsign1byte(); break; case 144: case 149: case 154: case 158: case 163: case 168: fpar = Dsign2byte(); break; case 145: case 150: case 155: case 159: case 164: case 169: fpar = Dsign3byte(); break; case 131: case 132: case 136: case 137: case 146: case 151: case 156: case 160: case 165: case 170: case 238: case 242: case 246: fpar = Dsign4byte(); break; case 138: case 139: case 140: case 141: case 142: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: fpar = 0; break; case 147: fpar = w; break; case 152: fpar = x; break; case 161: fpar = y; break; case 166: fpar = z; break; } return fpar; } static int specialcases(o, p) int32 o, p; { if (o < 157 || o > 249) { complain(ERRREALBAD); fprintf(logfile, "undefined command %d!\n", o); return (true); } else if (171 <= o && o <= 238) { font[nf].num = p; curfont = 0; while (font[curfont].num != p) curfont++; return (true); } switch (o) { case 157: case 158: case 159: case 160: break; case 161: case 162: case 163: case 164: case 165: y = p; break; case 166: case 167: case 168: case 169: case 170: z = p; break; case 243: case 244: case 245: case 246: definefont(p); return (true); case 239: case 240: case 241: case 242: /* =========specials============= */ mainhandlespecials(o, p); return (true); case 247: complain(ERRREALBAD); fprintf(logfile, "preamble command within a page!\n"); return (false); case 248: case 249: complain(ERRREALBAD); fprintf(logfile, "postamble command within a page!\n"); return (false); } if (v > 0 && p > 0) { if (v > TWO31 - p) p = TWO31 - v; } if (v < 0 && p < 0) { if (-v > p + TWO31) p = -v - TWO31; } v += p; return (true); } static int dopage() { int32 o, p, q; struct stackrec *WITH; curfont = nf; s = 0; h = 0; v = 0; w = 0; x = 0; y = 0; z = 0; ourxpos = 0; ourypos = 0; ourfontnum = -1; for (;;) { o = Dget1byte(); p = firstpar(o); if (feof(dvifile)) { fprintf(logfile, "Bad DVI file: the file ended prematurely!\n"); jumpout(); } if (o <= 131) goto _L41; if (o > 156) { if (specialcases(o, p)) continue; else return (false); } switch (o) { case 133: case 134: case 135: case 136: goto _L41; break; case 132: case 137: goto _L42; break; case 138: continue; case 139: /* BOP */ complain(ERRREALBAD); fprintf(logfile, "bop occurred before eop\n"); return (false); /* Fail */ break; case 140: /* EOP */ if (s != 0) { complain(ERRREALBAD); fprintf(logfile, "stack not empty at end of page (level %d)!\n", s); } if (multifigure != 0) { complain(ERRBAD); fprintf(logfile, "Some figure definition not closed at end of page %d!\n", currpagenum); } fprintf(logfile, "%d]", currpagenum); if (currpagenum % 10 == 0) putc('\n', logfile); return (true); case 141: /* PUSH */ WITH = &stack[s]; /* with */ WITH->sh = h; WITH->sv = v; WITH->sw = w; WITH->sx = x; WITH->sy = y; WITH->sz = z; s++; continue; case 142: /* POP */ if (s == 0) { complain(ERRREALBAD); fprintf(logfile, "illegal pop at level zero!\n"); } else { s--; WITH = &stack[s]; h = WITH->sh; v = WITH->sv; w = WITH->sw; x = WITH->sx; y = WITH->sy; z = WITH->sz; } continue; case 143: case 144: case 145: case 146: q = p; goto _L43; break; case 147: case 148: case 149: case 150: case 151: w = p; q = p; goto _L43; break; case 152: case 153: case 154: case 155: case 156: x = p; q = p; goto _L43; break; } /* case */ _L41: /* finish cmd to set/put a char */ if (p < 0) p = 255 - ((-p - 1) & 255); else if (p >= 256) p &= 255; if (p < font[curfont].bc || p > font[curfont].ec) q = TWO31; else q = font[curfont].widths[p]; if (q == TWO31) { complain(ERRREALBAD); fprintf(logfile, "Character %d invalid in font #%d\n", p, curfont); } if (o >= 133) continue; if (q == TWO31) q = 0; goto _L43; _L42: /* finish cmd to set/put rule */ q = Dsign4byte(); if (o == 137) continue; goto _L43; _L43: /* finish cmd that sets h += q */ if (h > 0 && q > 0) { if (h > TWO31 - q) q = TWO31 - h; } if (h < 0 && q < 0) { if (-h > q + TWO31) q = -h - TWO31; } h += q; } } static void skippages() { int32 p; int32 k; for (;;) { if (feof(dvifile)) { fprintf(logfile, "Bad DVI file: the file ended prematurely!\n"); jumpout(); } k = Dget1byte(); p = firstpar(k); switch (k) { case 139: /* BOP */ newbackptr = DVIMark() + TotBytesWritten - 1; currpagenum = Dsign4byte(); /* count[0] */ for (k = 1; k <= 9; k++) /* WAS count[k] := */ (void) Dsign4byte(); (void) Dsign4byte(); BackupInBuf(4); cmdSigned(oldbackptr, 4); oldbackptr = newbackptr; fprintf(logfile, "["); return; case 132: case 137: /* RULE */ (void) Dsign4byte(); break; case 243: case 244: case 245: case 246: definefont(p); break; case 239: case 240: case 241: case 242: /* specials */ mainhandlespecials(k, p); break; case 248: /* POST */ ourq = DVIMark() + TotBytesWritten - 1; inpostamble = true; return; } } } static void readpostamble() { int32 k, p, m, indx, FORLIM; MusFontInfRec *WITH; VectFontInfRec *WITH1; LabFontInfRec *WITH2; if (Dsign4byte() != numerator) fprintf(logfile, "Postamble numerator doesn't match the preamble!\n"); if (Dsign4byte() != denominator) fprintf(logfile, "Postamble denominator doesn't match the preamble!\n"); if (Dsign4byte() != mag) fprintf(logfile, "Postamble magnification doesn't match the preamble!\n"); maxv = Dsign4byte(); maxh = Dsign4byte(); maxs = Dget2byte(); BackupInBuf(2); cmd2byte(maxs + 2); /* * pretend the stack depth does not increase by more than two */ totalpages = Dget2byte(); do { k = Dget1byte(); if (k >= 243 && k < 247) { p = firstpar(k); Fastdefinefont(p); k = 138; } } while (k == 138); /* NOP */ /* * here, backup 1, enter all our fonts and then output the 249 that we backed over */ BackupInBuf(1); FORLIM = MFontsDefd; for (indx = 0; indx < FORLIM; indx++) { WITH = MFontTable[indx]; enterfont(WITH->DVIFontNum, WITH->Cksum, WITH->DesSize, WITH->DesSize, WITH->FontName); } /* for */ FORLIM = VFontsDefd; for (indx = 0; indx < FORLIM; indx++) { WITH1 = VFontTable[indx]; enterfont(WITH1->DVIFontNum, WITH1->Cksum, WITH1->DesSize, WITH1->DesSize, WITH1->FontName); } /* for */ FORLIM = LFontsDefd; for (indx = 0; indx < FORLIM; indx++) { WITH2 = LFontTable[indx]; enterfont(WITH2->DVIFontNum, WITH2->Cksum, WITH2->DesSize, WITH2->DesSize, WITH2->FontName); } cmd1byte(249); /* post post */ if (k != 249) fprintf(logfile, "byte %d is not postpost!\n", k); (void) Dsign4byte(); BackupInBuf(4); cmd4byte(ourq); m = Dget1byte(); if (m != 2) fprintf(logfile, "identification should be %d!\n", 2); m = 223; while ((m == 223) && (!feof(dvifile))) m = Dget1byte(); if (feof(dvifile)) return; fprintf(logfile, "Bad DVI file: signature in should be 223!\n"); jumpout(); } /* MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN */ int main(argc, argv) int argc; char *argv[]; { void exit PP((int)); if (setjmp(_JL666)) goto _L666; initialize(); if (argc < 3) { fprintf(stderr, "Usage: textyl dvi-in dvi-out\n"); exit(1); } if ((dvifile = fopen(argv[1], "r")) == NULL) { perror(argv[1]); exit(1); } if ((outputfil = fopen(argv[2], "w")) == NULL) { perror(argv[2]); exit(1); } logfile = stdout; fprintf(logfile, "%s for Berkeley Unix\n", TylVersion); p = Dget1byte(); if (p != 247) { fprintf(logfile, "Bad DVI file: First byte isn't start of preamble!!\n"); jumpout(); } p = Dget1byte(); if (p != 2) fprintf(logfile, "identification in byte 1 should be %d!\n", 2); numerator = Dsign4byte(); denominator = Dsign4byte(); if (numerator <= 0) { fprintf(logfile, "Bad DVI file: numerator is %d!\n", numerator); jumpout(); } if (denominator <= 0) { fprintf(logfile, "Bad DVI file: denominator is %d!\n", denominator); jumpout(); } conv = numerator / 254000.0 * (resolution / denominator); mag = Dsign4byte(); if (mag <= 0) { fprintf(logfile, "Bad DVI file: magnification is % .1E!\n", mag); jumpout(); } magfactor = mag / 1000.0; trueconv = conv; conv = trueconv * magfactor; p = Dget1byte(); /* the 'k' of the preamble */ while (p > 0) { p--; (void) Dget1byte(); } skippages(); if (!inpostamble) { while (maxpages-- > 0) { /* while */ if (!dopage()) { printf(" Bad DVI file: page ended unexpectedly!"); fprintf(logfile, "Bad DVI file: page ended unexpectedly!\n"); jumpout(); } WriteDVIBuf(); ClearDVIBuf(); multifigure = 0; pgfigurenum = 0; FTBDs = 0; didnewfonts = false; do { k = Dget1byte(); if (k >= 243 && k < 247) { /* fontdefs */ p = firstpar(k); definefont(p); k = 138; } } while (k == 138); /* nop */ if (k == 248) { inpostamble = true; ourq = DVIMark() + TotBytesWritten - 1; break; } if (k != 139) { /* BOP */ fprintf(logfile, "We did not find BOP when expected\n"); jumpout(); continue; } newbackptr = DVIMark() + TotBytesWritten - 1; currpagenum = Dsign4byte(); /* Count[0] */ for (k = 1; k <= 9; k++) /* WAS count[k] := */ (void) Dsign4byte(); (void) Dsign4byte(); /* backpointer */ BackupInBuf(4); cmdSigned(oldbackptr, 4); oldbackptr = newbackptr; fprintf(logfile, "["); } /* while */ } /* if not inpostamble */ if (!inpostamble) skippages(); (void) Dsign4byte(); /* ptr to the last bop in file */ BackupInBuf(4); cmdSigned(oldbackptr, 4); readpostamble(); WriteDVIBuf(); while ((TotBytesWritten & 3) != 0) /* final signatures */ OutputByte(223); fprintf(logfile, "(%d page", currpagenum); if (currpagenum > 1) putc('s', logfile); fprintf(logfile, ", %d bytes).\n", TotBytesWritten); _L666: if (ErrorOccurred) { fprintf(logfile, "\nSome error(s) occurred.\n"); fprintf(logfile, "Assume that the outputfile is incorrect\n"); } if (dvifile != NULL) fclose(dvifile); if (tfmfile != NULL) fclose(tfmfile); if (outputfil != NULL) fclose(outputfil); if (logfile != NULL) fclose(logfile); exit(0); return (0); }