diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/ivd2dvi/auxiliary.c |
Initial commit
Diffstat (limited to 'dviware/ivd2dvi/auxiliary.c')
-rw-r--r-- | dviware/ivd2dvi/auxiliary.c | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/dviware/ivd2dvi/auxiliary.c b/dviware/ivd2dvi/auxiliary.c new file mode 100644 index 0000000000..c6fa51a3e1 --- /dev/null +++ b/dviware/ivd2dvi/auxiliary.c @@ -0,0 +1,591 @@ +/* + * Auxiliary routines for ivd2dvi. Copyright 1988 by Larry Denenberg. + * May be freely distributed as long as this notice is retained. + */ + + +#include <stdio.h> +#include "commands.h" +#include "global.h" + +/* Procedures and global variables defined in io.c */ +extern unsigned BufSize; +extern unsigned_byte CopyByte(), ReadByte(), FReadByte(); +extern long FReadUnsigned(), FReadSigned(), ReadUnsigned(), ReadSigned(); +extern long CopyWord(); +extern void WriteByte(), CopyNBytes(), SkipNBytes(), FSkipNBytes(); +extern void InitIOBuffers(), BufOverflow(), WriteNumber(); + +/* Global variables defined in ivd2dvi.c */ +extern char *ProgramName; +extern long XInput, XOutput, WInput, WOutput, DeltaH; +extern int State; +extern boolean ExactOutput; + + +/* Global variables defined here */ +int FilePushLevel; /* current excess of PUSH over POP */ +int MaxFilePushLevel; /* maximum FilePushLevel seen so far */ +char *TeXFontDirs; /* directories to search for TFM files */ +int NTeXFontDirs; /* number of directories in TeXFontDirs */ +FILE *tfmfp; /* fp for currently open TFM file */ +font *CurFont; /* font from which we're typesetting */ +font *FirstFont; /* head of linked list of all fonts */ +long *AuxStackPointer; /* first unused spot on the aux stack */ +long *AuxBeginStack; /* first usable spot on the aux stack */ +long *AuxEndStack; /* first location beyond the aux stack */ + + +/* Procedures defined in this file, in order of definition */ +void Initializations(); +void PushWX(), PopXW(), PushDeltaH(), PopDeltaH(), AuxPush(); +long AuxPop(); +void PushWrite(), PopWrite(), MaxPushLevelOutput(); +font *FindFont(); +void FontDefine(), NewFont(); +long WordMaybeRead(); +unsigned_byte ByteMaybeRead(); +void CopyFontDefinition(), SkipFontDefinition(); +long CharWidth(); +void ReadTFMFile(); +boolean TFMOpen(), TFMTrialOpen(); +void TFMHeaderLoad(), TFMWidthsLoad(), FontMemoryOverflow(); +void BadDVIAbort(); + + + +/* + * Global initializations. At this point, the command line has been + * processed, so we know /BufSize/ and /ProgramName/. After trivial + * initializations, we change /TeXFontDirs/ from a colon-separated list + * to a sequence of null-terminated strings by simply changing each + * colon to a null and keeping a count in /NTeXFontDirs/. Finally, we + * set up the /AuxStack/ along with its pointer and end; giving it + * four times the size of a small stack since /PushWX/ puts four things + * on it at a time. + */ +void +Initializations() +{ + char *pchar; + + State = LTYPESETTING; + CurFont = FirstFont = NULL; + MaxFilePushLevel = FilePushLevel = 0; + InitIOBuffers(); + + TeXFontDirs = getenv("TEXFONTS"); + if (TeXFontDirs == NULL) TeXFontDirs = TFMAREADEFAULT; + if (*TeXFontDirs == ':') TeXFontDirs++; + for (NTeXFontDirs = 0, pchar = TeXFontDirs; *pchar; NTeXFontDirs++) { + while (*pchar && (*pchar != ':')) pchar++; + if (*pchar == ':') *pchar++ = '\0'; + } + + AuxBeginStack = SEQALLOC(4*(BufSize/SMALLBUFDIVISOR), long); + AuxEndStack = AuxBeginStack + 4*(BufSize/SMALLBUFDIVISOR); + AuxStackPointer = AuxBeginStack; + if (AuxBeginStack == NULL) { + fprintf(stderr, "\n%s fatal error: can't allocate buffers\n", + ProgramName); + exit(3); + } +} + + + +/* + * Save the horizontal motion parameters on the aux stack. + */ +void +PushWX() +{ + AuxPush(WInput); + AuxPush(WOutput); + AuxPush(XInput); + AuxPush(XOutput); +} + + + +/* + * Restore the horizontal motion parameters from the aux stack. + */ +void +PopXW() +{ + XOutput = AuxPop(); + XInput = AuxPop(); + WOutput = AuxPop(); + WInput = AuxPop(); +} + + + +/* + * Save /DeltaH/. We use the same stack as /PushWX/; only /EndReflect/ + * has to worry about the necessary stack discipline. + */ +void +PushDeltaH() +{ + AuxPush(DeltaH); +} + + + +/* + * Restore /DeltaH/. + */ +void +PopDeltaH() +{ + DeltaH = AuxPop(); +} + + + +/* + * Push /value/ onto the auxiliary stack. + */ +void +AuxPush(value) +long value; +{ + *AuxStackPointer++ = value; + if (AuxStackPointer >= AuxEndStack) BufOverflow(); +} + + + +/* + * Pop a value from the auxiliary stack. Underflow means that + * something is seriously wrong; even bad input shouldn't do it. + */ +long +AuxPop() +{ + if (--AuxStackPointer < AuxBeginStack) { + fprintf(stderr, "\n%s internal error: simulation stack underflow\n", + ProgramName); + exit(4); + } + return *AuxStackPointer; +} + + + +/* + * Write a PUSH command to the output DVI file. All such commands must + * be written by this routine so we can keep an accurate count of how + * deep we are. /FilePushLevel/ keeps this count and /MaxFilePushLevel/ + * keeps track of the deepest we've ever been. (This routine should be + * called WritePush, but then its name would conflict with WritePop.) + */ +void +PushWrite() +{ + WriteByte(PUSH); + if (++FilePushLevel > MaxFilePushLevel) + MaxFilePushLevel = FilePushLevel; +} + + + +/* + * Write a POP command to the output DVI file. All such commands must + * be written by this routine, so we can keep an accurate count of how + * deep we are. The error here shouldn't occur no matter what garbage + * is in the DVI file since this stuff is checked at an even lower + * level; see /NestingValidate/ in io.c. + */ +void +PopWrite() { + WriteByte(POP); + if (--FilePushLevel < 0) { + fprintf(stderr, "\n%s internal error: more pops than pushes!\n", + ProgramName); + exit(4); + } +} + + + +/* + * Write out the maximum stack depth necessary to process this file. + * That number is exactly /MaxFilePushLevel/, as computed by the two + * routines immediately preceding. However, we start by reading the + * old value, and use it instead if it's big enough and the -X flag + * was used. Here's the reason: TeX doesn't always put the correct + * value in this field! If TeX is writing out a POP that immediately + * follows a PUSH, they are both dropped and nothing goes to the DVI + * file. But the variable that's worrying about the maximum stack + * depth is not informed of this optimization. So if TeX tries to + * write "PUSH PUSH PUSH POP POP POP" it thinks that the max stack + * depth is 3, but in fact nothing is written. Thus TeX's behavior + * is always conservative. See paragraphs 601, 619, and 629 of + * Volume B of {\it Computers and Typesetting}. + */ +void +MaxPushLevelOutput() +{ + long inputlevel; + + inputlevel = ReadUnsigned(2); + if (ExactOutput && (inputlevel > MaxFilePushLevel)) + WriteNumber(inputlevel, 2); + else + WriteNumber((long) MaxFilePushLevel, 2); +} + + + + +/* + * Find the font associated with /fontnumber/ by searching the list. + * If it's not there, return NULL and let the caller worry. + */ +font * +FindFont(fontnumber) +long fontnumber; +{ + font *f; + + f = FirstFont; + while ((f != NULL) && (f->number != fontnumber)) f = f->nextfont; + return f; +} + + + + +/* + * Define a new font as required by a FNT_DEFn command. If the font is + * already known, we must have seen this FNT_DEFn before---skip it if + * simulating, otherwise copy it over. (A given FNT_DEFn command may be + * seen any number of times because we must process them whether we're + * simulating or typesetting.) Call /NewFont/ on never-yet-seen fonts. + */ +void +FontDefine(bytes) +unsigned bytes; +{ + long fontnumber; + + fontnumber = ReadUnsigned(bytes); + if (FindFont(fontnumber) == NULL) + NewFont(fontnumber, bytes); + else if (State >= SIMULATING) + SkipFontDefinition(); + else + CopyFontDefinition(fontnumber, bytes); +} + + + +/* + * Process a font for the first time. If we're not simulating, we must + * copy the FNT_DEFn command and parameters into the output file as we + * read them. Allocate the new font object and link it into the list. + * Fill in the /number/, /checksum/, /scalefactor/, /area/, and /name/ + * fields from the arguments (skip the design size; we don't need it). + * Set /loaded/ to FALSE to indicate that we haven't read the TFM file. + * Only when we need the width of a character in the font---when + * /CharWidth/ is called---do we load the TFM file and fill in the rest + * of the fields. That is, we never read the TFM files of fonts that + * aren't used in reflected text. + */ +void +NewFont(fontnumber, bytes) +long fontnumber; +unsigned bytes; +{ + font *newfont; + unsigned areasize, namesize; + char *p; + + if (State < SIMULATING) { + WriteByte(FNT_DEF1 + bytes - 1); + WriteNumber(fontnumber, bytes); + } + newfont = OBJALLOC(font); + if (newfont == NULL) FontMemoryOverflow(); + newfont->nextfont = FirstFont; + FirstFont = newfont; + newfont->number = fontnumber; + newfont->checksum = WordMaybeRead(); + newfont->scalefactor = WordMaybeRead(); + WordMaybeRead(); + areasize = ByteMaybeRead(); + namesize = ByteMaybeRead(); + newfont->area = (char *) calloc(areasize+1, sizeof(char)); + if (newfont->area == NULL) FontMemoryOverflow(); + for (p = newfont->area; areasize != 0; areasize--) *p++ = ByteMaybeRead(); + *p = '\0'; + newfont->name = (char *) calloc(namesize+1, sizeof(char)); + if (newfont->name == NULL) FontMemoryOverflow(); + for (p = newfont->name; namesize != 0; namesize--) *p++ = ByteMaybeRead(); + *p = '\0'; + newfont->loaded = FALSE; +} + + + +/* + * Either read or copy a word, depending on whether we're simulating. + * This routine and the next are useful because the definition of a + * font might be seen for the first time during a simulation or + * during normal left-to-right typesetting. Thus /NewFont/ might or + * might not want to copy out parameters as they're read. + */ +long +WordMaybeRead() +{ + if (State >= SIMULATING) return ReadSigned(4); else return CopyWord(); +} + + + +/* + * Either read or copy a byte, depending on whether we're simulating. + */ +unsigned_byte +ByteMaybeRead() +{ + if (State >= SIMULATING) return ReadUnsigned(1); else return CopyByte(); +} + + + +/* + * Copy a font definition from the input DVI file to the output file. + */ +void +CopyFontDefinition(fontnumber, bytes) +long fontnumber; +unsigned bytes; +{ + WriteByte(FNT_DEF1 + bytes - 1); + WriteNumber(fontnumber, bytes); + CopyNBytes(12L); + CopyNBytes((long) (CopyByte() + CopyByte())); +} + + + +/* + * Skip by a font definition. The FNT_DEFn command and the first + * parameter have already been skipped. + */ +void +SkipFontDefinition() +{ + SkipNBytes(12L); + SkipNBytes((long) (ReadUnsigned(1) + ReadUnsigned(1))); +} + + + + +/* + * Find the width of character /c/ in /CurFont/. If the TFM file hasn't + * been read, read it. The /widths/ field is NULL in fonts whose TFM + * files we couldn't find; we just return 0 as the width of any character + * in such a font. Carefully reduce /c/ modulo 256 if necessary. If /c/ + * is now between /bc/ and /ec/, it's a character in the font. Get its + * value from the /charwidths/ table (whose indices run from 0 to + * /ec/-/bc/) and use that number to index the /widths/ table. If /c/ + * isn't in the font, issue a warning and return 0. + */ +long +CharWidth(c) +long c; +{ + if (CurFont->loaded == FALSE) ReadTFMFile(CurFont); + if (CurFont->widths == NULL) return 0L; + if (c < 0) c = 255 - ((-1 - c) % 256); + else if (c >= 256) c = c % 256; + if ((c >= CurFont->bc) && (c <= CurFont->ec) && + (CurFont->charwidths[c - CurFont->bc] != 0)) + return CurFont->widths[CurFont->charwidths[c - CurFont->bc]]; + fprintf(stderr, "\n%s warning: character %d undefined in font %s\n", + ProgramName, c, CurFont->name); + return 0L; +} + + + + +/* + * Read in the width information for a font. This data isn't read until + * we actually need it, viz., the first time /CharWidth/ is called with + * /f/ in /CurFont/. If we can't find the TFM file, we set /f->widths/ + * to NULL as a flag meaning "assume all widths are zero." In any case, + * we mark /f/ as "loaded" so we don't do this again. + */ +void +ReadTFMFile(f) +font *f; +{ + if (TFMOpen(f)) { + TFMHeaderLoad(f); + TFMWidthsLoad(f); + (void) fclose(tfmfp); + } else + f->widths = NULL; + f->loaded = TRUE; +} + + + +/* + * Open the TFM file for a font, returning TRUE if we did so and FALSE + * otherwise. If the name of the font starts with a slash, we only + * try to open the exact file. Otherwise we try prepending each of + * the possible TFM directories until we get a hit or run out. Recall + * that at this point /TeXFontDirs/ is a null-separated list of names. + */ +boolean +TFMOpen(f) +font *f; +{ + char *pchar; + int ndir; + + if ((*f->area == '/') || ((!*f->area) && (*f->name == '/'))) { + if (TFMTrialOpen("", f->area, f->name)) return TRUE; + } else { + for (pchar = TeXFontDirs, ndir = NTeXFontDirs; ndir > 0; ndir--) { + if (TFMTrialOpen(pchar, f->area, f->name)) return TRUE; + while (*pchar++); + } + } + fprintf(stderr, "\n%s warning: Can't find TFM file for font %s; ", + ProgramName, f->name); + fprintf(stderr, "assuming zero width\n"); + return FALSE; +} + + + +/* + * Try to open a font file. The "area" is mostly empty for TeX, but + * you never can tell. On success, leave the file descriptor in the + * global variable /tfmfp/ and return TRUE, otherwise return FALSE. + */ +boolean +TFMTrialOpen(path,area,name) +char *path, *area, *name; +{ + static char buffer[MAXFILENAMESIZE]; + + (void) sprintf(buffer, "%s/%s/%s.tfm", path, area, name); + tfmfp = fopen(buffer, "r"); + if (tfmfp == NULL) return FALSE; else return TRUE; +} + + + +/* + * Set up the remaining fields of the font structure. Get and store + * the first and last character codes and the number of distinct widths + * in the font. Allocate the tables /charwidths/ and /widths/. Check + * the checksum, but skip by the rest of the header. Finally, read the + * values into the /charwidths/ table. + */ +void +TFMHeaderLoad(f) +font *f; +{ + int nchars; + long lh; + unsigned_byte *pbyte; + + FSkipNBytes(tfmfp,2L); + lh = FReadUnsigned(tfmfp,2); + f->bc = FReadUnsigned(tfmfp,2); + f->ec = FReadUnsigned(tfmfp,2); + nchars = f->ec - f->bc + 1; + if (nchars < 0) nchars = 0; + if (nchars > 0) { + f->charwidths = SEQALLOC(nchars, unsigned_byte); + if (f->charwidths == NULL) FontMemoryOverflow(); + } + f->nw = FReadUnsigned(tfmfp,2); + if (f->nw > 0) { + f->widths = SEQALLOC(nchars, long); + if (f->widths == NULL) FontMemoryOverflow(); + } + FSkipNBytes(tfmfp,14L); + if (f->checksum != FReadSigned(tfmfp,4)) + fprintf(stderr, "\n%s warning: checksum mismatch on font %s\n", + ProgramName, f->name); + FSkipNBytes(tfmfp, 4*lh - 4); + for (pbyte = f->charwidths; nchars > 0; nchars--) { + *pbyte++ = FReadByte(tfmfp); + FSkipNBytes(tfmfp,3L); + } +} + + + +/* + * Read the character widths of a font from the TFM file and convert + * to DVI units, a calculation that must be done with extreme care. + * Further explanation is punted to section 571 of volume B of the + * Encyclop\ae dia TeXnica. The results go into the /widths/ table. + */ +void +TFMWidthsLoad(f) +font *f; +{ + int nwidths; + unsigned_byte a,b,c,d; + long *pwidth,z,alpha,beta; + + z = f->scalefactor; + alpha = 16; + while (z >= 040000000L) { z = z/2; alpha = alpha+alpha; } + beta = 256/alpha; + alpha *= z; + nwidths = f->nw; + for (pwidth = f->widths; nwidths > 0; nwidths--) { + a = FReadByte(tfmfp); b = FReadByte(tfmfp); + c = FReadByte(tfmfp); d = FReadByte(tfmfp); + *pwidth = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta; + if (a != 0) { + if (a != 255) { + fprintf(stderr, "\n%s fatal error: Bad TFM file for font %s\n", + ProgramName, f->name); + exit(2); + } else *pwidth -= alpha; + } + pwidth++; + } +} + + + +/* + * Do you need comments for this one? + */ +void +FontMemoryOverflow() +{ + fprintf(stderr, "\n%s: Insufficient memory for font definitions\n", + ProgramName); + exit(3); +} + + + +/* + * Abort the run due to junk in the input. + */ +void +BadDVIAbort(message) +char *message; +{ + fprintf(stderr, "\n%s: Malformed DVI file (%s)\n", ProgramName, message); + exit(2); +} |