summaryrefslogtreecommitdiff
path: root/dviware/ivd2dvi/auxiliary.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/ivd2dvi/auxiliary.c
Initial commit
Diffstat (limited to 'dviware/ivd2dvi/auxiliary.c')
-rw-r--r--dviware/ivd2dvi/auxiliary.c591
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);
+}