DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T a

⟦1bcf0cce6⟧ TextFile

    Length: 15650 (0x3d22)
    Types: TextFile
    Names: »auxiliary.c«

Derivation

└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
    └─⟦this⟧ »./DVIware/ivd2dvi/auxiliary.c« 
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z« 
        └─⟦ca79c7339⟧ 
            └─⟦this⟧ »DVIware/ivd2dvi/auxiliary.c« 

TextFile

/*
 *  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);
}