/************************************************************************/
/*	File:	DVIPASTE.C            					*/
/************************************************************************/
/*   DEVELOPER: The TeXplorators Corporation			        */
/*   PRODUCT:	DVIPASTE						*/
/*   Version:	1.21							*/
/************************************************************************/
/*
			SOFTWARE LICENSE AGREEMENT

1. PURPOSE
	This agreement recites the terms and conditions under which 
The TeXplorators Corporation ("TEXPLORATORS") agrees to grant you a 
free, nonexclusive, transferable license to use the DVIPASTE software.

2. UNDERTAKINGS BY TEXPLORATORS
	2A. Ownership: Ownership of the DVIPASTE software remains 
exclusively in TEXPLORATORS.
	2B. License Fee: TEXPLORATORS makes the DVIPASTE software 
available to you free of any license fee.
	2C. Disclaimers: TEXPLORATORS DISCLAIMS ALL EXPRESS OR IMPLIED
WARRANTIES OF DVIPASTE'S MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
PURPOSE.
	2D. Liability: TEXPLORATORS' LIABILITY, IF ANY, IS LIMITED TO 
THE DISTRIBUTION FEE YOU PAID, AND DOES NOT INCLUDE SPECIAL AND/OR
CONSEQUENTIAL DAMAGES ARISING OUT OF, OR IN CONNECTION WITH, THE USE 
OF DVIPASTE.  SINCE SOME STATES DISALLOW LIMITATION OR EXCLUSION OF 
LIABILITY, THIS LIMITATION OR EXCLUSION MAY NOT APPLY TO YOU.

3. UNDERTAKINGS BY YOU.
	3A. Proper Use: You agree to use the DVIPASTE software in
compliance with the terms and conditions hereof.
	3B. Notices on Authorized Copies: You agree to take reasonable
precautions to preserve the propriety of the DVIPASTE software by
duplicating verbatim, on all copies thereof, the notices of TEXPLORATORS'
interests recited thereon.  You agree to note that source code is 
available upon request, if you do not distribute source code with the
DVIPASTE software.
	3C. Distribution: You are encouraged to freely distribute the
DVIPASTE software, including source code, on or through any common media
including diskettes and electronic bulletin board systems.  You agree to
distribute this license with each and every copy so distributed, and to 
either distribute source code therewith or make source code available upon
request. You may charge a distribution fee to cover the cost of diskettes,
handling and shipping.
	3D. Modifications: You are authorized to make modifications to
DVIPASTE, but these modifications must be conspicuously noted and dated
therewith.
	3E. License Fee: You may not charge a license fee for the
DVIPASTE software, either in its original or modified form.  However, you
may charge a license fee for your software which is broader in scope
than DVIPASTE, whereby DVIPASTE is not a primary functional unit thereof.

4. SCOPE
	This Software License Agreement constitutes the entire agreement
between TEXPLORATORS and you regarding the DVIPASTE software, and shall
be construed under the laws of the State of TEXAS.

					The TeXplorators Corporation
					By: Michael Spivak, President
*/
/*

Page*/
/* Comments:
      The following I/O routines may have to be changed for other 
      architectures.
      GetByte();
      GetWord();
      GetTrio();
      GetQuad();
      PutByte();
      PutWord();
      PutTrio();
      PutQuad();
      GetSignedWord();
 */
/* Configuration and defines for Unix 05/08/1991, P. A. MacKay */

/* System-dependent defines */

#include "config.h"

/*------------------------------*/
/*	includes		*/
/*------------------------------*/
#include <stdio.h>
#include <string.h>
#ifdef MICROSOFTC
#include <process.h>
#endif
#include <malloc.h>

/*------------------------------*/
/*	defines			*/
/*------------------------------*/
#define STRINGSIZE (5124)	/* maximum string size */
#define TRUE  1
#define FALSE 0

/*------------------------------*/
/*	typedefs		*/
/*------------------------------*/
typedef long integer;
#ifdef MICROSOFTC
typedef int  shalfword;
typedef unsigned int halfword;
#else
typedef short  shalfword;
typedef unsigned short halfword;
#endif
typedef unsigned char quarterword;
typedef float real;
typedef char  Boolean;

typedef struct 
{
   quarterword cmd;	
   integer k;
   integer checksum;
   integer scaledsize;
   integer designsize;
   quarterword a;
   quarterword l;
   char *name;
}  FontType;


typedef struct
{
   integer  p;
   integer  num;
   integer  den;
   integer  mag;
   integer  l;
   integer  u;
   halfword s;
   halfword t;
}  PostType;


typedef struct
{
   integer      q;
   quarterword  i;
}  PostPostType;


typedef struct
{
   integer fn;
   char    *name;    
   integer scaledsize;
   integer designsize;
}  DeclaredFontType; 

typedef struct
{
   integer fn;
   integer new;
   char    *name;    
}  SubListType;

typedef struct 
{
   int     cmd;
   integer k;
}  FontNumType;

/*------------------------------*/
/* 	function declarations   */
/*------------------------------*/
#ifdef ANSI /* Use ANSI C prototypes */
void      AddFontList(void);
void	  AlignPara(FILE *);

void	  beep(void);
void	  BeginSpecial(integer);
void      bop(void);

void      DefFont(int);
void	  DoSpecial(int);

int       EndSpecial(integer, int);
void      error(char *,char *);

void      FindPage(void);
void	  FntNum(int);
void      FontDef(int);

shalfword GetByte(FILE *);
integer	  GetQuad(FILE *);
shalfword GetSignedByte(FILE *);
shalfword GetSignedWord(FILE *);
integer	  GetTrio(FILE *);
integer   GetUniqueNumber(void);
halfword  GetWord(FILE *);

void      Initialize(void);

int       main(int argc, char *argv[]);

void	  PopsAndPushes(int);
void      PutByte(int, FILE *);
void	  PutQuad(integer, FILE *);
void      PutTrio(long,FILE *);
void      PutWord(int, FILE *);
void      PutFntNum( integer fn );

void      ReadPostamble(void);
void      ReadPreamble(void);
void	  ReadSubFile(void);

void      SkipOver(integer,FILE *);
void      SubDefFont(int);
void      SubFontDef(int);
void      SubPreamble(void);
void      SubPostamble(void);

void      TransferTable(void);

void      WritePostamble(void);

void	  xxxFontDef(int);

#else /* Use old-style K&R functions */
void      AddFontList();
void	  AlignPara();

void	  beep();
void	  BeginSpecial();
void      bop();

void      DefFont();
void	  DoSpecial();

int       EndSpecial();
void      error();

void      FindPage();
void	  FntNum();
void      FontDef();

shalfword GetByte();
integer	  GetQuad();
shalfword GetSignedByte();
shalfword GetSignedWord();
integer	  GetTrio();
integer   GetUniqueNumber();
halfword  GetWord();

void      Initialize();

int       main();

void	  PopsAndPushes();
void      PutByte();
void	  PutQuad();
void      PutTrio();
void      PutWord();
void      PutFntNum();

void      ReadPostamble();
void      ReadPreamble();
void	  ReadSubFile();

void      SkipOver();
void      SubDefFont();
void      SubFontDef();
void      SubPreamble();
void      SubPostamble();

void      TransferTable();

void      WritePostamble();

void	  xxxFontDef();
/* An ANSI string function, not guaranteed elsewhere */
char	  *strstr();
#endif
/*------------------------------*/
/* 	data structures		*/
/*------------------------------*/
FontType *main_fontlist[256]; /* Main font list pointers            */
FontType *sub_fontlist[256];  /* Sub font list pointers 	    */
			      /* list of dynamically declared fonts */
DeclaredFontType declared_fonts[256];
SubListType sublist[100];     /* substitution list	            */
PostType post;		      /* postamble                  	    */
PostPostType post_post;	      /* post postamble    		    */
FontNumType fnt;	      /* current font 	   		    */
char newname[13];             /* new dvi file name		    */
char dviname[13];             /* dvi file name     		    */
char subname[13];	      /* sub file name     		    */
char strings[STRINGSIZE];     /* strings buffer    		    */
char *nextstr, *maxstr;	      /* string pointers   		    */
FILE *dvifile;		      /* dvi file handle   		    */
FILE *newfile;		      /* new file handle   		    */	
FILE *subfile; 		      /* sub file handle   		    */
int  mfonts;		      /* number of fonts in main_fontlist   */
int  sfonts;		      /* number of fonts in sub_fontlist    */
int  dfonts;		      /* number of fonts in declared fonts  */
integer pagenum;	      /* page number 			    */
int  pushes;		      /* current number of pushes           */
int  pops;		      /* current number of pops		    */
int  max_stack_depth;	      /* max pushes over pops		    */
long prevbop;		      /* previous bop			    */
integer subpost_p;	      /* sub file postamble pointer	    */
int  push;		      /* number of pushes		    */
int  ColumnPos;               /* column position 		    */


/*------------------------------*/
/* 	functions		*/
/*------------------------------*/

/* align binary file on a 16-byte boundary */
void AlignPara(f)
FILE *f;
{
   long fpos, pad, i; 	
   fpos = ftell(f);
   pad  = fpos%16L;
   if (pad!=0L)
       pad=16L-pad;
   /* put out trailer bytes */
   for (i=0; i<pad; i++)
        PutByte(223,f);
   return;	
}


/* a quick and dirty way to sound the system horn */
void beep()
{
     printf("\007\b");  return;
}


/* print error message and die */
void error(s1,s2)
char *s1, *s2;
{
     beep();
     printf("\n%s %s",s1,s2); printf("\n");
     exit(1);
}

shalfword GetByte(f)
FILE *f;
{ shalfword i;
  i = fgetc(f);
  return(i);
}

halfword GetWord(f)
FILE *f;
{ halfword i;
  i = GetByte(f) ;
  return(i*256+GetByte(f)) ;
}

integer GetTrio(f)
FILE *f;
{ integer i ;
  i = GetWord(f) ;
  return(i*256+GetByte(f)) ; 
}

shalfword GetSignedByte(f)
FILE *f;
{ shalfword i;
  i = fgetc(f);
  if (i<128) return(i);
  else return(i-256);
}

shalfword GetSignedWord(f)
FILE *f;
{ shalfword i;
  i = GetSignedByte(f) ;
  return(i*256+GetByte(f)) ; 
}


integer GetQuad(f)
FILE *f;
{ integer i;
  i = GetSignedWord(f);
  return(i*65536+GetWord(f)); 
}

void PutByte(byte,f)
int byte;
FILE *f;
{
   fputc(byte,f);
   if ( ferror(f) )
	error("! File error - out of space",newname);
   return;	
}


void PutWord(num, f)
int num;
FILE *f;
{
   char *p;
   p=(char *)&num;
#ifdef LITTLENDIAN
   PutByte(*(p+1), f);
   PutByte(*p, f);
#else
   PutByte(*p, f);
   PutByte(*(p+1), f);
#endif
   return;
}	


void PutTrio(trio,f)
long trio;
FILE *f;
{
   int i;
   char *p;
   p = (char *)&trio;
#ifdef LITTLENDIAN
   for (i=2; i>=0; i--)
#else
   for (i=0; i<3; i++)
#endif
       PutByte( *(p+i), f);
   return;
}

void PutQuad(quad,f)
long quad;
FILE *f;
{
   int i;
   char *p; 
   p = (char *)&quad;
#ifdef LITTLENDIAN
   for (i=3; i>=0; i--)
#else
   for (i=0; i<4; i++)
#endif
        PutByte( *(p+i), f );
   return;
}


void PopsAndPushes(cmd)
int cmd;
{
int diff;

     switch (cmd)
     {
	case 141: pushes++; break;
	case 142: pops++; break;
     }
     diff = pushes - pops;
     if ( diff > max_stack_depth )
	   max_stack_depth = diff;
     return;	
}


void ReadPreamble()
{
   integer     num, den, mag;
   int         i;
   quarterword k;
   shalfword   id, pre, byte;
      
   pre  = GetByte(dvifile); PutByte(pre,newfile);
   id   = GetByte(dvifile); PutByte(id,newfile);	
   num  = GetQuad(dvifile); PutQuad(num,newfile);
   den  = GetQuad(dvifile); PutQuad(den,newfile);
   mag  = GetQuad(dvifile); PutQuad(mag,newfile);
   k    = (quarterword) GetByte(dvifile); PutByte(k,newfile);
   /* skip over TeX comment */
   for (i=0; i<k; i++)
   {    byte=GetByte(dvifile); PutByte(byte,newfile); }
   
   return;	
}

void ReadPostamble()
{
  long offset;
  int  cmd;
  Boolean done;
  integer k;
  
#ifndef SEEK_END
#define SEEK_END 2
#define SEEK_CUR 1
#define SEEK_SET 0
#endif
  fseek(dvifile,0L,SEEK_END);
  /* skip backwards over 223's until the id byte. */
  fseek(dvifile,-1L,SEEK_CUR);
  cmd = GetByte(dvifile);
  while (cmd==223)
  {
      fseek(dvifile,-2L,SEEK_CUR);
      if ( ftell(dvifile)==0L )
      {   error("! error in reading postamble",dviname); }
      cmd = GetByte(dvifile);
  }
  
  /* back up and read q */
  fseek(dvifile,-5L,SEEK_CUR);
  offset= GetQuad(dvifile);
  fseek(dvifile,offset,SEEK_SET);
  cmd   = GetByte(dvifile);

  /* this must be the post cmd */
  if (cmd!=248) 
  {   error("! error in reading postamble",dviname); }
  
  post.p   = GetQuad(dvifile);
  post.num = GetQuad(dvifile);
  post.den = GetQuad(dvifile);
  post.mag = GetQuad(dvifile);
  post.l   = GetQuad(dvifile);
  post.u   = GetQuad(dvifile);
  post.s   = GetWord(dvifile);
  post.t   = GetWord(dvifile);

  /* read in font defs */
  done = FALSE;
  while ( !done )
  {
      cmd = GetByte(dvifile);
      switch (cmd)
      {
	 case 243: /* fnt_def1 */
         case 244: /* fnt_def2 */
         case 245: /* fnt_def3 */
         case 246: /* fnt_def4 */		 
	      FontDef(cmd); 
 	      break;
	 default: done=TRUE; break;
      }
  }

  /* Now, we will try to assign a fnt number.
     To make life easier, we will pick the first one. There must be
     at least one font def in main_fontlist, otherwise font 0 will
     be assigned for better or for worse. */
  if ( main_fontlist[0]!=NULL )
  {
    k =   main_fontlist[0]->k;
    if ( k < 64L ) fnt.cmd = (quarterword) (k+171L) ;
    else if ( k < 256L ) { fnt.cmd = 235; fnt.k = k; }
       else if ( k < 65536L ) { fnt.cmd = 236; fnt.k = k; }
            else if ( k < 16777216L ) { fnt.cmd = 237; fnt.k = k; }
	         else { fnt.cmd = 238; fnt.k = k; }
  }
  else
      fnt.cmd = 171;
  
  return;	
}

void WritePostamble()
{
  int  i,j,n;
  Boolean found;
  FontType *fp;
  char *p;

  /* set max stack depth */
  post.s = max_stack_depth;
  PutQuad(post.p,newfile);  
  PutQuad(post.num,newfile);
  PutQuad(post.den,newfile);
  PutQuad(post.mag,newfile);
  PutQuad(post.l,newfile);
  PutQuad(post.u,newfile);
  PutWord(post.s,newfile);
  PutWord(post.t,newfile);

  /* send out font defs that are actually used in the combined file */
  /* - use declared_fonts list since this is the correct list.      */
  for (i=0; i<dfonts; i++)
  {
     fp = NULL; found = FALSE;
     for (j=0; j<mfonts && !found; j++)
     {
	  if ( declared_fonts[i].fn==main_fontlist[j]->k ) 
	  {    found = TRUE;  fp = main_fontlist[j]; }
     }

     if ( fp!=NULL )	  
     {
	  PutByte(fp->cmd,newfile);
          switch (fp->cmd)
	  {
	     case 243:
		  PutByte((quarterword)fp->k,newfile); break;
	     case 244:
		  PutWord((halfword)fp->k,newfile); break;
	     case 245:
		  PutTrio(fp->k,newfile); break;
	     case 246:
		  PutQuad(fp->k,newfile); break;
	  }
          PutQuad(fp->checksum,newfile);
          PutQuad(fp->scaledsize,newfile);
          PutQuad(fp->designsize,newfile);
          PutByte(fp->a,newfile);
          PutByte(fp->l,newfile);
	  p = fp->name;
	  /* directory */
          for (n=0; n<fp->a; n++)
	       PutByte(*p++, newfile);
          p++;
	  /* font name */
          for (n=0; n<fp->l; n++)
	       PutByte(*p++,newfile);
     }
  }

  /* now the post_post command */
  PutByte(249, newfile);
  PutQuad(post_post.q,newfile);
  PutByte(2,newfile);
  /* put out enough trailer bytes */
  for (i=0; i<4; i++)
       PutByte(223,newfile);
  AlignPara(newfile);
  return;	
}


void Initialize()
{
   int  i;
   for (i=0; i<256; i++)
        main_fontlist[i] = NULL;
   nextstr = strings;
   maxstr  = strings + STRINGSIZE - 1;
   mfonts  = 0;
   sfonts  = 0;
   dfonts  = 0;
   subname[0]= 0;
   subfile = NULL;
   pops = pushes = max_stack_depth = 0;
   prevbop = -1L;
   ColumnPos = 0;
   return;
}

void FontDef(cmd)
int  cmd;
{  
   int	       i,f;
   integer     fn;
   FontType    *fp;
   quarterword found;

   switch (cmd)
   {
        case 243: /* fnt_def1 */
	     fn = GetByte(dvifile); break;
        case 244: /* fnt_def2 */
	     fn = GetWord(dvifile); break;
        case 245: /* fnt_def3 */
	     fn = GetTrio(dvifile); break;
        case 246: /* fnt_def4 */
	     fn = GetQuad(dvifile); break;
   }
   
   /* walk thru main_fontlist */
   found = FALSE;
   for (f=0; f<mfonts && !found; f++)
   {
     if (main_fontlist[f]->k == fn ) found=TRUE;
   }
   
   if ( !found )
   {
       fp = (FontType *)malloc(sizeof(FontType));
       if (fp==NULL)
           error("! ran out of memory",dviname);
       main_fontlist[mfonts++] = fp;
       fp->cmd	        = (quarterword) cmd;
       fp->k	        = fn;
       fp->checksum     = GetQuad(dvifile);
       fp->scaledsize   = GetQuad(dvifile);
       fp->designsize   = GetQuad(dvifile);
       fp->a = (quarterword) GetByte(dvifile); 
       fp->l = (quarterword) GetByte(dvifile); 
       /* check strings space */
       if ( ( nextstr + fp->a + fp->l ) > maxstr )
          error("! out of string space",dviname);
       fp->name         = nextstr ;
       for (i=0; i<fp->a; i++)
           *nextstr++ = (char) GetByte(dvifile);
       *nextstr++ = 0;
       for (i=0; i<fp->l; i++)
         *nextstr++ = (char) GetByte(dvifile);
       *nextstr++ = 0;
     } 
     /* font already defined, skip over it */
     else
     {
      SkipOver(12L,dvifile);		/* c[4]...n[a+l] */
      i = GetByte(dvifile) + GetByte(dvifile);
      SkipOver((long)i,dvifile);
   }

   return;
}

void DefFont(cmd)
int cmd;
{
   quarterword byte, byte1;
   int	       i;   
   integer     fn;
   quarterword found;
   char        name[13];
   integer     checksum, scaledsize, designsize;
   
      switch (cmd)
      {
	case 243: /* fnt_def1 */
	     fn = GetByte(dvifile); PutByte((quarterword)fn,newfile);
	     break;
        case 244: /* fnt_def2 */	      		
	     fn = GetWord(dvifile); PutByte((halfword)fn,newfile); 
	     break;
        case 245: /* fnt_def3 */	
	     fn = GetTrio(dvifile); PutTrio(fn,newfile); 	     
	     break;
        case 246: /* fnt_def4 */	      
	     fn = GetQuad(dvifile); PutQuad(fn,newfile); 		
             break;
      }

      checksum   = GetQuad(dvifile);
      scaledsize = GetQuad(dvifile);      
      designsize = GetQuad(dvifile);      
      PutQuad(checksum,   newfile);
      PutQuad(scaledsize, newfile);
      PutQuad(designsize, newfile);      

      byte  = (quarterword) GetByte(dvifile); 
      byte1 = (quarterword) GetByte(dvifile);
      PutByte(byte,newfile); PutByte(byte1, newfile);
      i = byte;  
      for (i=0; i<byte; i++) 
      {  byte = (quarterword) GetByte(dvifile); PutByte(byte,newfile); } 
      i = byte1; 
      for (i=0; i<byte1; i++) 
      {  byte = (quarterword) GetByte(dvifile); 
         name[i]=byte; PutByte(byte,newfile); } 
      name[i]=0;

      /* keep a list of declared fonts */
      found = FALSE;
      for (i=0; i<dfonts && !found; i++)
      {
	   if (   (stricmp(declared_fonts[i].name,name)==0)
	       && (scaledsize==declared_fonts[i].scaledsize)
	       && (designsize==declared_fonts[i].designsize)
	      )
	           found = TRUE;
      }
      
      if ( !found )
      {
	    declared_fonts[dfonts].name = nextstr;
	    for (i=0; i<byte1; i++)
		 *nextstr++ = name[i];
	    *nextstr++ = 0;
	    declared_fonts[dfonts].fn   = fn;
	    declared_fonts[dfonts].scaledsize = scaledsize;
	    declared_fonts[dfonts].designsize = designsize;	    
	    dfonts++;
      }
      
  return;
}


void SubFontDef(cmd)
int  cmd;
{  int	       i,f;
   integer     fn;
   FontType    *fp;
   quarterword found;

   switch (cmd)
   {
        case 243: /* fnt_def1 */
	     fn = GetByte(subfile); break;
        case 244: /* fnt_def2 */
	     fn = GetWord(subfile); break;
        case 245: /* fnt_def3 */
	     fn = GetTrio(subfile); break;
        case 246: /* fnt_def4 */
	     fn = GetQuad(subfile); break;
   }

   
   /* walk thru sub_fontlist */
   found = FALSE;
   for (f=0; f<sfonts && !found; f++)
   {
     if (sub_fontlist[f]->k == fn ) found=TRUE;
   }

   
   if ( !found )
   {
       fp = (FontType *)malloc(sizeof(FontType)) ;
       if (fp==NULL)
           error("! sorry, out of memory",subname);
   
       sub_fontlist[sfonts++] = fp;
       fp->cmd	        = (quarterword) cmd;
       fp->k	        = fn;
       fp->checksum     = GetQuad(subfile);
       fp->scaledsize   = GetQuad(subfile);
       fp->designsize   = GetQuad(subfile);
       fp->a 		= (quarterword) GetByte(subfile); 
       fp->l		= (quarterword) GetByte(subfile); 

       /* check strings space */
       if ( ( nextstr + fp->a + fp->l ) > maxstr )
          error("! out of string space",subname);
  
       fp->name         = nextstr;
       for (i=0; i<fp->a; i++)
            *nextstr++  = (char) GetByte(subfile);
       *nextstr++ = 0;
       for (i=0; i<fp->l; i++)
         *nextstr++ = (char) GetByte(subfile) ;
       *nextstr++   = 0 ;
     } 
     /* font already defined */
     else
     {
      SkipOver(12L,subfile);		/* c[4]...n[a+l] */
      i = GetByte(subfile) + GetByte(subfile);
      SkipOver((long)i,subfile);
   }

   return;
}


void SubDefFont(cmd)
int cmd;
{
   quarterword byte, byte1;
   int	       i;
   integer     fn;
   char        name[13];
   
      switch (cmd)
      {
	case 243: /* fnt_def1 */
	     fn = GetByte(subfile);
	     break;
        case 244: /* fnt_def2 */	      		
	     fn = GetWord(subfile);
	     break;
        case 245: /* fnt_def3 */	
	     fn = GetTrio(subfile);
	     break;
        case 246: /* fnt_def4 */	      
	     fn = GetQuad(subfile);
             break;
      }

      for (i=0; i<12; i++)
           GetByte(subfile);

      byte  = (quarterword) GetByte(subfile); 
      byte1 = (quarterword) GetByte(subfile);
      i = byte;  
      for (i=0; i<byte; i++) 
      {  byte = (quarterword) GetByte(subfile); } 
      i = byte1; 
      for (i=0; i<byte1; i++) 
      {  byte = (quarterword) GetByte(subfile); name[i]=byte; } 
      name[i]=0;

  return;
}

void xxxFontDef(cmd)
int  cmd;
{  int	       i;
   integer     fn;
   quarterword a, l;
   quarterword found;
   integer     checksum, scaledsize, designsize;
   char        name[13];
   char        directory[80];
   
   switch (cmd)
   {
        case 243: /* fnt_def1 */
	     fn = (integer) GetByte(subfile); break;
        case 244: /* fnt_def2 */
	     fn = (integer) GetWord(subfile); break;
        case 245: /* fnt_def3 */
	     fn = (integer) GetTrio(subfile); break;
        case 246: /* fnt_def4 */
	     fn = GetQuad(subfile); break;
   }

   checksum   = GetQuad(subfile);
   scaledsize = GetQuad(subfile);
   designsize = GetQuad(subfile);
   a   	      = (quarterword) GetByte(subfile); 
   l          = (quarterword) GetByte(subfile); 

   for (i=0; i<a; i++)
        directory[i] = (char) GetByte(subfile);
   directory[i]=0;
   for (i=0; i<l; i++)
	name[i] = (char) GetByte(subfile);
   name[i]=0;

   /* walk thru list of declared fonts */
   found = FALSE;
   for (i=0; i<dfonts && !found; i++)
   {
       if (   (stricmp(declared_fonts[i].name,name)==0)
	   && (scaledsize == declared_fonts[i].scaledsize)
	   && (designsize == declared_fonts[i].designsize)		   
	  )
               found = TRUE;
   }

   if ( !found )
   {
	PutByte(cmd,newfile);
	/* substitute font number before tranfer */
	found = FALSE;
	for (i=0; i<sfonts && !found;  i++)
        {
	    if ( fn == sublist[i].fn )
	    {    fn = sublist[i].new; found = TRUE; }
        }
        switch (cmd)
        {
          case 243: /* fnt_def1 */
	       PutByte((quarterword)fn,newfile); break;
          case 244: /* fnt_def2 */
	       PutWord((halfword)fn,newfile); break;
          case 245: /* fnt_def3 */
	       PutTrio(fn,newfile); break;
          case 246: /* fnt_def4 */
	       PutQuad(fn,newfile); break;
        }

	PutQuad(checksum,  newfile);
        PutQuad(scaledsize,newfile);
        PutQuad(designsize,newfile);
        PutByte(a,newfile);
        PutByte(l,newfile);
	for (i=0; i<a; i++)
             PutByte(directory[i],newfile);
	for (i=0; i<l; i++)
	     PutByte(name[i],newfile);

	/* add font to declared_fonts list */
        declared_fonts[dfonts].name = nextstr;
	for (i=0; i<l; i++)
	     *nextstr++ = name[i];
        *nextstr++ = 0;
	declared_fonts[dfonts].fn   	  = fn;
	declared_fonts[dfonts].scaledsize = scaledsize;
	declared_fonts[dfonts].designsize = designsize;	
	dfonts++;
   }
   return;
}


void SkipOver(i,f)
integer i;
FILE *f;
{
   fseek(f,i,SEEK_CUR);	
   return;	 
}


void PutFntNum(fn)
integer fn;
{
  if ( fn >= 0  && fn < 64 )
      PutByte((quarterword)(171L+fn),newfile); 
  else
  {
   if ( fn >= 64L && fn < 256L )
   {  PutByte(235,newfile); PutByte((quarterword)fn,newfile);  }
   else
   {
      if ( fn >= 0 && fn < 65536L )
      { PutByte(236,newfile); PutWord((halfword)fn,newfile); }
      else
      {  /* combine 237 and 238 */
         PutByte(238,newfile); PutQuad(fn,newfile); 
      }
   }
  }
  return;	
}

void FntNum(cmd)
int cmd;
{
integer fn;
Boolean found;
char    name[13];
char    *p;
FontType *fp;
int     i;
integer scaledsize, designsize;

    switch(cmd)
    {
         case 235: /* fnt1   */	       
	      fn=GetByte(subfile); break;
         case 236: /* fnt2   */
	      fn=GetWord(subfile); break;
         case 237: /* fnt3   */
	      fn=GetTrio(subfile); break;
         case 238: /* fnt4   */	       
	      fn=GetQuad(subfile); break;
         default: 
	      fn = (long)cmd - 171L; break;
    }

    found = FALSE;
    for (i=0; i<sfonts && !found; i++)
    {
	 if ( fn == sub_fontlist[i]->k )
	 {   found = TRUE ; 
	     p = sub_fontlist[i]->name + sub_fontlist[i]->a + 1;
	     strcpy(name,p);
	     scaledsize = sub_fontlist[i]->scaledsize;
	     designsize = sub_fontlist[i]->designsize;
	 }
    }
    
    if ( !found )
	error(" ! cannot find font name",subname);

    /* walk thru list of declared fonts */
    found = FALSE;
    for (i=0; i<dfonts && !found; i++)
    {
       if (   (stricmp(declared_fonts[i].name,name)==0)
	   && (scaledsize==declared_fonts[i].scaledsize)
	   && (designsize==declared_fonts[i].designsize)
          )
               found = TRUE;
    }

    if ( found )
    {
	 /* substitute font number before transfer */
   	 found = FALSE;
	 for (i=0; i<sfonts && !found;  i++)
         {
	    if ( fn == sublist[i].fn )
	    {    fn = sublist[i].new; found = TRUE; }
         }
         PutFntNum(fn);	
    }
    else
    {
        /* Get font number from sub font list */
   	found = FALSE;
	for (i=0; i<sfonts && !found;  i++)
        {
	    if ( fn == sublist[i].fn )
	    {    fn = sublist[i].new; found = TRUE; }
        }
	
	found = FALSE;
	for (i=0; i<mfonts && !found; i++)
	{
            if ( fn == main_fontlist[i]->k )
	    {
		 found = TRUE;
		 fp = main_fontlist[i];
	    }
	}
	
	if ( !found )
	    error(" ! fnt number not in main list",subname);
    
	/* now, we send out a fnt_def */
        PutByte((quarterword)fp->cmd,newfile);
	switch (fp->cmd)
	{
           case 243: PutByte((quarterword)fp->k,newfile); break;
	   case 244: PutWord((halfword)fp->k,newfile); break;
	   case 245: PutTrio(fp->k,newfile); break;
	   case 246: PutQuad(fp->k,newfile); break;
	}
        PutQuad(fp->checksum,newfile);
        PutQuad(fp->scaledsize,newfile);
        PutQuad(fp->designsize,newfile);
        PutByte(fp->a,newfile);
        PutByte(fp->l,newfile);
	for (i=0; i<fp->a; i++)
             PutByte(*(fp->name+i),newfile);
        for (i=0; i<fp->l; i++)
             PutByte(*(fp->name+fp->a+1+i),newfile);
        /* now we have to send out the fnt_num cmd */
        PutFntNum(fn);
	 
	/* add font to declared_fonts list */
        declared_fonts[dfonts].name = nextstr;
	for (i=0; i<fp->l; i++)
	     *nextstr++ = name[i];
        *nextstr++ = 0;
	declared_fonts[dfonts].fn   	  = fn;
	declared_fonts[dfonts].scaledsize = fp->scaledsize;
	declared_fonts[dfonts].designsize = fp->designsize;	
	dfonts++;
	 
     }
    return;    
}


void DoSpecial(cmd)
int  cmd;
{
   integer i;
   char    str[90];
   char    opcode[80];
   char    name[80];
   integer numbytes;
   integer offset;
   
   switch (cmd)
   {
       case 239: /* xxx1   */
	    numbytes=GetByte(dvifile);
	    break;
       case 240: /* xxx2   */
	    numbytes=GetWord(dvifile);
	    break;
       case 241: /* xxx3   */
	    numbytes=GetTrio(dvifile);
	    break;
       case 242: /* xxx4   */	       
	    numbytes=GetQuad(dvifile); 
	    break;
   }

   offset = ftell(dvifile);

   for (i=0; i<numbytes && i<79; i++)
        str[i] = (char) GetByte(dvifile);
   str[i] = 0;
   sscanf(str,"%s%s%ld",opcode,name,&pagenum);
   strcat(name,".dvi");
   
   /* process only {dvipaste: <file> n} commands */ 
   if (strnicmp(opcode,"dvipaste:",9)==0)
   {
      fseek(dvifile,offset,SEEK_SET);
      SkipOver( numbytes, dvifile );
      
      /* read in new subfile if different */
      if (stricmp(name,subname)!=0)
      {
        strcpy(subname,name);
        ReadSubFile();
      }
      
      
      /* now we transfer table n from subfile */
      TransferTable();

      /* we must set previous fnt num before returning to dvifile */
      switch( fnt.cmd )
      {
	 case 235:
	      PutByte(fnt.cmd,newfile); 
	      PutByte((quarterword)fnt.k,newfile);
	      break;
	 case 236: 
	      PutByte(fnt.cmd,newfile); 
	      PutWord((halfword)fnt.k,newfile);
	      break;
         case 237:
	      PutByte(fnt.cmd,newfile);
	      PutTrio(fnt.k,newfile);
	      break;
         case 238:
	      PutByte(fnt.cmd,newfile);
	      PutQuad(fnt.k,newfile);
	      break;
        default:
	      PutByte(fnt.cmd,newfile);
              break;
      }
   }
   else
   {   /* pass the special thru. not the ones we care about */
       PutByte(cmd,newfile);
       switch (cmd)
       {
          case 239: /* xxx1   */
	    PutByte((quarterword)numbytes,newfile);
	    break;
          case 240: /* xxx2   */
	    PutWord((halfword)numbytes,newfile);
	    break;
          case 241: /* xxx3   */
	    PutTrio(numbytes,newfile);
	    break;
          case 242: /* xxx4   */
	    PutQuad(numbytes,newfile);
	    break;
       }

       fseek(dvifile,offset,SEEK_SET);
       for (i=0; i<numbytes; i++)
            PutByte(GetByte(dvifile),newfile);
      
   }

   return;
}

#ifndef MICROSOFTC
#define strnicmp strncmp
#define strcmp strcmp
#endif

int  EndSpecial(numbytes, cmd)
integer numbytes;
int cmd;
{
   integer  i;
   char     str[90];
   char     opcode[80];
   integer  offset;

   offset = ftell(subfile);
   for (i=0; i<numbytes && i<79; i++)
       str[i] = (char) GetByte(subfile);
   str[i] = 0;
   sscanf(str,"%s",opcode);
   
   if (strnicmp(opcode,"endpaste:",9)==0)
   {
       fseek(subfile,offset,SEEK_SET);
       SkipOver( numbytes, subfile );

       /* balance out pushes and pops */
       for (; push>0; push--)
       {
           PutByte(142,newfile);
           PopsAndPushes(142);
       }
       return( TRUE );
   }
 
   /* send out embedded special */
    PutByte(cmd,newfile);
    switch( cmd )
    {
      case 239: /* xxx1   */
           PutByte((quarterword)numbytes,newfile);
           break;
      case 240: /* xxx2   */
           PutWord((halfword)numbytes,newfile);
           break;
      case 241: /* xxx3   */
           PutTrio(numbytes,newfile);
           break;
      case 242: /* xxx4   */
           PutQuad(numbytes,newfile);
           break;
    }

    fseek(subfile,offset,SEEK_SET);
    for (i=0; i<numbytes; i++)
         PutByte(GetByte(subfile),newfile);
   
   return(FALSE);
}


void BeginSpecial(numbytes)
integer numbytes;
{
   integer i;
   char    str[90];
   char    opcode[80];
   Boolean done;
   integer ii;
   int     cmd;
   integer offset;

   offset = ftell(subfile);
   for (i=0; i<numbytes && i<79; i++)
        str[i] = (char) GetByte(subfile);
   str[i] = 0;
   sscanf(str,"%s",opcode);

   if (strnicmp(opcode,"beginpaste:",11)==0)
   {
      fseek(subfile,offset,SEEK_SET);
      SkipOver( numbytes, subfile );

      done=FALSE; push = 0;
      while ( !done )
      {
        cmd=GetByte(subfile);
  
	switch (cmd)
	{
         case 139: /* bop    */
         case 140: /* eop    */	
	      error("! illegal commands inside special",subname);
	      break;
	 case 141: /* push */
	      PutByte((quarterword)cmd, newfile);
	      PopsAndPushes(cmd);
	      push++; break;
         case 142: /* pop */
	      PutByte((quarterword)cmd, newfile);	
	      PopsAndPushes(cmd);      
	      push--; break; 
         /* fnt_def1...fnt_def4 */
         case 243: case 244: case 245: case 246:
	 /* xxx1...xxx4 - embedded specials */
         case 239: case 240: case 241: case 242:
	      /* don't put out cmd byte yet */
	      break;
         /* fnt1...fnt4 */
         case 235: case 236: case 237: case 238:
	      FntNum(cmd); break;
         default:	
              /* fnt_num_0 thru fnt_num_63 */
	      if (cmd>=171 && cmd<=234) 
	      {   FntNum(cmd); break; }
	      PutByte((quarterword)cmd, newfile); break;
        }

        switch( cmd )
        {
              /* eight bytes */
         case 132: /* set_rule */
         case 137: /* put_rule */
              PutQuad(GetQuad(subfile),newfile);
              /* four bytes  */
         case 131: /* set4   */
         case 136: /* put4   */
         case 146: /* right4 */
         case 151: /* w4     */
         case 156: /* x4     */
         case 160: /* down4  */
         case 165: /* y4     */
         case 170: /* z4     */
              PutByte(GetByte(subfile),newfile);
              /* three bytes */
         case 130: /* set3   */
         case 135: /* put3   */
         case 145: /* right3 */
         case 150: /* w3     */
         case 155: /* x3     */
         case 159: /* down3  */
         case 164: /* y3     */
         case 169: /* z3     */
              PutByte(GetByte(subfile),newfile);
              /* two bytes   */
         case 129: /* set2   */
         case 134: /* put2   */
         case 144: /* right2 */
         case 149: /* w2     */
         case 154: /* x2     */
         case 158: /* down2  */
         case 163: /* y2     */
         case 168: /* z2     */
              PutByte(GetByte(subfile),newfile); 
              /* one byte    */
         case 128: /* set1   */
         case 133: /* put1   */
         case 143: /* right1 */
         case 148: /* w1     */
         case 153: /* x1     */
         case 157: /* down1  */
         case 162: /* y1     */
         case 167: /* z1     */
              PutByte(GetByte(subfile),newfile); break;
              break;
         case 138: /* nop    */
         case 141: /* push   */
         case 142: /* pop    */
         case 147: /* w0     */
         case 152: /* x0     */
         case 161: /* y0     */
         case 166: /* z0     */
              break;
         case 239: /* xxx1   */
              ii=GetByte(subfile);
              if ( EndSpecial(ii, cmd) )
                   done=TRUE;
              break;
         case 240: /* xxx2   */
              ii=GetWord(subfile);
              if ( EndSpecial(ii, cmd) )
                   done=TRUE;
              break;
         case 241: /* xxx3   */
              ii=GetTrio(subfile); 
              if ( EndSpecial(ii,cmd) )
                   done=TRUE;
              break;
         case 242: /* xxx4   */
              ii=GetQuad(subfile);
              if ( EndSpecial(ii,cmd) )
                   done=TRUE;
              break;
              /* fnt_def1...fnt_def4 */
         case 243: case 244: case 245: case 246:
              xxxFontDef(cmd);
	      break;
         case 248: /* post   */
	      done=TRUE; break;
      }

    } /* while !done */

  }
  /* skip over special */
  else
  {
     fseek(subfile,offset,SEEK_SET);
     SkipOver( numbytes, subfile );
  }
  
  return;
}


void FindPage()
{
int     cmd;
integer count,offset;
Boolean found;

  /* position to the final bop */
  fseek(subfile,subpost_p,SEEK_SET);
  cmd = GetByte(subfile);
  if ( cmd!=139 )
       error(" ! cannot locate final page ",subname);
  count = GetQuad(subfile);
  if ( count == pagenum )
       found = TRUE;
  else { offset = 0L; found=FALSE;  }

  while ( !found && offset !=-1L )
  {
      SkipOver(36L,subfile);
      offset = GetQuad(subfile);
      if ( offset != -1L )
      {
           fseek(subfile,offset,SEEK_SET);
           cmd    = GetByte(subfile);
           count  = GetQuad(subfile);      
           if ( count == pagenum )
	        found = TRUE;
      }

  }

  if ( !found )
  {    printf("\n ! cannot find page %ld in %s",pagenum,subname);
       exit(1);
  }
  
  SkipOver(40L,subfile);
  return;
}


void TransferTable()
{
Boolean done;
integer ii;
int     cmd;

   FindPage();

   done=FALSE;
   while ( !done )
   {
      cmd=GetByte(subfile);

      /* set_char_0 thru set_char_127 */
      /* cmd>=0 && cmd<=127 */
   
      /* fnt_num_0 thru fnt_num_63 */
      /* cmd>=171 && cmd<=234 )    */
      if (cmd>=171 && cmd<=234)	
	  FntNum(cmd);

      switch (cmd)
      {
	    /* eight bytes */
       case 132: /* set_rule */
       case 137: /* put_rule */	       
	    GetQuad(subfile);
            /* four bytes  */	   
       case 131: /* set4   */
       case 136: /* put4   */	       
       case 146: /* right4 */	       
       case 151: /* w4 	   */	       
       case 156: /* x4     */	       
       case 160: /* down4  */	       
       case 165: /* y4     */	       
       case 170: /* z4     */	       
    	    GetByte(subfile);
            /* three bytes */
       case 130: /* set3   */
       case 135: /* put3   */	       
       case 145: /* right3 */	       
       case 150: /* w3     */	       
       case 155: /* x3     */	       
       case 159: /* down3  */	       
       case 164: /* y3     */	       
       case 169: /* z3     */	       
    	    GetByte(subfile); 	       
            /* two bytes   */
       case 129: /* set2   */	       
       case 134: /* put2   */	       
       case 144: /* right2 */	       
       case 149: /* w2     */	       
       case 154: /* x2     */	       
       case 158: /* down2  */	       
       case 163: /* y2     */	       
       case 168: /* z2     */	       
    	    GetByte(subfile); 
            /* one byte    */
       case 128: /* set1   */	       	       
       case 133: /* put1   */	       
       case 143: /* right1 */	       
       case 148: /* w1     */	       
       case 153: /* x1     */	       
       case 157: /* down1  */	       
       case 162: /* y1     */	       
       case 167: /* z1     */	       
    	    GetByte(subfile); break;	       
	    break;
       case 139: /* bop    */
	    /* filter thru c0[4]...c9[4] and p[4] */
	    SkipOver(44L,subfile);
	    break;
       case 138: /* nop    */    
       case 140: /* eop    */
       case 141: /* push   */
       case 142: /* pop    */
       case 147: /* w0     */	       
       case 152: /* x0     */	       
       case 161: /* y0     */	       
       case 166: /* z0     */	       
	    break;
       case 235: /* fnt1   */	       
       case 236: /* fnt2   */	       
       case 237: /* fnt3   */
       case 238: /* fnt4   */	       
	    FntNum(cmd);  break;
       case 239: /* xxx1   */
	    ii=GetByte(subfile); 
	    BeginSpecial(ii);
	    done = TRUE;
	    break;
       case 240: /* xxx2   */
	    ii=GetWord(subfile); 
	    BeginSpecial(ii);
	    done = TRUE;
	    break;
       case 241: /* xxx3   */
	    ii=GetTrio(subfile); 
	    BeginSpecial(ii);
	    done=TRUE;	    
	    break;
       case 242: /* xxx4   */	       
	    ii=GetQuad(subfile); 
	    BeginSpecial(ii);
	    done=TRUE;	    
	    break;
            /* fnt_def1...fnt_def4 */	    
       case 246: case 245: case 244: case 243:
	    SubDefFont(cmd);
            break;
       case 248: /* post   */	       
	    done=TRUE; break;
      }
      
  }
   return;	
}


integer GetUniqueNumber()
{
  integer fn;
  int     i,j;
  Boolean found, assigned;
  
     fn = 0L; found = FALSE;
     for (i=0; i<mfonts && !found; i++)
     {  
	assigned = FALSE;
	for (j=0; j<mfonts && !assigned;  j++)
	{
	  if (fn == main_fontlist[j]->k)
          {   fn++; assigned=TRUE; }
	}
	if ( !assigned ) found = TRUE;
     }
  
  return(fn);
}


void AddFontList()
{
   Boolean found;
   int i,j;
   FontType *f1, *f2, *fp;
   char *p, *q;
   integer fn;
   
   for (i=0; i<sfonts; i++)
   {
        f1 = sub_fontlist[i];
	p  = f1->name + f1->a + 1; 
	found = FALSE;
	for (j=0; j<mfonts && !found; j++)
	{
	     f2 = main_fontlist[j];
	     q = f2->name + f2->a + 1;
	     if ( (stricmp(p,q)==0)
		&&(f1->scaledsize==f2->scaledsize)
		&&(f1->designsize==f2->designsize)
	        )
	     {    found = TRUE; fn = f2->k;  fp = f2;  }
	}

	if ( !found )
	{
           fp = (FontType *)malloc(sizeof(FontType));
           if (fp==NULL)
               error("! ran out of memory","");
           main_fontlist[mfonts++] = fp;
	   fp->cmd	   = f1->cmd;
	   fp->checksum    = f1->checksum;
	   fp->scaledsize  = f1->scaledsize;
	   fp->designsize  = f1->designsize;
	   fp->a 	   = f1->a;
	   fp->l 	   = f1->l;
	   fp->name        = f1->name;
	   fn = GetUniqueNumber();
	   fp->k	   = fn;
	}
	/* add to sub list */
	sublist[i].fn   = f1->k;
	sublist[i].new  = fn;
	sublist[i].name = fp->name + fp->a + 1;
   }
   return;	
}


void SubPostamble()
{
integer offset;
int     cmd;
Boolean done;

   fseek(subfile,0L,SEEK_END);
  
   /* skip backwards over 223's until the id byte. */
   fseek(subfile,-1L,SEEK_CUR);
   cmd = GetByte(subfile);
   while (cmd==223)
   {
      fseek(subfile,-2L,SEEK_CUR);
      if ( ftell(subfile)==0L ) 
           error("\n ! error in reading postamble",subname); 
      cmd = GetByte(subfile);
   }
  
   /* back up and read q */
   fseek(subfile,-5L,SEEK_CUR);
   offset=GetQuad(subfile);
   fseek(subfile,offset,SEEK_SET);
   cmd   = GetByte(subfile);

   /* this must be the post cmd */
   if (cmd!=248) 
       error("\n ! error in reading postamble",subname); 
  
   /* skip over post parameters */
   subpost_p = GetQuad(subfile);
   SkipOver(24L,subfile);
   /* font defs */
   done = FALSE;
   while ( !done )
   {
      cmd = GetByte(subfile);
      switch (cmd)
      {
	 case 243: /* fnt_def1 */
         case 244: /* fnt_def2 */
         case 245: /* fnt_def3 */
         case 246: /* fnt_def4 */
	      SubFontDef(cmd);
	      break;
	 default: done=TRUE; break;
      }
  }
  return;	
}


void SubPreamble()
{
   integer num, den, mag;
   quarterword pre, id, k;
      
   pre  = (quarterword) GetByte(subfile);
   id   = (quarterword) GetByte(subfile);
   num  = GetQuad(subfile);
   den  = GetQuad(subfile);
   mag  = GetQuad(subfile);
   k    = (quarterword) GetByte(subfile); 
   /* skip over TeX comment */
   SkipOver((long)k,subfile);

   return;	
}


void ReadSubFile()
{
int  i;

   if ( subfile!= NULL )
        fclose(subfile);

   subfile = fopen(subname, READ_BINARY);
   if (subfile==NULL)
      error("\n ! couldn't open file",subname);

   for (i=0; i<sfonts; i++)
   {
       free(sub_fontlist[i]); sub_fontlist[i]=NULL;
   }
   
   sfonts  = 0;
   SubPostamble();
   AddFontList();

   return; 
}


void bop()
{
int  i,j;
char tmp[80];
integer pageno[10];
char string[200];
int  done;

    post.p = ftell(newfile)-1L;

    /* filter thru c0[4]...c9[4] */
    for (i=0; i<10; i++ )
    { 
      pageno[i] = GetQuad(dvifile);
      PutQuad(pageno[i],newfile);
    }
 
    j = 0; done = FALSE;
    for (i=9; i>0 && !done; i--)
    {
      if ( pageno[i]!=0 ) 
      { j = i; done = TRUE ; }
    }
    
    done = FALSE; string[0] = 0;
    sprintf(string,"[%ld",pageno[0]);
    for (i=1; i<=j; i++)
    {
      sprintf(tmp,".%ld",pageno[i]);
      strcat(string,tmp);
    }
    strcat(string,"]");
    
    i = strlen( string );
    if ( ( ColumnPos + i ) > 80 )
    {  printf("\r\n"); ColumnPos = 0; }
    printf("%s",string);
    ColumnPos += i;
    
    /* p[4] */ 
    GetQuad(dvifile);
    PutQuad(prevbop,newfile);

    prevbop = post.p ;
    
    return;	
}

/* 08/06/1991 PAM Give main a predictable return value for the OS */
int main(argc, argv)
int   argc;
char *argv[];
{
int     cmd,i;
Boolean done;

   if ( argc<2 ) 
   {
      printf("\n\t\tUsage: dvipaste dvifile [newfile]");
      printf("\n\t\tNote:  newfile is optional\n");
      exit(0);
   }


   printf("\nThis is DVIPASTE, Version 1.21");
   printf("\nCopyright (c) 1989-91, The TeXplorators Corporation.");
   printf("\nAll rights reserved.\n");
   
   strcpy(dviname,argv[1]);
   if (strstr(dviname,".")==NULL) 
       strcat(dviname,".dvi");

   if ( argc<=2 )
   {
     strcpy(newname,dviname);
     i = strlen(newname);
     newname[i-1] = 'x';
   }
   else
   {
     strcpy(newname,argv[2]);
     if (strstr(newname,".")==NULL) 
       strcat(newname,".dvi");
   }
   
   dvifile = fopen(dviname, READ_BINARY ) ;
   if (dvifile==NULL)
       error("! couldn't open file",dviname);

   newfile = fopen(newname, WRITE_BINARY);
   if (newfile==NULL)
       error("! couldn't open file",newname);

   Initialize();
   ReadPostamble();
   
   fseek(dvifile,0L,SEEK_SET);
   ReadPreamble();
   
   done=FALSE; 
   while ( !done )
   {
      cmd=GetByte(dvifile); 
      
      /* let's take a peek first at the current cmd before 
	 running thru it.  */
      switch (cmd)
      {  /* this are specials; handle with care. */
	 case 239: case 240: case 241: case 242:
	      /* don't send out cmd yet */
	      break;
	 default:
	      PutByte(cmd,newfile); break;
      }
      
      /* set_char_0 thru set_char_127 */
      /* cmd>=0 && cmd<=127 */
   
      /* fnt_num_0 thru fnt_num_63 */
      if ( cmd>=171 && cmd<=234 )
           fnt.cmd = cmd;

      switch (cmd)
      {
            /* eight bytes */
       case 132: /* set_rule */
       case 137: /* put_rule */
            PutQuad(GetQuad(dvifile),newfile);
            /* four bytes  */
       case 131: /* set4   */
       case 136: /* put4   */
       case 146: /* right4 */
       case 151: /* w4 	   */
       case 156: /* x4     */
       case 160: /* down4  */
       case 165: /* y4     */
       case 170: /* z4     */
            PutByte(GetByte(dvifile),newfile);
            /* three bytes */
       case 130: /* set3   */
       case 135: /* put3   */
       case 145: /* right3 */
       case 150: /* w3     */
       case 155: /* x3     */
       case 159: /* down3  */
       case 164: /* y3     */
       case 169: /* z3     */
            PutByte(GetByte(dvifile),newfile);
            /* two bytes   */
       case 129: /* set2   */
       case 134: /* put2   */
       case 144: /* right2 */
       case 149: /* w2     */
       case 154: /* x2     */
       case 158: /* down2  */
       case 163: /* y2     */
       case 168: /* z2     */
            PutByte(GetByte(dvifile),newfile);
            /* one byte    */
       case 128: /* set1   */
       case 133: /* put1   */
       case 143: /* right1 */
       case 148: /* w1     */
       case 153: /* x1     */
       case 157: /* down1  */
       case 162: /* y1     */
       case 167: /* z1     */
            PutByte(GetByte(dvifile),newfile);
            break;
       case 139: /* bop    */
            bop();
            break;
       case 141: /* push   */
       case 142: /* pop    */
            PopsAndPushes(cmd);
            break;
       case 138: /* nop    */
       case 140: /* eop    */
       case 147: /* w0     */
       case 152: /* x0     */
       case 161: /* y0     */
       case 166: /* z0     */
            break;
       case 235: /* fnt1   */
            fnt.cmd = cmd; fnt.k = GetByte(dvifile);
            PutByte((quarterword)fnt.k,newfile);
            break;
       case 236: /* fnt2   */
            fnt.cmd = cmd; fnt.k = GetWord(dvifile);
            PutWord((halfword)fnt.k,newfile); break;
       case 237: /* fnt3   */
            fnt.cmd = cmd; fnt.k = GetTrio(dvifile);
            PutTrio(fnt.k,newfile);
            break;
       case 238: /* fnt4   */
            fnt.cmd = cmd; fnt.k = GetQuad(dvifile);
            PutQuad(fnt.k,newfile);
            break;
       case 239: /* xxx1   */
       case 240: /* xxx2   */
       case 241: /* xxx3   */
       case 242: /* xxx4   */
            DoSpecial(cmd);
            break;
            /* fnt_def1...fnt_def4 */
       case 243: case 244: case 245: case 246:
            DefFont(cmd);
            break;
       case 248: /* post   */
            post_post.q = ftell(newfile) -1L;
            done=TRUE;
            break;
       }
   }

   WritePostamble(); 
   fclose(dvifile); fclose(newfile);
   if ( subfile != NULL )
        fclose(subfile);
   
   if ( argc<=2 )
   {
       unlink(dviname); rename(newname,dviname);
   }
   printf("\n");
   return(0);
}


/*
   Add strstr() to the strings functions.
   Some versions of SUN cc complain about macros in
   loops, but gcc has no trouble with them.  Depends
   on how the macro is written, I suppose, but I think
   gcc uses the same macro text as cc in this case.
*/
#ifndef ANSI
char *
  strstr(s,t)
char *s,*t;
{
  char *ss;
  ss = s;
  while ( *ss != '\0' ) {
    if ((strcmp(ss,t)) == 0) return ss; 
    ss++;
  }
  return(NULL);
}
#endif
