parag@hpsdeb.sde.hp.com (Parag Patel) (05/15/91)
Submitted-by: Parag Patel <parag@hpsdeb.sde.hp.com> Posting-number: Volume 19, Issue 65 Archive-name: dvi/part02 ---- Cut Here and feed the following to sh ---- #!/bin/sh # This is part 02 of dvi # ============= stack.C ============== if test -f 'stack.C' -a X"$1" != X"-c"; then echo 'x - skipping stack.C (File already exists)' else echo 'x - extracting stack.C (Text)' sed 's/^X//' << 'SHAR_EOF' > 'stack.C' && // Copyright (c) 1991 by Parag Patel. All Rights Reserved. static const char rcsid[] = "$Header: stack.C,v 1.7 91/02/22 15:57:07 hmgr Exp $"; X // manipulate a DVI stack // // by Parag Patel X #include "defs.h" X X // a stack representation struct stkrep { X double h, v, w, x, y, z; }; X declare_array(Stack, stkrep); implement_array(Stack, stkrep); X static int top = 0; // top of the stack; static Stack sp(50); // the DVI stack itself X X // save current DVI/TeX variable values // void pushdvi() { X sp[top].h = H; X sp[top].v = V; X sp[top].w = W; X sp[top].x = X; X sp[top].y = Y; X sp[top].z = Z; X top++; } X X // restore current DVI/TeX variable values // void popdvi() { X if (top <= 0) X quit("Stack underflow"); X top--; X H = sp[top].h; X V = sp[top].v; X W = sp[top].w; X X = sp[top].x; X Y = sp[top].y; X Z = sp[top].z; } X X // clear the stack and dvi vars // void cleardvi() { X H = V = W = X = Y = Z = 0.0; X top = 0; } SHAR_EOF chmod 0444 stack.C || echo 'restore of stack.C failed' Wc_c="`wc -c < 'stack.C'`" test 970 -eq "$Wc_c" || echo 'stack.C: original size 970, current size' "$Wc_c" fi # ============= dirs.C ============== if test -f 'dirs.C' -a X"$1" != X"-c"; then echo 'x - skipping dirs.C (File already exists)' else echo 'x - extracting dirs.C (Text)' sed 's/^X//' << 'SHAR_EOF' > 'dirs.C' && // Copyright (c) 1991 by Parag Patel. All Rights Reserved. static const char rcsid[] = "$Header: dirs.C,v 1.10 91/02/22 15:57:16 hmgr Exp $"; X // read font directory names into memory for fast traversal // // by Parag Patel X #include "defs.h" #include "dirs.h" #ifdef __ZTC__ #include <dos.h> #define d_name name #else #ifdef BSD #include <sys/dir.h> #else #include <ndir.h> #endif #endif X X implement_array(Dirlist, Dirent); implement_array(Pathlist, Pathent); X X Pathlist pathlist; X X Dirent::Dirent() { X name = NULL; X val = 0; } X Pathent::Pathent() { X path = NULL; } X Pathent &Pathent::operator=(Pathent &x) { X path = x.path; X dirs = x.dirs; X return *this; } X X void setupdirs(char *path) { X path = strdup(path); X char *save = path; X X pathlist.reset(); X X debug(3, "Setup dirpaths = %s", path); X while (path != NULL && *path != '\0') X { X char *dirpath = path; X while (*path != PATHSEP && *path != '\0') X path++; X if (*path != '\0') X *path++ = '\0'; X debug(4, " DIR = %s", dirpath); X #ifndef __ZTC__ X DIR *dir = opendir(dirpath); X if (dir == NULL) X { X warn("Cannot opendir directory \"%s\" for scanning", dirpath); X continue; X } #endif X X Pathent & path = pathlist[pathlist.size()]; X path.path = strdup(dirpath); X path.dirs.reset(); X #ifdef __ZTC__ X char dos_dirpath[64]; X (void)strcpy(dos_dirpath, dirpath); X (void)strcat(dos_dirpath, "/*.*"); X for (FIND *ent = findfirst(dos_dirpath, FA_DIREC); ent != NULL; X ent = findnext()) #else X for (direct * ent = readdir(dir); ent != NULL; ent = readdir(dir)) #endif X { X char *s = strchr(ent->d_name, '.'); X int magent; X X if (s != NULL) X { X // if there is a dot in the name, it may be the newer X // magnification value naming conventions: "1.000" X *s = '\0'; X magent = atoi(ent->d_name) * 1000 + atoi(s + 1); X *s = '.'; X } X else X // older resolution naming convention: "300", "1000" X magent = atoi(ent->d_name); X X if (magent <= 0) X continue; X X Dirent & d = path.dirs[path.dirs.size()]; X d.name = strdup(ent->d_name); X d.val = magent; X debug(5, " name=%s val=%d", d.name, d.val); X } X #ifndef __ZTC__ X closedir(dir); #endif X } X strfree(save); } SHAR_EOF chmod 0444 dirs.C || echo 'restore of dirs.C failed' Wc_c="`wc -c < 'dirs.C'`" test 2199 -eq "$Wc_c" || echo 'dirs.C: original size 2199, current size' "$Wc_c" fi # ============= dvi.C ============== if test -f 'dvi.C' -a X"$1" != X"-c"; then echo 'x - skipping dvi.C (File already exists)' else echo 'x - extracting dvi.C (Text)' sed 's/^X//' << 'SHAR_EOF' > 'dvi.C' && // Copyright (c) 1991 by Parag Patel. All Rights Reserved. static const char rcsid[] = "$Header: dvi.C,v 1.24 91/02/22 15:57:33 hmgr Exp $"; X // dvi scanning routines // // by Parag Patel X #include "defs.h" X X static long mag = 1000; static double magval = 1.0; X X // print the specified page from the file "fp" at the specified // magnification - this is called for any page in the DVI file provided // that the "fp" has been set to the start of a page in the DVI file - // thus pages may be printed in any random order // static void dopage(FILE *fp, long page) { X // clear and initialize the global state for a new page X cleardvi(); X clearfonts(); X X // if this is not the first page, then eject the previous X // page from the printer X // X static first = TRUE; X dev_newpage((page & 0x01) || page == 0, first); X first = FALSE; X X // now go through the DVI file executing opcodes... X register int opcode; X while ((opcode = (int)getuval(1, fp)) != EOP) X { X debug(7, " H=%f V=%f W=%f X=%f Y=%f Z=%f", H, V, W, X, Y, Z); X debug(6, "opcode = %d", opcode); X X if (opcode >= SET0 && opcode <= SET127) X { X // typeset (print) a character X typeset(opcode, TRUE, magval); X continue; X } X if (opcode >= FONT0 && opcode <= FONT63) X { X // switch to a new font X newfont(opcode - FONT0); X continue; X } X switch (opcode) X { X // print (typeset) a character and move the cursor X Case SET1: X typeset(getuval(1, fp), TRUE, magval); X Case SET2: X typeset(getuval(2, fp), TRUE, magval); X Case SET3: X typeset(getuval(3, fp), TRUE, magval); X Case SET4: X typeset(getsval(4, fp), TRUE, magval); X X // just typeset a character X Case PUT1: X typeset(getuval(1, fp), FALSE, magval); X Case PUT2: X typeset(getuval(2, fp), FALSE, magval); X Case PUT3: X typeset(getuval(3, fp), FALSE, magval); X Case PUT4: X typeset(getsval(4, fp), FALSE, magval); X X // print a rule X Case SETRULE: X typerule(fp, TRUE, magval); X Case PUTRULE: X typerule(fp, FALSE, magval); X X Case NOOP: X X Case PUSH: X pushdvi(); X Case POP: X popdvi(); X X // horizontal moves (negative == move left) X Case RIGHT1: X moveright(Getsval(1, fp) * magval); X Case RIGHT2: X moveright(Getsval(2, fp) * magval); X Case RIGHT3: X moveright(Getsval(3, fp) * magval); X Case RIGHT4: X moveright(Getsval(4, fp) * magval); X X // move horizontal based on the var W X Case W0: X moveright(W); X Case W1: X moveright(W = Getsval(1, fp) * magval); X Case W2: X moveright(W = Getsval(2, fp) * magval); X Case W3: X moveright(W = Getsval(3, fp) * magval); X Case W4: X moveright(W = Getsval(4, fp) * magval); X X // move horizontal based on the var X X Case X0: X moveright(X); X Case X1: X moveright(X = Getsval(1, fp) * magval); X Case X2: X moveright(X = Getsval(2, fp) * magval); X Case X3: X moveright(X = Getsval(3, fp) * magval); X Case X4: X moveright(X = Getsval(4, fp) * magval); X X // move vertically (negative == towards top of page) X Case DOWN1: X movedown(Getsval(1, fp) * magval); X Case DOWN2: X movedown(Getsval(2, fp) * magval); X Case DOWN3: X movedown(Getsval(3, fp) * magval); X Case DOWN4: X movedown(Getsval(4, fp) * magval); X X // move vertically based on the var Y X Case Y0: X movedown(Y); X Case Y1: X movedown(Y = Getsval(1, fp) * magval); X Case Y2: X movedown(Y = Getsval(2, fp) * magval); X Case Y3: X movedown(Y = Getsval(3, fp) * magval); X Case Y4: X movedown(Y = Getsval(4, fp) * magval); X X // move vertically based on the var Z X Case Z0: X movedown(Z); X Case Z1: X movedown(Z = Getsval(1, fp) * magval); X Case Z2: X movedown(Z = Getsval(2, fp) * magval); X Case Z3: X movedown(Z = Getsval(3, fp) * magval); X Case Z4: X movedown(Z = Getsval(4, fp) * magval); X X // change current font X Case FNT1: X newfont(getuval(1, fp)); X Case FNT2: X newfont(getuval(2, fp)); X Case FNT3: X newfont(getuval(3, fp)); X Case FNT4: X newfont(getsval(4, fp)); X X // special - used definable X Case XXX1: X special(fp, getuval(1, fp)); X Case XXX2: X special(fp, getuval(2, fp)); X Case XXX3: X special(fp, getuval(3, fp)); X Case XXX4: X special(fp, getsval(4, fp)); X X // define a font - note that this will be a redefinition X Case FNTDEF1: X definefont(fp, getuval(1, fp), mag); X Case FNTDEF2: X definefont(fp, getuval(2, fp), mag); X Case FNTDEF3: X definefont(fp, getuval(3, fp), mag); X Case FNTDEF4: X definefont(fp, getsval(4, fp), mag); X X Default: X quit("Unexpected opcode %d", opcode); X } X } } X X // read the DVI file and create a list with pointers to every // page in the file - also calculate a section number for each page // static void loadpages(FILE *fp, long pageloc, long numpages, X long §ions, Pageinfo &pages) { X long loc = pageloc; X long lastpage = MAXLONG; X long i; X X sections = 1; X X // search backwards through the DVI file X for (i = numpages - 1; loc >= 0 && i >= 0; i--) X { X (void)fseek(fp, loc, SEEK_SET); X if (getuval(1, fp) != BOP) X quit("Expected BOP"); X X // get the values of the internal TeX variables X // - the first is a page number (c[0]) X long c[10]; X for (int j = 0; j < 10; j++) X c[j] = getsval(4, fp); X loc = getsval(4, fp); // location of previous page in file X X // new section if we see a page larger than the previous one X if (c[0] >= lastpage) X sections++; X lastpage = c[0]; X X // save the "real" page number and the offset in the file X pages[i].page = c[0]; X pages[i].section = sections; X pages[i].loc = ftell(fp); X } X X // now change the section numbers to be in the proper order X for (i = 0; i < numpages; i++) X pages[i].section = sections - pages[i].section + 1; } X X // dump only the specified pages from the DVI file // static void dumppages(FILE *fp, Pagespec &pages, X Pageinfo &allpages, long sections) { X long numpages = allpages.size(); X X for (int i = 0; i < pages.size(); i++) X { X // get the page spec entry in normal or reverse order X long pent = reverse ? pages.size() - i - 1 : i; X X // if the end is not specified, take the current maximum X long endsect = pages[pent].endsection == MAXLONG ? sections X : pages[pent].endsection; X long endpage = pages[pent].endpage == MAXLONG ? numpages X : pages[pent].endpage; X X // print only the last section? make sure we go through loop once X long startsect = pages[pent].section; X if (startsect == MAXLONG) X startsect = endsect; X X for (long s = startsect; s <= endsect; s++) X { X long snum = reverse ? endsect - s + startsect : s; X for (long p = pages[pent].page; p <= endpage; p++) X { X long pnum = reverse ? endpage - p + pages[pent].page : p; X X // look for this page/section in the list of allpages X // - if section == MAXLONG - 1, then use the last section X long ent; X for (ent = numpages - 1; ent >= 0; ent--) X if (allpages[ent].page == pnum X && allpages[ent].section == snum) X break; X X if (ent < 0) X { X // print an error only if the user explicitly specified X // a page that does not exist - do not print an error X // if we are going through to the end X if (pages[pent].section == MAXLONG X || pages[pent].endsection <= pages[pent].section) X if (pages[pent].endpage == MAXLONG X || pages[pent].endpage < pages[pent].page) X if (pages[pent].section <= sections) X continue; X X error("No page/section %ld.%ld in DVI file", pnum, snum); X continue; X } X X // seek to that page and spit it out X (void)fseek(fp, allpages[ent].loc, SEEK_SET); X mesg(" [%ld.%ld", allpages[ent].page, allpages[ent].section); X debug(1, "Page: %ld.%ld (%ld)", allpages[ent].page, X allpages[ent].section, ent + 1); X dopage(fp, allpages[ent].page); X mesg("]"); X } X } X } } X X // dump all the pages in the DVI file in either forward or reverse order // static void dumpall(FILE *fp, Pageinfo &allpages) { X long numpages = allpages.size(); X for (int i = 0; i < numpages; i++) X { X long p = reverse ? numpages - i - 1 : i; X (void)fseek(fp, allpages[p].loc, SEEK_SET); X mesg(" [%ld.%ld", allpages[p].page, allpages[p].section); X debug(1, "Page: %ld.%ld (%ld)", allpages[p].page, X allpages[p].section, p + 1); X dopage(fp, allpages[p].page); X mesg("]"); X } } X X // process the DVI file "fp" - verify the file, setup the fonts, then // print pages in the file either backwards or forwards - print only // that "pages" specified, or everything if none were specified // void dodvi(FILE *fp, Pagespec &pages) { X // verify the preamble and id value X if (getuval(1, fp) != PRE) X quit("Not a DVI file"); X long version = getuval(1, fp); X if (version != ID) X { X debug(7, "DVI file version = %ld instead of %d", version, ID); X quit("Incorrect DVI file version"); X } X X // if we cannot seek, then we cannot do anything X if (fseek(fp, 0, SEEK_END) != 0) X quit("Cannot seek to end of DVI file"); X X long floc = ftell(fp); X debug(2, "DVI file len = %ld", floc); X X // now look for the real end of the DVI file (after the POSTPOST) X register int opcode = FILLER; X while (opcode == FILLER && floc > 0) X { X (void)fseek(fp, --floc, SEEK_SET); X opcode = (int)getuval(1, fp); X } X if (opcode != ID) X { X debug(7, "DVI file version = %d instead of %d", opcode, ID); X quit("Incorrect DVI file version"); X } X X // get the pointer to the start of the postamble X (void)fseek(fp, floc -= 4, SEEK_SET); X long postloc = getuval(4, fp); X (void)fseek(fp, postloc, SEEK_SET); X X // verify that we are where we think we are X if (getuval(1, fp) != POST) X quit("Expected POST"); X X // pointer to the last page in the DVI file X long pageloc = getsval(4, fp); X X // read in the other values in the postamble X double numerator = Getsval(4, fp); X if (numerator <= 0) X quit("Illegal numerator"); X X double denominator = Getsval(4, fp); X if (denominator <= 0) X quit("Illegal denominator"); X X mag = getsval(4, fp); X if (usermag > 0) X mag = usermag; X magval = (double)mag; X if (mag <= 0) X quit("Illegal magnification"); X magval *= numerator / denominator / 25400000.0 * 473628672.0 / 1000.0; X debug(3, "num=%f denom=%f mag=%ld/%f", numerator, denominator, X mag, magval); X X // worst-case page sizes - we ignore these for now X long tallest = getsval(4, fp); X long widest = getsval(4, fp); X long maxdepth = getsval(2, fp); X long numpages = getuval(2, fp); X debug(3, "tallest=%ld widest=%ld maxdepth=%ld", tallest, widest, maxdepth); X debug(1, "numpages=%ld", numpages); X X // scan the opcodes in the rest of the postamble - only font X // definitions and specials are allowed here X while ((opcode = (int)getuval(1, fp)) != POSTPOST) X switch (opcode) X { X Case FNTDEF1: X definefont(fp, getuval(1, fp), mag); X Case FNTDEF2: X definefont(fp, getuval(2, fp), mag); X Case FNTDEF3: X definefont(fp, getuval(3, fp), mag); X Case FNTDEF4: X definefont(fp, getsval(4, fp), mag); X X Case XXX1: X special(fp, getuval(1, fp)); X Case XXX2: X special(fp, getuval(2, fp)); X Case XXX3: X special(fp, getuval(3, fp)); X Case XXX4: X special(fp, getsval(4, fp)); X X Case NOOP: X X Default: X quit("Illegal opcode = %d in font definitions", opcode); X } X X // initialize the page pointer table X Pageinfo allpages(numpages); X long sections; X loadpages(fp, pageloc, numpages, sections, allpages); X X // process the pages as specified X if (pages.size() < 1) X dumpall(fp, allpages); X else X dumppages(fp, pages, allpages, sections); X X mesg(NULL); } SHAR_EOF chmod 0444 dvi.C || echo 'restore of dvi.C failed' Wc_c="`wc -c < 'dvi.C'`" test 11617 -eq "$Wc_c" || echo 'dvi.C: original size 11617, current size' "$Wc_c" fi # ============= font.C ============== if test -f 'font.C' -a X"$1" != X"-c"; then echo 'x - skipping font.C (File already exists)' else echo 'x - extracting font.C (Text)' sed 's/^X//' << 'SHAR_EOF' > 'font.C' && // Copyright (c) 1991 by Parag Patel. All Rights Reserved. static const char rcsid[] = "$Header: font.C,v 1.42 91/04/02 17:59:01 hmgr Exp $"; X // font manipulation and basic typesetting functions // // by Parag Patel X #include "defs.h" X X // local globals static int fontsonpage; // # of fonts on current page static long devv; // current device Vertical coord static long devh; // Horizontal coord (both in pixels) static font *devfont; // current font in device X X font::font() { X chr = new fontchar[MAXCHARS]; X // this initialization is redundant, but safer X fp = NULL; X use = 0; X path = basename = NULL; X onpage = toomany = downloaded = setup = NULL; } X font::~font() { X if (fp != NULL) X fclose(fp); X delete[MAXCHARS] chr; } X // return the fontlist location for the font number specified // - returns one more than the current size if there is no such font static long getfontloc(long fnum) { X for (long f = 0; f < fontlist.size(); f++) X if (fontlist[f] != NULL && fontlist[f]->num == fnum) X break; X return f; } X // clear font info for a new page - there are currently no fonts on // this page - reset the device coordinates to "unknown" - there is no // current font selected, nor a current font in the device // void clearfonts() { X for (int i = 0; i < fontlist.size(); i++) X if (fontlist[i] != NULL) X fontlist[i]->toomany = fontlist[i]->onpage = FALSE; X fontsonpage = 0; X devh = devv = -MAXLONG; X currfont = devfont = NULL; } X X static void setupbits(font &f) { X static long minm = MAXLONG; X static long maxm = -MAXLONG; X static long minn = MAXLONG; X static long maxn = -MAXLONG; X X if (f.minm >= minm && f.maxm <= maxm X && f.minn >= minn && f.maxn <= maxn) X return; X X if (fontbits != NULL) X { X for (long i = maxn - minn; i >= 0; i--) X delete fontbits[i]; X delete fontbits; X } X X if (f.maxm > maxm) X maxm = f.maxm + 10; X if (f.minm < minm) X minm = f.minm - 10; X if (f.maxn > maxn) X maxn = f.maxn + 10; X if (f.minn < minn) X minn = f.minn - 10; X X debug(4, "newbits maxm=%ld minm=%ld maxn=%ld minn=%ld", X maxm, minm, maxn, minn); X X // allocate the memory that we will need X fontbits = new Bitvec *[maxn - minn + 2]; X for (long i = maxn - minn; i >= 0; i--) X fontbits[i] = new Bitvec(maxm - minm + 2); } X X // define a font "fnum" from the file "fp" at the magnification "mag" // - "fp" is a pointer into a DVI file right after the FNTDEF byte // - this function will be called twice for each font - once in the // postamble and once just before it is used (if it is used) // void definefont(FILE *fp, long fnum, long mag) { X // find the font with this number in our fontlist X long floc = getfontloc(fnum); X X // if already loaded, then we are not in the postamble anymore X boolean loaded = (fontlist[floc] != NULL); X X debug(2, "fontnum = %ld(%ld)%s", fnum, floc, loaded ? " loaded" : ""); X X // allocate space for this font, if necessary X if (!loaded) X fontlist[floc] = new font; X X font &f = *fontlist[floc].ptr; X X if (loaded) X { X // ignore the values in the file - we already have them X (void)getsval(4, fp); X (void)getsval(4, fp); X (void)getsval(4, fp); X skipbytes(getuval(1, fp) + getuval(1, fp), fp); X return; X } X X // initialize the font and start reading the values out of the file X f.fp = NULL; X f.use = 0; X f.num = fnum; X f.checksum = getsval(4, fp); X f.scaledsize = getsval(4, fp); X f.designsize = getsval(4, fp); X debug(3, "checksum=%ld scaled=%ld design=%ld", X f.checksum, f.scaledsize, f.designsize); X X f.mag = (long)((double)mag * (double)f.scaledsize / X (double)f.designsize + 0.5); X X // get the name of the font file - if the library name length X // (liblen) is 0, then use the default library directory instead X X int liblen = (int)getuval(1, fp); X int namelen = (int)getuval(1, fp); X X f.path = NULL; X f.basename = new char[namelen + 1]; X int i; X X // read the optional font directory name from the DVI file X if (liblen != 0) X { X // just use what the DVI file has X char *s = f.path = new char[liblen + 1]; X for (i = 0; i < liblen; i++) X *s++ = (unsigned char)getuval(1, fp); X *s = '\0'; X } X X // get the name of the font file to load X char *s = f.basename; X for (i = 0; i < namelen; i++) X *s++ = (unsigned char)getuval(1, fp); X *s = '\0'; X debug(4, "libname=%s basename=%s", X f.path == NULL ? "" : f.path, f.basename); X X // just defined - not yet downloaded - not setup X f.setup = f.downloaded = f.onpage = f.toomany = FALSE; X X // no characters are downloaded either X for (i = 0; i < MAXCHARS; i++) X f.chr[i].downloaded = f.chr[i].charbig = FALSE; } X X // change to a new font "fnum" - this is the FNT DVI command // void newfont(long fnum) { X long f = getfontloc(fnum); X debug(5, "Change to font %ld(%ld)", fnum, f); X X currfont = fontlist[f]; X if (currfont == NULL) X quit("Font %ld(%ld) has not been defined yet", fnum, f); } X X // move the device's cursor to the current H and V values // void makecurrent(boolean force) { X long h = dev_sp2dev(H); X long v = dev_sp2dev(V); X X // use the most efficient move that we can X if (force || (devh != h && devv != v)) X dev_movehv(h, v); X else if (devh != h) X dev_moveh(h); X else if (devv != v) X dev_movev(v); X X debug(8, "lastH=%ld lastV=%ld H=%ld V=%ld", devh, devv, h, v); X X // update the current cursor values X devh = h; X devv = v; } X X static void dumpescape(const char *s, long len) { X for (long i = 0; i < len; s++, i++) X { X if (*s != '\\' && *s != '`') X { X putchar(*s); X continue; X } X s++; X i++; X if (i >= len) X break; X X if (isdigit(*s)) X { X int chr = *s - '0'; X int base = 8; X if (*s == '0') X { X s++; X i++; X switch (isupper(*s) ? tolower(*s) : *s) X { X Case 'b': X base = 2; X Case 'o': X base = 8; X Case 'd': X base = 10; X Case 'x': X base = 16; X Default: X s--; X i--; X } X } X s++; X i++; X for (; isxdigit(*s) && i < len; s++, i++) X { X int d = (islower(*s) ? toupper(*s) : *s) X - (isdigit(*s) ? '0' : 'A' - 10); X if (d >= base) X break; X chr = (chr * base) + d; X } X s--; X i--; X putchar(chr); X continue; X } X X switch (isupper(*s) ? tolower(*s) : *s) X { X Case 'b': X putchar('\b'); X Case 'f': X putchar('\f'); X Case 'n': X putchar('\n'); X Case 'r': X putchar('\r'); X Case 't': X putchar('\t'); X Case 'v': X putchar('\v'); X Case '\\': X putchar('\\'); X Case '`': X putchar('`'); X Case 'e': X putchar('\033'); X Case '?': X putchar('\177'); X Case '^': X s++; X i++; X putchar(*s == '?' ? '\177' : (*s & 037)); X Default: X // putchar('\\'); X putchar(*s); X } X } } X // DVI XXX special command - "num" is the number of bytes in the DVI // file that are for the special command // take the special string as a file name of a raw device-specific // image file and dump it straight to the device // void special(FILE *fp, long num) { X debug(2, "special length = %ld", num); X X // allocate a buffer that is large enough for this length X static char *buf = NULL; X static long blen = 0; X if (num >= blen) X { X if (buf != NULL) X delete buf; X buf = new char[blen = num + 1]; X } X X // read in the data from the DVI file into our buffer X char *s = buf; X for (long i = num; i-- > 0;) X *s++ = (unsigned char)getuval(1, fp); X *s = '\0'; X X // we use the first word (up to a space) for identifying different X // kinds of special files X enum Specials X { X S_NONE = 0, X S_RASTERFILE, X S_ESCAPESEQ, X S_RAWSTRING, X } type; X X // handle special escape-sequences X if (strncmp("escapeseq ", buf, 10) == 0) X { X s = buf + 10; X num -= 10; X type = S_ESCAPESEQ; X debug(4, "Special == escapeseq = %s", s); X mesg(" <<escapeseq"); X makecurrent(); X dev_push(); X dumpescape(s, num); X dev_pop(); X mesg(">>"); X return; X } X X // handle special raw-strings X if (strncmp("rawstring ", buf, 10) == 0) X { X s = buf + 10; X num -= 10; X type = S_RAWSTRING; X debug(4, "Special == rawstring = %s", s); X mesg(" <<rawstring"); X makecurrent(); X dev_push(); X while (num-- > 0) X putchar(*s++); X dev_pop(); X mesg(">>"); X return; X } X X // handle raw file dumps - usually graphics data X if (strncmp("rasterfile ", buf, 11) == 0) X { X s = buf + 11; X type = S_RASTERFILE; X } X else if (strncmp("pcl:", buf, 4) == 0) X { X s = buf + 4; X type = S_RASTERFILE; X } X else X s = buf; X X debug(4, "Special == rasterfile = %s", s); X mesg(" <%s", s); X X // now open this file and dump it to the device X X FILE *sp = fopenp(dviinput, s, F_READ); X if (sp == NULL) X quit("Cannot open \"%s\" for reading", s); X X // move the cursor, and save the current location in the device X makecurrent(); X dev_push(); X X // dump the file X int l; X char dat[1024]; X while ((l = fread(dat, sizeof *dat, sizeof dat, sp)) > 0) X fwrite(dat, sizeof *dat, l, stdout); X X fclose(sp); X X // restore the cursor X dev_pop(); X mesg(">"); } X X // change the current font that is downloaded to the device if we have // to - this is completely demand-driven - a font is never even read into // memory much less downloaded unless a character from it is actually // going to be printed // static void changefont() { X // do we need to download this font? X if (!currfont->downloaded) X { X mesg(" ("); X X if (!currfont->setup) X { X // load in the font info - we're really going to use it X setupfont(*currfont); X setupbits(*currfont); X currfont->setup = TRUE; X } X mesg("%s", currfont->basename); X X static int fontsdown = 0; X currfont->use++; X X if (fontsdown < MAXLOADED) X fontsdown++; X else X { X // we need to delete a font from the device X register int i; X int fn = -1; X long u = MAXLONG; X X // find the least recently used font X for (i = 0; i < fontlist.size(); i++) X if (fontlist[i] != NULL && fontlist[i]->downloaded X && !fontlist[i]->onpage && fontlist[i]->use < u) X { X fn = i; X u = fontlist[i]->use; X } X X // we need too many fonts - dump currfont in graphics mode X if (fn < 0) X { X currfont->toomany = TRUE; X mesg("#)"); X return; X } X X // mark it as not downloaded, then delete it X font &f = *fontlist[fn].ptr; X for (i = 0; i < MAXCHARS; i++) X f.chr[i].downloaded = FALSE; X f.toomany = f.downloaded = FALSE; X dev_delfont(f); X } X X // downloaded this font X dev_newfont(*currfont); X currfont->downloaded = TRUE; X X mesg(")"); X } X X // select this font in the device X dev_usefont(*currfont); X devfont = currfont; X X // if this font is already being used on page, we are done X if (currfont->onpage || currfont->toomany) X return; X currfont->onpage = TRUE; X X // are there too many fonts on this page? if so, mark X // the font as toomany to print it in graphics mode X if (++fontsonpage > MAXONPAGE) X { X debug(3, "too many fonts on page - currfont marked"); X currfont->toomany = TRUE; X mesg("#"); X } } X X // typeset a character - this is the DVI SET or PUT command - if "move" // is TRUE, then the cursor will be moved right by the width of the // character // void typeset(long ch, boolean move, double magval) { X fontchar & gch = currfont->chr[ch]; X X // change the font if we have to X if (currfont != devfont) X changefont(); X X // download the character if we have to - this also gets bigchars X if (!gch.downloaded || gch.charbig || currfont->toomany) X downchar((int)ch, currfont->toomany); X X // print the character if it is not too big X if (!gch.charbig && !currfont->toomany) X { X makecurrent(); X int len; X const char *dat = dev_char2dev((int)ch, len); X fwrite(dat, sizeof *dat, len, stdout); X devh += gch.dx >> 16; X } X X if (move) X moveright(gch.width * magval); } X X // DVI SETRULE or PUTRULE command - again, if "move" is TRUE, then the // cursor is moved to the right, else it isn't // void typerule(FILE *fp, boolean move, double magval) { X double a = Getsval(4, fp) * magval; X double b = Getsval(4, fp) * magval; X X // let the device do the work (if it can) X if (a > 0 && b > 0) X dev_rule(a, b); X X if (move) X moveright(b); } SHAR_EOF chmod 0444 font.C || echo 'restore of font.C failed' Wc_c="`wc -c < 'font.C'`" test 12300 -eq "$Wc_c" || echo 'font.C: original size 12300, current size' "$Wc_c" fi # ============= readfont.C ============== if test -f 'readfont.C' -a X"$1" != X"-c"; then echo 'x - skipping readfont.C (File already exists)' else echo 'x - extracting readfont.C (Text)' sed 's/^X//' << 'SHAR_EOF' > 'readfont.C' && // Copyright (c) 1991 by Parag Patel. All Rights Reserved. static const char rcsid[] = "$Header: readfont.C,v 1.21 91/04/02 17:50:26 hmgr Exp $"; X // read font data from the METAFONT GF (generic font) files // // by Parag Patel X #include "defs.h" X X // maximum number of file that we can keep open at one time - we try to // keep as many font files open at one time as we can instead of // reading the entire font into memory - this should gain a little // speed if only a few characters are loaded from many different fonts // (which is the normal case) // #ifdef _SC_OPEN_MAX const long MAXFILES = sysconf(_SC_OPEN_MAX) - NUMOPENFILES; #else const long MAXFILES = _NFILE - NUMOPENFILES; #endif X static int numfiles = 0; // number of files currently open X X // try looking for a particular type of font file - this is called // multiple times until we succeeding in finding a font we can use // static int tryfile(font &f, char *dir, char *mag, char *base, char *ext) { X static char buf[MAXPATHLEN + 1]; X sprintf(buf, "%s/%s/%s%s", dir, mag, base, ext); X char *path = buf; X FILE *fp = fopen(path, F_READ); X if (fp == NULL) X return FALSE; X X // first byte is a preamble byte - same for GF and PK files X if (getuval(1, fp) != FPRE) X { X fclose(fp); X return FALSE; X } X X // second byte is the font version ID field X f.type = (int)getuval(1, fp); X char *old = f.path; X f.path = path; X switch (f.type) X { X Case GFID: X debug(2, "GF font file %s", path); X setupgffont(f, fp); X Case PKID: X debug(2, "PK font file %s", path); X setuppkfont(f, fp); X Default: X fclose(fp); X f.path = old; X return FALSE; X } X X delete old; X f.path = strdup(path); X old = f.basename; X sprintf(buf, "%s/%s%s", mag, base, ext); X f.basename = strdup(buf); X delete old; X debug(6, "font basename = %s", f.basename); X X // keep only a MAXFILES number of font files open at one time X if (numfiles >= MAXFILES) X { X fclose(fp); X f.fp = NULL; X } X else X { X f.fp = fp; X numfiles++; X } X X return TRUE; } X X // setup a new font in memory - the font is already initialized with // the information from the DVI file - we now have to actually read the // font file (GF or PK) to get the rest of the font's description // void setupfont(font &f) { X if (f.path != NULL) X if (tryfile(f, f.path, "", f.basename, "")) X return; X X // setup the font directory cache if we need to X if (pathlist.size() < 1) X setupdirs(fontpath); X X for (int i = 0; i < pathlist.size(); i++) X { X Pathent & p = pathlist[i]; X X if (tryfile(f, p.path, pkmagdir(p.dirs, f.mag), f.basename, ".pk")) X return; X if (tryfile(f, p.path, gfmagdir(p.dirs, f.mag), f.basename, ".gf")) X return; X if (tryfile(f, p.path, gfmagdir(p.dirs, f.mag), f.basename, "")) X return; X if (tryfile(f, p.path, pkmagdir(p.dirs, f.mag), f.basename, "")) X return; X } X quit("Cannot find font file \"%s\" (at or near magnification %ld.%03ld) anywhere", X f.basename, f.mag / 1000, f.mag % 1000); } X X // dump the current "fontbits" on screen in a human-readable // format - this is really for debugging only // void dumpbits(int ch) { X register long i, j; X font & f = *currfont; X fontchar & g = f.chr[ch]; X X // print a row of 2-digit X coordinate values across the top X fprintf(stderr, " "); X for (j = 0; j <= g.maxm - g.minm; j++) X fprintf(stderr, "%2ld", j + g.minm); X fprintf(stderr, "\n\n"); X X // print the Y coordinate on both sides of each row of pixels X for (i = g.maxn - g.minn; i >= 0; i--) X { X fprintf(stderr, "%3ld ", i + g.minn); X for (j = 0; j <= g.maxm - g.minm; j++) X fprintf(stderr, "%s", fontbits[i]->isin(j) ? "[]" : " ."); X fprintf(stderr, " %3ld\n", i + g.minn); X } X X // and finally another row of X-coords across the bottom X fprintf(stderr, "\n "); X for (j = 0; j <= g.maxm - g.minm; j++) X fprintf(stderr, "%2ld", j + g.minm); X fprintf(stderr, "\n"); } X X // down load the specified character "ch" to the device - we read this // character's GF paint commands to build a bitmap of the character in // memory - then we download this image to the printer // void downchar(int ch, boolean toomany) { X font & f = *currfont; X fontchar & g = f.chr[ch]; X X // is this font file open? X if (f.fp == NULL) X { X // we need to close another font file if we already have the X // maximum number open X if (numfiles >= MAXFILES) X { X register int i; X int fn = -1; X long u = MAXLONG; X X // look for the least-recently used font X for (i = 0; i < fontlist.size(); i++) X if (fontlist[i] != NULL && fontlist[i]->fp != NULL X && fontlist[i]->use < u) X { X fn = i; X u = fontlist[i]->use; X } X if (fn < 0) X quit("Cannot open another font file - all fonts are in use"); X X // close this font file X fclose(fontlist[fn]->fp); X fontlist[fn]->fp = NULL; X numfiles--; X mesg("@"); X } X X // open the new font file X f.fp = fopen(f.path, F_READ); X if (f.fp == NULL) X quit("Cannot re-open font file \"%s\"", f.path); X numfiles++; X } X X switch (f.type) X { X Case GFID: X getgfchar(f, g, ch); X Case PKID: X getpkchar(f, g, ch); X Default: X quit("?!BUG? Internal font type id changed"); X } X X // show what this character looks like X if (debuglevel > 12) X dumpbits(ch); X X // now download this character to the printer... X X long width = g.maxm - g.minm + 1; X long height = g.maxn - g.minn + 1; X if (toomany || g.minm < FHMIN || g.minm > FHMAX || width > FWIDTH X || g.maxn < FVMIN || g.maxn > FVMAX || height > FHEIGHT) X { X // char is too big - send it down as a graphics X // image but do NOT mark it as downloaded X if (!toomany) X g.charbig = TRUE; X dev_bigchar(f, g, ch); X return; X } X X // this is the usual method... X g.downloaded = TRUE; X dev_downchar(f, g, ch); } SHAR_EOF chmod 0444 readfont.C || echo 'restore of readfont.C failed' Wc_c="`wc -c < 'readfont.C'`" test 5861 -eq "$Wc_c" || echo 'readfont.C: original size 5861, current size' "$Wc_c" fi # ============= gffont.C ============== if test -f 'gffont.C' -a X"$1" != X"-c"; then echo 'x - skipping gffont.C (File already exists)' else echo 'x - extracting gffont.C (Text)' sed 's/^X//' << 'SHAR_EOF' > 'gffont.C' && // Copyright (c) 1991 by Parag Patel. All Rights Reserved. static const char rcsid[] = "$Header: gffont.C,v 1.20 91/02/22 15:58:04 hmgr Exp $"; X // read font data from the METAFONT GF (generic font) files // // by Parag Patel X #include "defs.h" X X // these are for "drawing" an image of a character in a font const int WHITE = FALSE; const int BLACK = TRUE; X X // return a string containing the magnification sub-directory for the // requested magnification // char *gfmagdir(Dirlist &dirlist, long mag) { X // look for the closest magnification value to the one desired X int ent = -1; X long diff = MAXLONG; X X for (int i = 0; i < dirlist.size(); i++) X { X long d = mag - dirlist[i].val; X long newdiff = d < 0 ? -d : d; // absolute value X if (newdiff >= diff) X continue; X diff = newdiff; X ent = i; X } X X // we should be within 1/32 (.03%) of the desired mag value X if (ent < 0 || diff > (mag >> 5)) X return ""; X X // return the new value as a string X return dirlist[ent].name; } X X // setup a GF font file in memory // void setupgffont(font &f, FILE *fp) { X // skip the comment X int len = (int)getuval(1, fp); X while (len-- > 0) X (void)getuval(1, fp); X X // now we jump to the end to find the postamble X if (fseek(fp, 0, SEEK_END) != 0) X quit("Cannot seek to end of GF file %s", f.path); X X register int op = GFILLER; X long floc = ftell(fp); X X // skip the filler bytes at the end of the file X while (op == GFILLER && floc > 0) X { X (void)fseek(fp, --floc, SEEK_SET); X op = (int)getuval(1, fp); X } X if (op != GFID) X quit("Incorrect GF version for %s", f.path); X X // now we get the file-pointer to the start of the postamble X (void)fseek(fp, floc -= 4, SEEK_SET); X long postloc = getuval(4, fp); X X // verify that we have a POST byte X (void)fseek(fp, postloc, SEEK_SET); X if (getuval(1, fp) != FPOST) X quit("Expected FPOST"); X X long fsize = getuval(4, fp);// pointer to last EOC in file X debug(3, "GF last EOC=%ld", fsize); X X // get and verify that the design size is ok - the GF file stores X // this value as a "fix_word" value while the DVI file keeps it as X // a "scaled-point" value - also note that the "basename" pointer X // is NULL only for the "dumpfont" main program X X long dsize = getsval(4, fp); X debug(4, "GF designsize=%ld", dsize); X if (f.basename != NULL && dsize >> 4 != f.designsize) X if (dochecksum && dsize != 0 && f.designsize != 0) X quit("Designsize in DVI and GF file %s does not match", f.path); X else X warn("Designsize in DVI and GF file %s does not match", f.path); X X // check the checksum (!) X long check = getuval(4, fp); X debug(5, "GF checksum=%ld", check); X if (f.basename != NULL && check != f.checksum) X if (dochecksum && check != 0 && f.checksum != 0) X quit("Checksums in DVI and GF file %s do not match", f.path); X else X warn("Checksums in DVI and GF file %s do not match", f.path); X X // get the horizontal and vertical pixels per point values X f.hppp = getuval(4, fp); X f.vppp = getuval(4, fp); X X // get the size ranges of the characters in this font X f.minm = getsval(4, fp); X f.maxm = getsval(4, fp); X f.minn = getsval(4, fp); X f.maxn = getsval(4, fp); X X debug(3,"mag=%ld hppp=%ld vppp=%ld minm=%ld maxm=%ld minn=%ld, maxn=%ld", X f.mag, f.hppp, f.vppp, f.minm, f.maxm, f.minn, f.maxn); X X // now initialize the info for each character in this font - note X // that there may only be CHARLOC or NOOPs in this part of the file X while ((op = (int)getuval(1, fp)) != FPOSTPOST) X { X if (op == FNOOP) X continue; X X // assume that the next byte is a character "residue" (id % 256) X int c = (int)getuval(1, fp); X if (c >= MAXCHARS) X quit("Char %d too big in GF file %s", c, f.path); X fontchar & g = f.chr[c]; X X // get the values for delta-x, delta-y, width, and file-pointer X // for this character X switch (op) X { X Case CHARLOC: X g.dx = getuval(4, fp); X g.dy = getuval(4, fp); X g.width = Getsval(4, fp); X g.floc = getsval(4, fp); X X Case CHARLOC0: X g.dx = getuval(1, fp) << 16; X g.dy = 0; X g.width = Getsval(4, fp); X g.floc = getsval(4, fp); X X Default: X quit("Illegal opcode %d in GF postamble", op); X } X X g.width = g.width / double(16) * double(f.designsize) / X double(65536L) * double(f.mag) / 1000.0; X } } X X // load the specified character "ch" into the bitmap - we read this // character's GF paint commands to paint this font // void getgfchar(font &f, fontchar &g, int ch) { X // go to the file where this character is defined X if (fseek(f.fp, g.floc, SEEK_SET) < 0) X quit("Cannot fseek to start of font in %s", f.path); X X register int op = (int)getuval(1, f.fp); X X // we had better get some flavor of BOC here... X switch (op) X { X Case BOC: X // verify the character (Just In Case) X if (ch != getsval(4, f.fp)) X quit("Character definition for %d does not match", ch); X X (void)getuval(4, f.fp); // pointer to next character % 256 X X // get the size (in pixels) of this character X g.minm = getsval(4, f.fp); X g.maxm = getsval(4, f.fp); X g.minn = getsval(4, f.fp); X g.maxn = getsval(4, f.fp); X X Case BOC1: X if (ch != getuval(1, f.fp)) X quit("Character definition for %d does not match", ch); X X // decode the size (in pixels) of this character X g.minm = getuval(1, f.fp); X g.maxm = getuval(1, f.fp); X g.minm = g.maxm - g.minm; X X g.minn = getuval(1, f.fp); X g.maxn = getuval(1, f.fp); X g.minn = g.maxn - g.minn; X X Default: X quit("Expected BOC* (not %d) in font file %s for char %d", X op, f.path, ch); X } X X { X int len; X const char *x = dev_char2dev(ch, len); X debug(5, "char=%d(%s) minm=%ld maxm=%ld minn=%ld maxn=%ld", X ch, x, g.minm, g.maxm, g.minn, g.maxn); X debug(5, " dx=%ld dy=%ld dx/=%ld dy/=%ld width=%f", g.dx, g.dy, X g.dx >> 16, g.dy >> 16, g.width); X } X X // initialize the character painting variables X register long m = 0; X register long n = g.maxn - g.minn; X int p = WHITE; X X long width = g.maxm - g.minm + 1; X long height = g.maxn - g.minn + 1; X X // clear the global fontbits for the bitmap X register long d; X for (d = f.maxn - f.minn; d >= 0; d--) X fontbits[d]->clear(); X X // paint the fontbits to build the character X while ((op = (int)getuval(1, f.fp)) != EOC) X { X if (op > PAINT0 && op <= PAINT63) X { X // paint with the current color, advance X X if (p == BLACK) X while (op-- > 0) X *fontbits[n] += m++; X else X m += op; X p = !p; X continue; X } X if (op >= NEWROW0 && op <= NEWROW164) X { X // advance Y, paint to black X n--; X m = op - NEWROW0; X p = BLACK; X continue; X } X X switch (op) X { X // paint with current color, advange X X Case PAINT0: X p = !p; X Case PAINT1: X d = getuval(1, f.fp); X if (p == BLACK) X while (d-- > 0) X *fontbits[n] += m++; X else X m += d; X p = !p; X Case PAINT2: X d = getuval(2, f.fp); X if (p == BLACK) X while (d-- > 0) X *fontbits[n] += m++; X else X m += d; X p = !p; X Case PAINT3: X d = getuval(3, f.fp); X if (p == BLACK) X while (d-- > 0) X *fontbits[n] += m++; X else X m += d; X p = !p; X X // advance Y, paint to white X Case SKIP0: X n--; X m = 0; X p = WHITE; X Case SKIP1: X n -= getuval(1, f.fp) + 1; X m = 0; X p = WHITE; X Case SKIP2: X n -= getuval(2, f.fp) + 1; X m = 0; X p = WHITE; X Case SKIP3: X n -= getuval(3, f.fp) + 1; X m = 0; X p = WHITE; X X // special opcodes - just ignore for now X Case FXXX1: X skipbytes(getuval(1, f.fp), f.fp); X Case FXXX2: X skipbytes(getuval(2, f.fp), f.fp); X Case FXXX3: X skipbytes(getuval(3, f.fp), f.fp); X Case FXXX4: X skipbytes(getuval(4, f.fp), f.fp); X X // special numeric opcode - also ignored X Case YYY: X (void)getuval(4, f.fp); X X Case FNOOP: X X Default: X quit("Illegal GF opcode %ld in file %f", d, f.path); X } X } } SHAR_EOF chmod 0444 gffont.C || echo 'restore of gffont.C failed' Wc_c="`wc -c < 'gffont.C'`" test 7918 -eq "$Wc_c" || echo 'gffont.C: original size 7918, current size' "$Wc_c" fi true || echo 'restore of pkfont.C failed' echo End of part 2, continue with part 3 exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.