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 i

⟦defc8b611⟧ TextFile

    Length: 12326 (0x3026)
    Types: TextFile
    Names: »io.c«

Derivation

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

TextFile

/*
 *  Input/output routines for ivd2dvi.  Copyright 1988 by Larry Denenberg.
 *  May be freely distributed as long as this notice is retained.
 *  
 *  Here are the naming conventions for input routines: A routine is named
 *  "Read..." if it merely reads something from standard input, e.g.
 *  /ReadByte/, /ReadSigned/.  Recall that the input DVI file always
 *  comes via standard input.  As in C, there are routines "FRead..."
 *  whose first argument is of type FILE*; these read from an arbitrary
 *  file and are used to read TFM files.  We also have the "Copy..."
 *  routines; these are just like their "Read..." counterparts but also
 *  copy every byte read to the output DVI file.  There are no "FCopy..."
 *  routines for obvious reasons.  The routine /CopyNBytes/ has no "Read"
 *  analogue because it returns no value.
 */


#include <stdio.h>
#include "global.h"
#include "commands.h"

/* Procedure and global variable defined in auxiliary.c */
extern void BadDVIAbort();
extern font *CurFont;

/* Global variables defined in ivd2dvi.c */
extern int State;
extern char *ProgramName;

/* Global variables defined here */
unsigned BufSize = BUFDEFAULTSIZE;	/* buffer size, mutable with -b	*/
unsigned_byte *Buffer;		/* first char of input buffer		*/
unsigned_byte *BufEnd;		/* pointer just beyond buffer area	*/
unsigned_byte *BufFirstNonchar;	/* first unused spot; save input here	*/
unsigned_byte *BufPointer;	/* pointer into buffer; read from here	*/
boolean ReadingCommand = FALSE;	/* true iff reading a DVI main command 	*/
unsigned_byte *VStack;		/* start of nesting validation stack	*/
unsigned_byte *VEnd;		/* pointer just beyond vstack area	*/
unsigned_byte *VPointer;	/* vstack pointer to first unused slot	*/
long BytesOutput = 0L;		/* number of bytes written to output	*/


/* Procedures defined in this file, in order of definition */
void InitIOBuffers();
unsigned_byte ReadByte();
void NestingValidate(), BufOverflow();
unsigned_byte ReadCommand(), CopyByte(), FReadByte();
void SkipNBytes(), FSkipNBytes(), CopyNBytes();
long ReadUnsigned(), FReadUnsigned(), ReadSigned(), FReadSigned();
long CopyWord(), CopyUnsigned();
unsigned_byte *ReadFilePosition();
void ResetFilePosition(), RereadLastByte();
void WriteByte(), WriteWord(), WriteNumber(), WriteString();
unsigned SignedBytes();



/*
 *  Initialize two of the three main memory areas in ivd2dvi.  The
 *  size of each is a function of the value /BufSize/ which can be
 *  changed by the user with the -b flag.  So the user doesn't need to
 *  know that there are lots of buffers with different sizes;  if there's
 *  not enough room, using the -b flag will make them all bigger.
 */
void
InitIOBuffers()
{
  Buffer = SEQALLOC(BufSize, unsigned_byte);
  BufPointer = NULL;
  BufFirstNonchar = Buffer;
  BufEnd = Buffer + BufSize;

  VStack = SEQALLOC(BufSize/SMALLBUFDIVISOR, unsigned_byte);
  VPointer = VStack;
  VEnd = VStack + BufSize/SMALLBUFDIVISOR;

  if ((Buffer == NULL) || (VStack = NULL)) {
    fprintf(stderr, "\n%s fatal error: can't allocate buffers\n",
		    ProgramName);
    exit(3);
  }
}




/*
 *  Read a byte from the input DVI file.  All input routines that read
 *  standard input must come through here.
 *
 *  The problem to worry about is that ivd2dvi frequently needs to reread
 *  input.  Rather than doing seeks, we've (perhaps foolishly) decided to
 *  buffer input so we can see it again later.  This means that ivd2dvi is
 *  a true filter, which is a useless advantage since TeX doesn't write
 *  its standard output and since most dvi drivers (dvi2ps in particular)
 *  need real files and can't read standard input.
 *
 *  Now, we don't buffer *all* input, since we know that only if we're
 *  simulating will we need to reread the input.  So anytime we're
 *  reading from the real input file and we're simulating, we save the
 *  character in the buffer.
 *
 *  /BufPointer/ is the place in the buffer from which we're reading
 *  saved input.  It also serves as a flag; if it's NULL, then we're not
 *  reading saved input at all.  So the basic idea is:  if /BufPointer/
 *  is pointing, return the character it points to and advance it.
 *  Otherwise, do a real read, and save if simulating.
 *
 *  What if /BufPointer/ points, but there's no more input?  Then we want
 *  to go back to reading real input: set /BufPointer/ to NULL and call
 *  ourselves recursively to force real input.  We also take this
 *  opportunity to clear out the buffer and start over, a step which is
 *  justified only because we start rereading input only when we stop
 *  simulating (thus nobody can need the saved input anymore).
 *
 *  Note that it's an error if standard input ever comes to EOF; we
 *  should have seen the postamble and quit.  Finally, /ReadingCommand/
 *  is TRUE iff the byte is a command and not a parameter; in this case
 *  we check it with /NestingValidate/.
 */
unsigned_byte
ReadByte()
{
  int nextchar;

  if (BufPointer) {
    if (BufPointer < BufFirstNonchar) return *BufPointer++;
    else {
      BufPointer = NULL;
      BufFirstNonchar = Buffer;
      return ReadByte();
    }
  } else {
    nextchar = getchar();
    if (nextchar == EOF) BadDVIAbort("unexpected EOF");
    if (ReadingCommand) NestingValidate((unsigned_byte) nextchar);
    if (State >= SIMULATING) {
      *BufFirstNonchar++ = (unsigned_byte) nextchar;
      if (BufFirstNonchar > BufEnd) BufOverflow();
    }
    return nextchar;
  }
}



/*
 *  Test a character for nesting.  Since dvitype doesn't check DVI-IVD
 *  files for validity, it's important to do careful checking here---
 *  ivd2dvi will get horribly confused if reflections and pushes don't
 *  nest properly.  This routine gets called to validate every single
 *  command read from the input file.  The method is simple: if the
 *  command is PUSH, BEG_REFLECT, or BOP, just push it on the stack (the
 *  stack is the tiny /VStack/, not used for anything else).  If the
 *  command is POP, END_REFLECT, or EOP, pop a command from the stack and
 *  be sure it matches.  Ignore all other commands.
 */
void
NestingValidate(nextchar)
unsigned_byte nextchar;
{
  switch (nextchar) {
    case PUSH: case BEG_REFLECT: case BOP:
      if (VPointer >= VEnd) BufOverflow(); else *VPointer++ = nextchar;
      break;
    case POP:
      if ((VPointer <= VStack) || (*--VPointer != PUSH))
	BadDVIAbort("reflection commands incorrectly nested");
      break;
    case EOP:
      if ((VPointer <= VStack) || (*--VPointer != BOP))
	BadDVIAbort("reflection commands incorrectly nested");
      break;
    case END_REFLECT:
      if ((VPointer <= VStack) || (*--VPointer != BEG_REFLECT))
	BadDVIAbort("reflection commands incorrectly nested");
      break;
  }
}



/*
 *  As Knuth would say, ``Exit due to finiteness.''  We can become less
 *  finite, but we have to know in advance!
 */
void
BufOverflow()
{
  fprintf(stderr, "\n%s: Buffer size %d was inadequate\n",
		  ProgramName, BufSize);
  fprintf(stderr, "(Use the -b flag to increase the buffer size)\n");
  exit(3);
}




/*
 *  Read a command.  Just read a byte with /ReadingCommand/ turned on
 *  (and then turn it off!).  See the discussion of /VStack/ above.
 */
unsigned_byte
ReadCommand()
{
  unsigned_byte result;

  ReadingCommand = TRUE;
  result = ReadByte();
  ReadingCommand = FALSE;
  return result;
}




/*
 *  Copy a single byte from the input DVI file to the output file and
 *  return it.
 */
unsigned_byte
CopyByte()
{
  unsigned result = ReadByte();

  WriteByte(result);
  return result;
}



/*
 *  Read a byte from the input file /fp/.  We don't have to worry about
 *  buffering or special checks, just about EOF.  The error message is
 *  justified because we do input only from the TFM file of the current
 *  font (except for the main input DVI file, of course).
 */
unsigned_byte
FReadByte(fp)
FILE *fp;
{
    int nextchar;

    nextchar = getc(fp);
    if (nextchar == EOF) {
      fprintf(stderr, "\n%s: unexpected EOF in TFM file for font %s\n",
		      ProgramName, CurFont->name);
      exit(2);
    }
    return nextchar;
}




/*
 *  Discard /n/ bytes from the input DVI file.
 */
void
SkipNBytes(n)
long n;
{
  while (n--) (void) ReadByte();
}



/*
 *  Discard /n/ bytes from the input file /fp/.
 */
void
FSkipNBytes(fp,n)
FILE *fp;
long n;
{
  while (n--) (void) FReadByte(fp);
}



/*
 *  Copy /n/ bytes from the input DVI file to the output file.
 */
void
CopyNBytes(n)
long n;
{
  while (n--) WriteByte(ReadByte());
}




/*
 *  Read an unsigned integer of length /bytes/ from the input DVI file.
 */
long
ReadUnsigned(bytes)
unsigned bytes;
{
  long result = 0;

  while (bytes-- != 0) {
    result <<= 8;
    result |= ReadByte();
  }
  return result;
}



/*
 *  Read an unsigned integer of length /bytes/ from the input file /fp/.
 */
long
FReadUnsigned(fp,bytes)
FILE *fp;
unsigned bytes;
{
  long result = 0;

  while (bytes--) {
    result <<= 8;
    result |= FReadByte(fp);
  }
  return result;
}



/*
 *  Read a signed integer of length /bytes/ from the input DVI file.
 *  This must be done with no assumptions about the length of long ints
 *  on the machine and without using sign-extending right shifts.
 */
long
ReadSigned(bytes)
unsigned bytes;
{
  long result;

  result = ReadByte();
  if (result >= 128) result -= 256;
  while (--bytes) {
    result <<= 8;
    result |= ReadByte();
  }
  return result;
}



/*
 *  Read a signed integer of length /bytes/ from the input file /fp/.
 */
long
FReadSigned(fp,bytes)
FILE *fp;
int bytes;
{
  long result;

  result = FReadByte(fp);
  if (result >= 128) result -= 256;
  while (--bytes) {
    result <<= 8;
    result |= FReadByte(fp);
  }
  return result;
}




/*
 *  Copy a 32-bit word from the input DVI file to the output file, and
 *  return it.
 */
long
CopyWord()
{
  long result = ReadSigned(4);

  WriteWord(result);
  return result;
}



/*
 *  Copy an unsigned integer of length /bytes/ from the input DVI file
 *  to the output file, and return it.
 */
long
CopyUnsigned(bytes)
unsigned bytes;
{
  long result = ReadUnsigned(bytes);

  WriteNumber(result,bytes);
  return result;
}




/*
 *  Get a file position from which we can take input later.  If we're
 *  currently taking input from the buffer, the result is just the buffer
 *  pointer.  If not, the saved position is the place inside the buffer
 *  where we're storing the input as it comes in.  Details at /ReadByte/.
 */
unsigned_byte *
ReadFilePosition()
{
  if (BufPointer) return BufPointer; else return BufFirstNonchar;
}



/*
 *  Reset to take input starting from a saved file position.  Easy.
 */
void
ResetFilePosition(position)
unsigned_byte *position;
{
  BufPointer = position;
}



/*
 *  Arrange to see the last character of the input again.  Possible only
 *  when we're reading buffered input, in which case it's simple.  In
 *  fact, this routine is used only by /SetString/ while RTYPESETTING.
 */
void RereadLastByte() {
  if (!BufPointer || (BufPointer == Buffer)) {
    fprintf(stderr, "\n%s internal error: illegal attempt to backup input\n",
		    ProgramName);
    exit(4);
  }
  BufPointer--;
}




/*
 *  Write a single byte to the output DVI file.  All non-diagnostic output
 *  ***MUST*** go through this routine so that the number of bytes output
 *  is counted accurately.
 */
void
WriteByte(value)
unsigned value;
{
  putchar(value);
  BytesOutput++;
}



/*
 *  Write a 32-bit word to the output file.
 */
void
WriteWord(value)
long value;
{
  WriteNumber(value, 4);
}



/*
 *  Write /value/ to the output file as an integer of length /bytes/.
 */
void
WriteNumber(value,bytes)
long value;
unsigned bytes;
{
  if (bytes > 1) WriteNumber(value >> 8, bytes - 1);
  WriteByte((unsigned_byte) value & 0377);
}



/*
 *  Write a string to the output DVI file.
 */
void
WriteString(string)
char *string;
{
  char *pchar;

  for (pchar = string; *pchar; pchar++)
    WriteByte((unsigned_byte) *pchar);
}




/*
 *  Calculate how many bytes are required to represent /number/.  Don't
 *  say  /number = -(number+1)/  because of the possibility of overflow.
 */
unsigned
SignedBytes(number)
long number;
{
  if (number > 0) { number = -number; number -= 1; }
  if (number >= -128) return 1;
  else if (number >= -(128*256)) return 2;
  else if (number >= -(128*256*256)) return 3;
  else return 4;
}