/* $Id: dvi2xx.c,v 2.5 1997/12/08 20:52:20 neumann Exp $ */
#define VERSION "dviljk (version 2.6p5)"
/*
#define DEBUGGS 1
*/
/**********************************************************************
 ****************************  Intro  *********************************
 **********************************************************************
 * This program translates TeX's DVI-Code into device dependent
 * code of either the
 *
 *     -   HP-LASERJET+ and compatibles (PCL), or the
 *     -   IBM 3812 pageprinter
 *
 * depending on the preprocessor switches specified before compilation.
 * The program is written to run on a PC XT/AT/PS2 under MS-DOS. It can
 * be compiled nicely with MSC Rel. 3.0-5.1 with option -AL (large memory
 * model).  Take care that in the CONFIG.SYS file the FILES parameter
 * is set to 20; otherwise reduce MAXOPEN.  640K are recommended.
 * I use link option /stack:9000 to increase runtime stack.
 * It also works without modifications under Unix System V.
 **********************************************************************
 *            Adapted for the PC:    Gustaf Neumann
 *            +1002 stuff        University of Economics
 *            +3812 support      Augasse 2-6
 *            +Output buffering      A-1090 Vienna, AUSTRIA
 *            +lpt binary support    Tel. *43-222-340525/533
 *            +pk-89 stuff                   773
 *            +pixelpaths
 *            +alternative directory structure
 *            +code compiles also under Unix V (HP/UX)
 *                      (thx Michael Haberler)
 *            +huge characters (a character bigger than 32K)
 *                      formats PXL1001 and PXL 1002
 *                     (use: raster graphics)
 *            +reduction of the produced code
 *            +new options -X -Y -c -g
 *            +changed options -r (LJ now default from first to last)
 *                     -x,-y  (accept floats)
 *            +new option -z for LJ: print testpage containing
 *                     pagecounter after printjob
 *            +try to overcome font limit on LJ (max 16 fonts/page) and
 *             (max 32 fonts/document):
 *                     additional fonts are drawn as bitmap-
 *                     graphics.
 *            +allows to set character close to the paperedge on LJ
 *            +gf-supprt (by Joe Kelsey joe@Pacer.com)
 *                gf.c and gf.h from mitdevices/dvi2ps
 *            +clipping of rules
 *            +OS/2 defines from Rutger Berns, apprmb@hheouh50.bitnet
 *
 *            BITNET/EARN:       NEUMANN at AWIWUW11
 **********************************************************************
 * fixes in LJ-mode:  rule-drawing,
 *            characters with 127<=height<=200
 *            reset printer at beginning and end of each job
 *            better positioning of rules
 * 30.1.89 (0.48) bug fixed for files containing >32 fonts (thanks A. Brosig),
 *                different font assignment heuristic
 * fixes in 3812-mode:  14.juli 87  positioning of rastered characters
 *            better positioning of rules
 * general fixes
 * 1.1.88         page origin set to 1in/1in (hopefully everywhere)
 * 22.7.88        reset y-position for each page-eject
 * 15.1.89        fixing bug is space allocation for EmitFileName
 *                (thanks to Bernhard Simon)
 * 15.3.91 (0.49) landscape support for lj ii p, lj iii and lj 2000
 *                fixing rule drawing problems for IBM3812 in landcape mode,
 *                256 character clean (lj family and IBM3812)
 * 5.5.91 (0.50)  -DSEVENBIT added for older LJ-emulations
 *                -D1, -D2, -D-, -D1-, -D2- options added due to suggestions
 *                from Tomasz Wolniewicz
 **********************************************************************
 * Preprocessor switches:
 *      #define DEBUG    for massive printing of trace information
 *               when -d cmdline option specified
 *      #define IBM3812  produce output for the IBM3812 pageprinter
 *      #define LJ       produce output for the HP Laserjet+ or LJ II
 *      #define LJ2P     produce output for the HP Laserjet LJ IIP, LJ III
 *                       or LaserJet 2000
 *      #define LJ_LARGE_FONT_MEMORY  large FONT Memory for LJ printer family
 *      #define DRAWGLYPH draws PK-Glyphs on stderr
 *      #define USEPXL   use PXL and PK fonts rather than gf fonts
 **********************************************************************
 *             Adapted for Acorn RISC OS computers: Andreas Dehmel
 *             Address:    Andreas Dehmel
 *                       Am Schorn 18
 *                       82327 Tutzing
 *                       Germany
 *                       dehmel@informatik.tu-muenchen.de
 *
 *             Changes:
 *           - Split the whole thing up into smaller files
 *           - Rearranged certain parts of the output
 *           - If fonts are missing a taskobey file is created that
 *             contains MF commands to build the fonts.
 *           - SUPPORT FOR DIAGRAMS AS USED IN DVIVIEW!!!
 *           - Fixed problem of raster chars being scrambled when diagram
 *             printouts were on the same page.
 *             - Raster chars and fonts can now also be downloaded in
 *             compressed format; many thanks to Karl Berry!
 */

#include "dvi2xx.h"

#ifdef SEVENBIT
#define VIS   33
#define VIS2  (VIS+32)
unsigned char
VisChar(c)
unsigned char   c;
{
  c &= 0xff;
  if (c < VIS)
    return ((unsigned char)(160 + c));
  if (c < 128)
    return (c);
  if (c < (255 - VIS2))
    return ((unsigned char)(VIS2 + c));
  return (255);
}
#endif


/**********************************************************************/
/*******************************  main  *******************************/
/**********************************************************************/
int
#if NeedFunctionPrototypes
main(int argc, char *argv[])
#else
main(argc, argv)
int     argc;
char    *argv[];
#endif
{
  struct stack_entry {  /* stack entry */
    long4    h, v, w, x, y, z;  /* what's on stack */
  };
  short   command;           /* current command                         */
  long4   count[10];         /* the 10 counters at begining of each page*/
  long4   cpagep = 0;        /* current page pointer                    */
  bool    Emitting = _FALSE; /* outputting typsetting instructions?     */
  int     i;                 /* command parameter; loop index           */
  int     k;                 /* temporary parameter                     */
  char    n[STRSIZE];        /* command parameter                       */
  int     PassNo = 0;        /* which pass over the DVI page are we on? */
  bool    SkipMode = _FALSE; /* in skip mode flag                       */
  int     sp = 0;            /* stack pointer                           */
  struct  stack_entry stack[STACK_SIZE];  /* stack                      */
  char    SpecialStr[STRSIZE]; /* "\special" strings                    */
  long4   val, val2;         /* temporarys to hold command information  */
  long4   w = 0;             /* current horizontal spacing              */
  long4   x = 0;             /* current horizontal spacing              */
  long4   y = 0;             /* current vertical spacing                */
  long4   z = 0;             /* current vertical spacing                */

#ifdef vms
  extern noshare int errno;
  extern noshare char *sys_errlist[];
#else
# if !defined (__riscos) && !defined (KPATHSEA)
  extern  char *sys_errlist[];
  extern  int   errno;
# endif
#endif

  /* Initialize pixel_files */
  for (i = 0; i <= MAXOPEN; i++)
    pixel_files[i].pixel_file_id = FPNULL;

  x_origin = XDEFAULTOFF; /* x-origin in dots                    */
  y_origin = YDEFAULTOFF; /* y-origin in dots                    */

  setbuf(ERR_STREAM, NULL);
  G_progname = argv[0];
#ifdef KPATHSEA
  kpse_set_program_name(argv[0], "dvilj");
  kpse_set_program_enabled (kpse_pk_format, MAKE_TEX_PK_BY_DEFAULT, kpse_src_compile);
#endif
  DecodeArgs(argc, argv);

#ifdef LJ4
  if (CompressCharWidth < 0) {
    switch(UseCompression) {
    case 0: CompressCharWidth = COMPRESS_WIDTH0; break;
    case 2: CompressCharWidth = COMPRESS_WIDTH2; break;
    case 3: CompressCharWidth = COMPRESS_WIDTH3; break;
    }
  }
#endif

#ifdef KPATHSEA
  kpse_init_prog("DVILJ", RESOLUTION, MFMODE, "cmr10");
#endif

  power[0] = 1;
  for (i = 1; i <= 31; i ++)
    power[i] = power[i - 1] << 1;
  gpower[0] = 0l;
  for ( i = 1; i <= 32; i ++)
    gpower[i] = gpower[i - 1] + power[i - 1];

  if ((i = (int)NoSignExtend(dvifp, 1)) != PRE) {
    Fatal("%s: PRE doesn't occur first--are you sure this is a DVI file?\n\n",
          G_progname);
  }
  i = (int)SignExtend(dvifp, 1);
  if (i != DVIFORMAT) {
    Fatal( "%s: DVI format = %d, can only process DVI format %d files\n\n",
           G_progname, i, DVIFORMAT);
  }

  if (*EmitFileName == '-') {
#ifdef RISC_USE_OSL
    EMTO = BOUTOPEN("Vdu:");
#else
    EMTO = stdout;
#endif
  }
  else
    if ((EMTO = BOUTOPEN(EmitFileName)) == FPNULL)
#ifndef KPATHSEA
      Fatal("opening output file: fopen(%s) : %s", EmitFileName,
#ifdef __riscos
            "Cannot open"
#else
            sys_errlist[errno]
#endif
            )
#endif /* not KPATHSEA */
            ;
#ifdef __riscos
  xosfile_set_type(EmitFileName,0xff4);
#endif

  /* If EmitFileName is "-", we use stdout.  But it is by default open
     in TEXT mode, and we need to switch it to binary, unless they are
     writing to the screen (in which case they get what they deserve).  */
  if (O_BINARY && !isatty(fileno(outfp)))
    AssureBinary(fileno(outfp));

#ifdef TIMING
#ifdef BSD_TIME_CALLS
  ftime(&timebuffer);
  start_time = timebuffer.time + (float)(timebuffer.millitm) / 1000.0;
#else
  gettimeofday(&Tp, NULL);
  start_time = Tp.tv_sec + ((float)(Tp.tv_usec))/ 1000000.0;
#endif
#endif

  /* it is important that these be the very first things output !!! */
  if ( G_header )
    CopyFile( HeaderFileName );

  /*****************************/
  /*for( i0=0; i0<nif; i0++ )  */    /* copy all included files */
  /*    CopyFile( Ifile[i0] ); */
  /*****************************/

#ifdef IBM3812
  PMPout(3, "\307\310\366");          /* unload all fonts and macros */
  EMITWORD(MAX_PAGE_WIDTH);
  EMITWORD(MAX_PAGE_HEIGHT);
  if (Landscape)
    PMPout(2, "\322\1");
#endif

#ifdef LJ
# ifdef LJ4
  /* According to the PCL (p. 4-2) and PJL (p. 4-3) reference manuals, it is
     critical that the UEL escape sequence (\e%-12345X) comes before the
     reset sequence (\eE). According to PJL Reference Manual (p. 4-3) the
     correct order is (1) UEL, (2) PJL commands, (3) Reset and PCL job, (4)
     Reset, (5) UEL. */
  if (ResetPrinter) {
    EMIT1("\033%%-12345X"); /* UEL: Universal Exit Language */
    EMIT2("@PJL SET RESOLUTION=%d\012",RESOLUTION);
    EMIT1("@PJL SET PAGEPROTECT=OFF\012");
    if (econoMode && LJ6)
      EMIT1("@PJL SET ECONOMODE=ON\012");
    /* The PJL ENTER LANGUAGE command must be the last PJL command before
       PCL output starts. */
    EMIT1("@PJL ENTER LANGUAGE=PCL\012");
    EMIT1("\033E");
  }
  EMIT3("\033&u%dD\033*t%dR",RESOLUTION,RESOLUTION);
  if (econoMode && !LJ6)
    EMIT1("\033*v1T");
# else
  if (ResetPrinter)
    EMIT1("\033E");
# endif
# ifdef LJ2P
  if (DuplexMode)
    EMIT2("\033&l%dS", DuplexMode);
# endif
  if (Landscape)
    EMIT1("\033&l1O\033*rF");
  if (pagesize>0) {
# ifndef vms
    EMIT2("\033&l%hdaE\033&aL", pagesize);
# else
    EMIT2("\033&l%daE\033&aL", pagesize);
# endif
  } else
    EMIT1("\033&lE\033&aL");

  if (ncopies>1) {
# ifndef vms
    EMIT2("\033&l%hdX", ncopies);
# else
    EMIT2("\033&l%dX", ncopies);
# endif
  }
#endif /* LJ */

  if (DoublePage) {
    StartPrintPages = PrintPages;
#ifdef IBM3812
    Reverse = (bool)!Reverse; /* perverse and strange */
#endif
  }

  if (ManualFeed)
      EMIT(outfp, "\033&l2H"); /* Manual Feed */

  if (Reverse) {
#ifdef DEBUG
    if (Debug)
      fprintf(ERR_STREAM, "reverse\n");
#endif
    ReadPostAmble(_TRUE);
    FSEEK(dvifp, ppagep, SEEK_SET);
  } else {
    ReadPostAmble(_TRUE);
    FSEEK(dvifp,  14l, SEEK_SET);
    k = (int)NoSignExtend(dvifp, 1);
    GetBytes(dvifp, n, k);
  }
  PassNo = 0;

  while (_TRUE)  {
    command = (short) NoSignExtend(dvifp, 1);
#ifdef DEBUG
    if (Debug)
      fprintf(ERR_STREAM,"CMD@%ld:\t%d\n", (long) ftell(dvifp) - 1, command);
#endif
    switch (command)  {
    case SET1:
    case SET2:
    case SET3:
    case SET4:
      val = NoSignExtend(dvifp, (int)command - SET1 + 1);
      if (!SkipMode)
        SetChar(val, command, PassNo, _TRUE,_FALSE);
      break;
    case SET_RULE:
      val = NoSignExtend(dvifp, 4);
      val2 = NoSignExtend(dvifp, 4);
      if (Emitting)
        SetRule(val, val2, 1);
      break;
    case PUT1:
    case PUT2:
    case PUT3:
    case PUT4:
      val = NoSignExtend(dvifp, (int)command - PUT1 + 1);
      if (!SkipMode)
        SetChar(val, command, PassNo, _TRUE,_FALSE);
      break;
    case PUT_RULE:
      val = NoSignExtend(dvifp, 4);
      val2 = NoSignExtend(dvifp, 4);
      if (Emitting)
        SetRule(val, val2, 0);
      break;
    case NOP:
      break;
    case BOP:
      cpagep = FTELL(dvifp) - 1;
      DEBUG_PRINT ("BOP for [");
      for (i = 0; i <= 9; i++) {
        count[i] = NoSignExtend(dvifp, 4);
        DEBUG_PRINT1 ("%d.", (int) count[i]);
      }
      DEBUG_PRINT1 ("] at %ld.\n", cpagep);
      ppagep = (long)NoSignExtend(dvifp, 4);
      h = v = w = x = y = z = 0;
      hh = vv = 0;
      last_rx = last_ry = UNKNOWN;
      sp = 0;
      fontptr = NULL;
      prevfont = NULL;
      DoBop();
      /*
        fprintf(ERR_STREAM,"skimode %d, count %d, F %d, L %d\n",
        (int)SkipMode,(int)count[0],(int)FirstPageSpecified,(int)LastPageSpecified);
        */
      SkipMode = (bool)((FirstPageSpecified && count[0] < FirstPage) ||
                        (LastPageSpecified && count[0] > LastPage ));
      /*
        fprintf(ERR_STREAM,"skimode %d, count %d, F %d, L %d\n",
        (int)SkipMode,(int)count[0],(int)FirstPageSpecified,(int)LastPageSpecified);
        */

      if (DoublePage && !SkipMode) {
        if (PassNo == 0) {
          LastPtobePrinted = count[0];
          if (!Reverse && (WouldPrint == 0)) {
            if (count[0] == 0l) {
              ZeroPage = _TRUE;
              EvenPage = _FALSE;
            }
            else {
              EvenPage = (bool)( (count[0]<0? labs(count[0])+1: count[0]) %2 == 0);

              if (PrintEmptyPages && EvenPage && PageParity==1) {
                WouldPrint ++;
                if (PrintFirstPart) {
                  qfprintf(ERR_STREAM,"[EvenPage] ");
                  FormFeed();
                }
              }
            }
          }
          WouldPrint ++;
          /*
            fprintf(ERR_STREAM, "doublepage %d, page parity = %d, 1=%d 2=%d, Reverse %d, WouldPrint %d, fpZ %d\n",
            (int)DoublePage, (int)PageParity,(int)PrintFirstPart,(int)PrintSecondPart,
            (int)Reverse, (int)WouldPrint, (int)ZeroPage);
            */
        }
        if (!PrintFirstPart && PageParity==1) {
          if (count[0] == 0) {
            ZeroPage = _TRUE;
            EvenPage = _FALSE;
          }
          SkipMode = _TRUE;
        }
        else {
          /*
            fprintf(ERR_STREAM,"FirstPart\n count %d, mod %d, pp %d\n",(int)count[0],(int)count[0]%2,PageParity);
            */
          SkipMode =
            (bool)(PageParity != (short)((count[0]<0 ?
                                          labs(count[0])+1 : count[0])%2));
          if (count[0] == 0) SkipMode = (bool)!SkipMode;
        }

      }
      Emitting = (bool)((PassNo != 0) && !SkipMode);
      /*
        fprintf(ERR_STREAM,"Emitting= %d, PassNo=%d, SkipMode = %d\n",(int)Emitting,(int)PassNo,(int)SkipMode);
        */
      if ( !SkipMode ) {
        if (PassNo == 0)
          qfprintf(ERR_STREAM,"[%ld",  (long)count[0]);
      }
      break;
    case EOP:
      if ( !SkipMode ) {
        if (PassNo == 0) {
          /* start second pass on current page */
          FSEEK(dvifp, cpagep, SEEK_SET);
          PassNo = 1;
#ifdef DEBUG
          if (Debug)
            fprintf(ERR_STREAM,"\nStarting second pass\n");
#endif

        } else {
          /* end of second pass, and of page processing */

          last_rx = last_ry = UNKNOWN;
          FormFeed();
          ++ndone;

          qfprintf(ERR_STREAM,"] ");
          if ( (ndone % 10) == 0 )
            qfprintf(ERR_STREAM,"\n");

          if (DoublePage) --PrintPages;
          if (--PrintPages < 1) AllDone(_TRUE);
          PassNo = 0;
        }
      } else
        PassNo = 0;

      if ( PassNo == 0 && Reverse ) {
        if ( ppagep > 0 )
          FSEEK(dvifp, ppagep, SEEK_SET);
        else {
          if (DoublePage && !SkipMode)
            ZeroPage = (bool)(count[0] == 0);

          if (ZeroPage)
            EvenPage = _FALSE;
          else
            EvenPage = (bool)((int)LastPtobePrinted%2 == 0);

          AllDone(_FALSE);
        }
      }
      break;
    case PUSH:
      if (sp >= STACK_SIZE)
        Fatal("stack overflow");
      stack[sp].h = h;
      stack[sp].v = v;
      stack[sp].w = w;
      stack[sp].x = x;
      stack[sp].y = y;
      stack[sp].z = z;
      sp++;
      break;
    case POP:
      --sp;
      if (sp < 0)
        Fatal("stack underflow");
      h = stack[sp].h;
      v = stack[sp].v;
      w = stack[sp].w;
      x = stack[sp].x;
      y = stack[sp].y;
      z = stack[sp].z;
      last_rx = last_ry = UNKNOWN;
      break;
    case RIGHT1:
    case RIGHT2:
    case RIGHT3:
    case RIGHT4:
      val = SignExtend(dvifp, (int)command - RIGHT1 + 1);
      if (Emitting)
        MoveOver(val);
      break;
    case W0:
      if (Emitting)
        MoveOver(w);
      break;
    case W1:
    case W2:
    case W3:
    case W4:
      w = SignExtend(dvifp, (int)command - W1 + 1);
      if (Emitting)
        MoveOver(w);
      break;
    case X0:
      if (Emitting)
        MoveOver(x);
      break;
    case X1:
    case X2:
    case X3:
    case X4:
      x = SignExtend(dvifp, (int)command - X1 + 1);
      if (Emitting)
        MoveOver(x);
      break;
    case DOWN1:
    case DOWN2:
    case DOWN3:
    case DOWN4:
      val = SignExtend(dvifp, (int)command - DOWN1 + 1);
      if (Emitting)
        MoveDown(val);
      break;
    case Y0:
      if (Emitting)
        MoveDown(y);
      break;
    case Y1:
    case Y2:
    case Y3:
    case Y4:
      y = SignExtend(dvifp, (int)command - Y1 + 1);
      if (Emitting)
        MoveDown(y);
      break;
    case Z0:
      if (Emitting)
        MoveDown(z);
      break;
    case Z1:
    case Z2:
    case Z3:
    case Z4:
      z = SignExtend(dvifp, (int)command - Z1 + 1);
      if (Emitting)
        MoveDown(z);
      break;
    case FNT1:
    case FNT2:
    case FNT3:
    case FNT4:
      k = NoSignExtend(dvifp, (int) command - FNT1 + 1);
      if (!SkipMode) {
        SetFntNum(k, Emitting);
      }
      break;
    case XXX1:
    case XXX2:
    case XXX3:
    case XXX4:
      k = (int)NoSignExtend(dvifp, (int)command - XXX1 + 1);
      GetBytes(dvifp, SpecialStr, k);
      if (Emitting)
        DoSpecial(SpecialStr, k);
      break;
    case FNT_DEF1:
    case FNT_DEF2:
    case FNT_DEF3:
    case FNT_DEF4:
      k = (int)NoSignExtend(dvifp, (int)command - FNT_DEF1 + 1);
      SkipFontDef();    /* SkipFontDef(k); */
      break;
    case PRE:
      Fatal("PRE occurs within file");
      break;
    case POST:
      AllDone(_FALSE);
      PassNo = 0;
      break;
    case POST_POST:
      Fatal("POST_POST with no preceding POST");
      break;
    default:
      if (command >= FONT_00 && command <= FONT_63) {
        if (!SkipMode)
          SetFntNum((long4)command - FONT_00, Emitting);
      } else if (command >= SETC_000 && command <= SETC_127) {
        if (!SkipMode) {
          SetString(command, PassNo);
        }
      } else
        Fatal("%d is an undefined command", command);
      break;
    }
  } /* while _TRUE */
}






/*------------------------ begin dviIO.c ----------------------------------*/

/* The following functions buffer input/output during CopyFile / CopyHPFile
   Write functions are only needed if RISC_BUFFER is defined; otherwise output
   is not buffered. */

/* read a buffered byte */
char
#if NeedFunctionPrototypes
b_read(FILEPTR spfp)
#else
b_read(spfp)
FILEPTR spfp;
#endif
{
  if (biact >= binumber) {
#ifdef RISC_USE_OSL
    binumber = BUFFSIZE - read_multi(buffin,1,BUFFSIZE,spfp);
#else
    binumber = read_multi(buffin,1,BUFFSIZE,spfp);
#endif
    biact = 0;
  }
  return binumber == 0 ? 0 : buffin[biact++];
}

#ifdef RISC_BUFFER
void
#if NeedFunctionPrototypes
b_write(FILEPTR spfp, char c) /* write a buffered byte */
#else
b_write(spfp, c)
FILEPTR spfp;
char c;
#endif
{
  if (boact >= BUFFSIZE) {
    write_multi(buffout,1,BUFFSIZE,spfp);
    boact = 0;
  }
  buffout[boact++] = c;
}

void
#if NeedFunctionPrototypes
b_wrtmult(FILEPTR spfp, char *buf, int len) /* write a sequence of bytes to the output buffer */
#else
b_wrtmult(spfp, buf, len)
FILEPTR spfp;
char *buf;
int len;
#endif
{
  register int i;

  if ((len > (BUFFSIZE - boact)) || (len >= (BUFFSIZE/4))) {
    write_multi(buffout,1,boact,spfp);
    /* Copy only small blocks; large ones are written directly */
    if (len < (BUFFSIZE/4)) {
      for (i = 0; i<len; i++)
        buffout[i] = buf[i];
      boact = len;
    } else {
      write_multi(buf,1,len,spfp);
      boact = 0;
    }
  }
  else {
    for (i = 0; i<len; i++)
      buffout[boact++] = buf[i];
  }
}

/* flush the output buffer */
void
#if NeedFunctionPrototypes
b_oflush(FILEPTR spfp)
#else
b_oflush(spfp)
FILEPTR spfp;
#endif
{
  write_multi(buffout,1,boact,spfp);
  boact = 0;
}
#endif
/* end of buffer handling functions */


/*-->CopyFile*/   /* copy a file straight through to output */
/*********************************************************************/
/***************************** CopyFile ******************************/
/*********************************************************************/
void
#if NeedFunctionPrototypes
CopyFile(char *str )
#else
CopyFile( str )
char    *str;
#endif
{
  FILEPTR spfp;
  int     todo;

  if ( (spfp = BINOPEN(str)) == FPNULL ) {
    if ( errno != EACCES || ! kpse_tex_hush("readable") ) {
      Warning("Unable to open file %s (errno=%d), skipping inclusion",
	      str, errno);
    }
    return;
  }
  qfprintf(ERR_STREAM," [%s", str);
#ifdef RISC_BUFFER
  b_oflush(outfp);
#endif
  do {
    todo = read_multi(buffin,1,BUFFSIZE,spfp);
    write_multi(buffin,1,todo,outfp);
  }
  while (todo == BUFFSIZE);

  BCLOSE(spfp);
  qfprintf(ERR_STREAM,"]");
}


/*-->CopyHPFile*/  /* copy a HP file to output removing unwanted control codes*/
/*********************************************************************/
/***************************** CopyHPFile ******************************/
/*********************************************************************/
#if NeedFunctionPrototypes
int getnum(FILEPTR spfp, char *t, char *numstr)
#else
int getnum(spfp, t, numstr)
FILEPTR spfp;
char *t, *numstr;
#endif
{
  int count=0;
  for (*t = (char)b_read(spfp); *t<0x40; *t = (char)b_read(spfp))
    numstr[count++] = *t;
  numstr[count] = 0;
  return atoi(numstr);
}

#if NeedFunctionPrototypes
void setOffset(char dir, char sign, int pos)
#else
void setOffset(dir, sign, pos, first)
char dir, sign;
int pos;
#endif
{
  if ((sign == '+' || sign == '-') && pos > 0 ) {
    EMIT4("\033*p%c%d%c",sign,pos,dir);
#ifdef DEBUGGS
    fprintf(stderr, "relative: *p%c%d%c\n", sign, pos, dir);
#endif
  } else if (pos>0) {
    EMIT3("\033*p%d%c",pos,dir);
#ifdef DEBUGGS
    fprintf(stderr, "absolute: *p%d%c\n", pos, dir);
#endif
    if (dir == 'X')
      last_rx = pos;
    else
      last_ry = pos;
  } else {
    /*EMIT3("\033*p%d%c",pos,dir);*/
#ifdef DEBUGGS
    fprintf(stderr, "Relative: *p%d%c\n", pos, dir);
#endif
  }
}


void
#if NeedFunctionPrototypes
CopyHPFile(char *str )
#else
CopyHPFile( str )
char    *str;
#endif
{
  FILEPTR spfp;
  char    t,numstr[20];
  int     count,miny,minx,num;

  if ( (spfp = BINOPEN(str)) == FPNULL ) {
    if ( errno != EACCES || ! kpse_tex_hush("readable") ) {
      Warning("Unable to open file %s (errno=%d), skipping inclusion",
	      str, errno);
    }
    return;
  }
  minx = 32767;                 /* Set to a high value initially */
  miny = 32767;

  /* Pass through the input PCL file twice.  The first time find the
     smallest x- and y-offsets so that they can be subtracted out when
     sending positioning commands later.  The second pass strips the
     unwanted commands from the input file and outputs the rest */

  /* reset the input buffer */
  binumber = 0;
  biact = 0;

  qfprintf(ERR_STREAM," [%s", str);
  /* Test for !EOF now ((binumber == BUFFSIZE) || (biact < binumber)) */
  do {
    t = (char)b_read(spfp);
    if (t==0x1B) { /* Find the escape character */
      t = (char)b_read(spfp);
      if (t==0x2A) { /* This indiactes the start of a graphics command */
        t = (char)b_read(spfp);
        switch(t) {
        case('p'):
          /* These are the graphics positioning commands */
          /* Find the smallest x and y offsets */
          num = getnum(spfp, &t, numstr);

          /* Take into account the possible different ordering */
          /* of the commands (x first, y first) */

          if (t=='Y' || t=='y') {
            if (numstr[0]!='+' && numstr[0]!='-' && num<miny)
              miny = num;
            if (t=='y') {
              num = getnum(spfp, &t, numstr);
              if (numstr[0]!='+' && numstr[0]!='-' && num<minx)
                minx = num;
            }
          }
          if (t=='X' || t=='x') {
            if (numstr[0]!='+' && numstr[0]!='-' && num<minx)
              minx = num;

            if (t=='x') {
              num = getnum(spfp, &t,numstr);
              if (numstr[0]!='+' && numstr[0]!='-' && num<miny)
                miny = num;
            }
          }
          break;
          /* Ignore all other commands for the moment - just read them */
        case(0x74):
          for (t = (char)b_read(spfp); t != 0x52; t = (char)b_read(spfp));
          break;

        case(0x72):
          for (t = (char)b_read(spfp); ((t< 0x40)||(t>0x60)); t = (char)b_read(spfp));
          break;

        case(0x62):
          num = 0;
          count = 0;
          /* Read in the correct number of bytes of raster graphics */
          /* so that we don't get commands and raster graphics confused */

          for (t = (char)b_read(spfp); ((t<0x40)||(t>=0x60)); t = (char)b_read(spfp))
            numstr[count++]=t;
          numstr[count]=0;
          if (t==0x4D)
            for(t = numstr[count = 0]; t!=0; t = numstr[++count]);
          if (t==0x57) {
            for(t = numstr[count = 0]; t!=0; t = numstr[++count]);
            for(count = atoi(numstr); count>0; count--)
              t = (char)b_read(spfp);
          }
          break;

        case(0x63):
          for (t = (char)b_read(spfp); t< 0x40 || t>0x60; t = (char)b_read(spfp));
          break;

        default:
          break;
        }
      }
    }
  }
  while ((binumber == BUFFSIZE) || (biact < binumber));

  /* reset input buffer, to read it anew */
  if ( FSEEK(spfp, 0L, SEEK_SET) == -1 ) {
    Warning(" could not seek to start of file (errno=%d), abandon %s inclusion",
	    errno, str);
    return;
  }
  binumber = 0;
  biact = 0;


  /* Pass through the input file again but this time output the */
  /* retained PCL commands */
#ifdef DEBUGGS
  fprintf(stderr,"\nminx=%d, miny=%d, xg=%d, yg=%d\n",
          minx, miny, x_goffset, y_goffset);
#endif
  do {
    t = (char)b_read(spfp);
    if (t==0x1B) {
      t = (char)b_read(spfp);
      if (t==0x2A) {
        t = (char)b_read(spfp);
        switch(t) {
        case('p'):
          num = getnum(spfp, &t,numstr);
          if (t == 'Y' || t == 'y') {
            if (numstr[0]!='+' && numstr[0]!='-') {
              /* Subtract the minimum offset found in first pass */
              /* and add in the current vertical offset */
              setOffset('Y',numstr[0],
                        num-miny + (int)PIXROUND(v,vconv) + y_goffset);
            } else {
              setOffset('Y',numstr[0], num);
            }

            if (t == 'y') {
              num = getnum(spfp, &t,numstr);
              if (numstr[0]!='+' && numstr[0]!='-') {
                /*Add in correct horizontal offset */
                setOffset('X',numstr[0],
                          num - minx + (int)PIXROUND(h,hconv) + x_goffset);
              } else if (num>=0) {
                setOffset('X',numstr[0], num);
              }
            }
          }

          if (t=='X' || t=='x') {
            if (numstr[0]!='+' && numstr[0]!='-') {
              /*Add in the correct horizontal offset*/
              setOffset('X',numstr[0],
                        num - minx + (int)PIXROUND(h,hconv) + x_goffset);
            } else {
              setOffset('X',numstr[0], num);
            }

            if (t=='x') {
              num = getnum(spfp, &t,numstr);
              if (numstr[0]!='+' && numstr[0]!='-') {
                /* Subtract the minimum offset found in first pass */
                /* and add in the current vertical offset */
                setOffset('Y',numstr[0],
                          num-miny + (int)PIXROUND(v,vconv) + y_goffset);
              } else {
                setOffset('Y',numstr[0], num);
              }
            }
          }
          break;

        case(0x74):
          /* Set the Raster resolution */
          EMIT1("\033*t");
          for (t = (char)b_read(spfp); t != 0x52; t = (char)b_read(spfp))
            EMITC(t);
          EMITC(t);
          break;

        case(0x72):
          /* Raster Graphics commands such as start */
          EMIT1("\033*r");
          for (t = (char)b_read(spfp); t< 0x40 || t>0x60; t = (char)b_read(spfp))
            EMITC(t);
          EMITC(t);
          break;

        case(0x62):
          /* Transfer the correct number of bytes of raster graphics */
          EMIT1("\033*b");
          num = 0;
          count = 0;
          for (t = (char)b_read(spfp); t<0x40 || t>=0x60; t = (char)b_read(spfp))
            numstr[count++] = t;
          numstr[count] = 0;
          if (t==0x4D) {
            for (t = numstr[count = 0]; t!=0; t = numstr[++count])
              EMITC(t);
            EMIT1("M");
          }
          if (t==0x57) {
            for(t = numstr[count = 0]; t!=0; t = numstr[++count])
              EMITC(t);
            EMIT1("W");
            for (count = atoi(numstr); count>0; count--) {
              t = (char)b_read(spfp);
              EMITC(t);
            }
          }
          break;

        case(0x63):
          /* Rectangular draw commands */
          EMIT1("\033*c");
          for (t = (char)b_read(spfp); t<0x40 || t>0x60;
               t = (char)b_read(spfp))
            EMITC(t);
          EMITC(t);
          break;

        default:
          break;
        }
      }
    }
  }
  while ((binumber == BUFFSIZE) || (biact < binumber));

  BCLOSE(spfp);
  qfprintf(ERR_STREAM,"]");
}

/* This function closes all open files */
void
#if NeedFunctionPrototypes
CloseFiles(void)
#else
CloseFiles()
#endif
{
  struct font_entry *fe;
  FILEPTR f;

  /* First input/output files */
  if (outfp != FPNULL) {
#ifdef RISC_BUFFER
    b_oflush(outfp);
#endif
    BCLOSE(outfp);
  }
  if (dvifp != FPNULL) {
    BCLOSE(dvifp);
  }
#ifdef __riscos
  if (metafile != FPNULL) {
    BCLOSE(metafile);
  }
#endif
  /* Now all open font files */
  fe = hfontptr;
  while (fe != NULL) {
    f = fe->font_file_id;
    if ((f != FPNULL) && (f != NO_FILE)) {
      BCLOSE(f);
    }
    fe = fe->next;
  }
}

/*-->NoSignExtend*/
/**********************************************************************/
/***************************  NoSignExtend  ***************************/
/**********************************************************************/
long4
#if NeedFunctionPrototypes
NoSignExtend(FILEPTR fp, register int n)
#else
NoSignExtend(fp, n)     /* return n byte quantity from file fd */
register FILEPTR fp;    /* file pointer    */
register int    n;      /* number of bytes */
#endif
{
  long4 x = 0;      /* number being constructed */
  unsigned char h;
  while (n--) {
    x <<= 8;
    read_byte(fp,h);
    x |= h;
  }
  /* fprintf(stderr,"[%ld] ",(long)x);*/
  return(x);
}


#ifndef ARITHMETIC_RIGHT_SHIFT
long4   signTab[5] = {0,0x00000080,0x00008000,0x00800000,0x00000000};
long4 extendTab[5] = {0,~0^0xff,~0^0xffff,~0^0xffffff,~0^0xffffffff};
#endif

/*-->SignExtend*/
/**********************************************************************/
/****************************  SignExtend  ****************************/
/**********************************************************************/
long4
#if NeedFunctionPrototypes
SignExtend(FILEPTR fp, register int n)
#else
SignExtend(fp, n)     /* return n byte quantity from file fd */
register FILEPTR fp;  /* file pointer    */
register int     n;   /* number of bytes */
#endif
{
  int     n1;       /* number of bytes      */
  long4   x;        /* number being constructed */
  unsigned char    h;
#ifdef SIGN_DEBUG
  long4    x0;      /* copy of x  */
#endif
  read_byte(fp,h);
  x = h; /* get first (high-order) byte */
  n1 = n--;
  while (n--) {
    x <<= 8;
    read_byte(fp,h);
    x |= h;
  }
  /*
   *   NOTE: This code assumes that the right-shift is an arithmetic, rather
   *   than logical, shift which will propagate the sign bit right.   According
   *   to Kernighan and Ritchie, this is compiler dependent!
   */

#ifdef SIGN_DEBUG
  x0 = x;
#endif

#ifdef ARITHMETIC_RIGHT_SHIFT
  x <<= 32 - 8 * n1;
  x >>= 32 - 8 * n1; /* sign extend */
#else
  if (x & signTab[n1]) x |= extendTab[n1];
#endif

#ifdef SIGN_DEBUG
  fprintf(ERR_STREAM,"\tSignExtend(fp,%d)=%lX, was=%lX,%d\n",
          n1,x,x0,x0&signTab[n1]);
#endif

#ifdef DEBUG
  if (Debug > 1)
    fprintf(ERR_STREAM,"\tSignExtend(fp,%d)=%lX\n", n1, x);
#endif
  return(x);
}


#ifdef IBM3812
/*-->PMPout*/
/*****************************************************************************/
/* This routine produces the PMP-envelopes for the 3812. Its semantics are:

   first arg == 0  ... flush buffer
   first arg == -1 ... number of bytes specified in the second argument
               have to be continuous, that is they must not
               be disrupted by ENTER PMP etc.
   first arg > 0       output first arg bytes

               If arg2 > OUTBUFSIZE ... flush buffer,
                        switch to unbuffered mode
                        (dont't collect PMP commands)
               If arg2+bufferpointer > OUTBUFSIZE ... flush buffer,
                        block will fit into buffer
               otherwise ..... block will fit into buffer

  Buffering is done to reduce the ENTER PMP-commands. Initially
  the 3812 is in PC-ASCII mode. In order to issue a PMP-command it is
  necessary to enter PMP mode. The ENTER-PMP-command contains the
  number of bytes that will be interpreted as PMP-commands. In the
  most naive approach for each primitive command (eg. set cursor) you
  have to produce a seperate ENTER-PMP-envelope (5 bytes). It is
  favourable to collect as many PMP commands as possible in one envelope. */
/*****************************************************************************/
void
#if NeedFunctionPrototypes
PMPout(int l, char *s)
#else
PMPout(l, s)
int     l;
char    *s;
#endif
{
  static char           buffer[OUTBUFSIZE];
  static unsigned short bp = 0;         /* range 0..OUTBUFSIZE */
  static long4          continuous = 0l;
  static bool           buffered = _TRUE;

  if (l == 0) {
    if (bp == 0)
      return;
    EMIT3("\033[C%c%c", (unsigned char)(bp & 0xFF), (unsigned char)(bp >> 8));
    EMITB((int)bp, buffer);
    bp = 0;
    return;
  }
  if (l == -1) {
    continuous = (long4)s;
    if (continuous + (long4)bp + 5l > (long4)OUTBUFSIZE)
      PMPflush;
    buffered = (bool)((continuous + 5l <= (long4)OUTBUFSIZE));
    if (!buffered) {
      EMIT3("\033[C%c%c", (unsigned char)(continuous & 0xFF),
            (unsigned char)((continuous >> 8) & 0xFF));
    }
    return;
  }
  if (buffered) {
    register int    i;
    if ( ((long4)l + bp) > OUTBUFSIZE)
      PMPflush;
    for (i = 0; i < l; i++)
      buffer[bp+i] = s[i];
    bp += (unsigned short)l;
  } else {
    EMITB((int)l, s);
    buffered = (bool)((continuous -= (long4)l) <= 0);
  }
}


void
#if NeedFunctionPrototypes
PMPoutC(char c)
#else
PMPoutC(c)
char c;
#endif
{
  PMPout(1, &c);
}
#endif /* IBM3812 */


#ifdef MSC5
/*-->AssureBinary*/
/**********************************************************************/
/*************************** AssureBinary *****************************/
/**********************************************************************/
/* This procedure is both DOS AND MSC dependent. The MSC file open on */
/* a device ignores the 'binary' of the "wb" parameter and opens the  */
/* file in ascii mode. This procedure sets the file f to binary mode  */
/* if it is connected to a device that is not console input or output */
/* or the null device. For other operating systems this routine is    */
/* useless. (Background: MSDOS 3.2 Technical Reference upd 1 pg 6-137 */
/**********************************************************************/
void
#if NeedFunctionPrototypes
AssureBinary(FILEPTR f)
#else
AssureBinary(f)
FILEPTR f;
#endif
{
  union REGS regs;                      /* registers for bios call */

  regs.h.ah = (unsigned char) 0x44;     /* IOCTL                   */
  regs.h.al = (unsigned char) 0x00;     /* get device information  */
  regs.x.bx = (unsigned int) fileno(f); /* handle from MSC         */
  intdos(&regs, &regs);                 /* call DOS interrupt      */
                                        /* ---> result in DX       */

  if (  (regs.h.dl & 0x80)              /* file handle points to a device */
        && !(regs.h.dl & 0x07) ) {      /* neither console i/o or null    */

    regs.h.dl  |= 0x20;                 /* set BINARY bit in device info  */
    regs.h.ah = (unsigned char) 0x44;   /* IOCTL                  */
    regs.h.al = (unsigned char) 0x01;   /* set device information */
    regs.x.bx = (unsigned int) fileno(f); /* handle from MSC      */
    regs.h.dh = (unsigned char) 0x00;   /* clear DH               */
    intdos(&regs, &regs);               /* call DOS interrupt     */
  }
}
#endif /* MSC5 */

/*------------------------ end dviIO.c ----------------------------------*/

/*------------------------ begin dvichars.c -----------------------------*/
/*-->EmitChar*/
/**********************************************************************/
/****************************  EmitChar  ******************************/
/**********************************************************************/
void                     /* output a character bitmap */
#if NeedFunctionPrototypes
EmitChar(long4 c, struct char_entry *ce)
#else
EmitChar(c, ce)
long4    c;
struct char_entry *ce;
#endif
{
  register int i;
  register unsigned char  *sl;
  unsigned short nbpl, nwpl;
  long     total;
#ifdef LJ
  unsigned char cnv_buffer[10];
#endif


#ifdef LJ
/*
printf("Emit character %c(%d) id=%d, yoff=%d[%d], w=%d[%d], h=%d[%d]\n",
        (char)c,(int)c,
    fontptr->plusid,
    ce->yOffset, fontptr->max_yoff,
    ce->width,   fontptr->max_width,
    ce->height,  fontptr->max_height
);
*/
#endif



  if ( fontptr->ncdl == 0 ) {
#ifdef IBM3812
    used_fontstorage += 1028;
#endif
#ifdef LJ
    if (fontptr->max_width == 0) { /* we have no realistic values */
      fontptr->max_yoff = CHAR_HEIGTH_LARGE;
      fontptr->max_width = CHAR_WIDTH_LARGE;
      fontptr->max_height = CHAR_HEIGTH_LARGE*2;
    }

    /* open font dict before first char, set active font */
    INT_ASCII(cnv_buffer,fontptr->plusid);
# ifdef LJ4
    EMIT2("\033*c%sD\033)s68W", cnv_buffer);
    EMITB(6, "\0\104\024\2\0\0");
# else
    EMIT2("\033*c%sD\033)s64W", cnv_buffer); /* changed 26 to 64 (khk) */
    EMITWORD( 64 );                     /* Font descriptor size */
    EMITC((char) 0 );                   /* res0 (byte) */
#  ifdef SEVENBIT
    EMITC((char) 1);                    /* Font Type */
#  else
    EMITC((char) 2);                    /* Font Type */
#  endif /* SEVENBIT */
    EMITWORD( 0 );                      /* res1 */
# endif /* LJ 4 */
    EMITWORD( fontptr->max_yoff);       /* Baseline Distance */
    EMITWORD( fontptr->max_width);      /* Cell Width */
    EMITWORD( fontptr->max_height);     /* Cell Height */
    EMITC((char) 0);            /* Orientation */
    EMITC((char) 1);            /* Spacing */
    EMITWORD( 277 );            /* Symbol Set */
    EMITWORD( 1024 );           /* Pitch */
    EMITWORD( 1024 );           /* Height */
    EMITWORD( 0 );              /* xHeight */
    EMITC((char) 0);            /* Width Type */
    EMITC((char) 0);            /* Style */
    EMITC((char) 0);            /* Stroke Weight */
    EMITC((char) 0);            /* Typeface */
    EMITC((char) 0);            /* res2 (byte) */
    EMITC((char) 0);            /* Serif Style */
    EMITWORD( 0 );              /* res 3 */
    EMITC((char) 0);            /* Underline Distance */
    EMITC((char) 0);            /* Underline Height */
    EMITWORD( 0 );              /* Text Height */
    EMITWORD( 0 );              /* Text Width */
    EMITWORD( 0 );              /* res4 */
    EMITWORD( 0 );              /* res5 */
    EMITC((char) 0);            /* Pitch Extended */
    EMITC((char) 0);            /* Height Extended */
    EMITWORD( 0 );              /* res6 */
    EMITWORD( 0 );              /* res7 */
    EMITWORD( 0 );              /* res8 */
    EMITB(16,"                ");
# ifdef LJ4
    EMITB(4 ,"\2\130\2\130");
# endif
    EMIT1("\033*c4F");
#endif /* LJ */
    }
  if ( fontptr != prevfont ) {   /* because this isn't done on pass 0 */
#ifdef LJ
    INT_ASCII(cnv_buffer,fontptr->plusid);
    EMIT2("\033(%sX", cnv_buffer);
#endif
    prevfont = fontptr;
  }

#ifdef USEPXL
  if (fontptr->id == pk89) {
    nwpl = 0; /* initialize variable */
    nbpl = ((int)(ce->width) +  7) >> 3;
    total = (long)ce->height * nbpl;
  } else if (fontptr->id == id1002) {
    nwpl = 0; /* initialize variable */
    nbpl = ((int)(ce->width) +  7) >> 3;
    total = (long)ce->height * nbpl;
  } else if (fontptr->id == id1001) {
    nwpl = ((int)(ce->width) + 31) >> 5;
    nbpl = ((int)(ce->width) + 7) >> 3;
    total = (long)ce->height * nbpl;
  } else {
    /* should never be necessary */
    nwpl = 0;
    nbpl = 0;
    total = 0;
  }
#else
  nbpl = (num_cols + 7) >> 3;
  total = num_rows * nbpl;
#endif
/***************************************************************
    if ( ((char) c == 'i') && (fontptr->plusid == 0)) {
        long j;
        fprintf(ERR_STREAM, "cols=%ld, ncols=%ld\n",(long)nwpl,(long)nbpl);

        fprintf(ERR_STREAM, "%ld Bytes:->",(long)total);
        for (j=0; j<total; j++) {
            char *ch; char ic;
            ch = (char *)(ce->where.address.pixptr);
            ic = *(ch+j);
            fprintf(ERR_STREAM,"%X.",ic);
                }
        fprintf(ERR_STREAM,"<- Now Emitting\n");
        }
***************************************************************/
#ifdef USEPXL
#ifdef IBM3812
  if ((short)(ce->height) - ce->yOffset > 55) {
    ce->yyOffset = (short) ce->height - ce->yOffset;
    ce->yOffset  = (short) ce->height;
  } else {
    ce->yyOffset = (short) 0;
  }
#endif
#ifdef LJ
  ce->yyOffset = (short) 0;
#endif
#endif

  /* ce->cw = (long4)(((double)ce->tfmw / (double)hconv) +0.5); */
  /* set active font to nn, load font pattern  xx ... */
#ifdef IBM3812
  PMPcont(total + 9);
# ifdef USEPXL
  sprintf(PMPformat, "\323%c\360%c%c%c",
          (unsigned char)fontptr->plusid,
          (unsigned char)VisChar((char)c),
          (unsigned char)ce->height,
          (unsigned char)ce->width);
  PMPout(6, PMPformat);
  PMPoutC((char)(-(ce->xOffset)));
  PMPoutC((char)(ce->cw - (-ce->xOffset + ce->width)));
  PMPoutC((char)(ce->yOffset));
# else
  sprintf(PMPformat, "\323%c\360%c%c%c",
          (unsigned char)fontptr->plusid,
          (unsigned char)VisChar((char)c),
          (unsigned char)num_rows,
          (unsigned char)num_cols);
  PMPout(6, PMPformat);
  PMPoutC((char)(-x_offset));
  PMPoutC((char)(ce->cw - (-x_offset + num_cols)));
  PMPoutC((char)num_rows-y_offset);
# endif
#endif

#ifdef LJ
# ifdef LJ4
  if (CompressFontMode) { /* Should we use compressed font downloading? */
    /* For COMPRESSED CHARS */
    if (PrevSize < nbpl) {
      PrevSize = nbpl;
      if (PrevLine != NULL)
        free(PrevLine);
      if ((PrevLine = (unsigned char*)malloc(PrevSize*sizeof(char)))
          == NULL) {
        PrevSize = 0;
        Fatal("EmitChar: Out of memory error!\n");
      }
    }
    /* Clear seed line */
    for (i = 0; i<nbpl; i++)
      PrevLine[i] = 0;
    CChar_Off = 0;
    CChar_Last = -1;

    /* This bit copied from below... */
#  ifdef USEPXL
    if (fontptr->id == pk89)
      PkRaster(ce,2);
    else if (fontptr->id == id1002)
      for (i = 0; i < (int)ce->height; i++) {
        sl = ((unsigned char *)(ce->where.address.pixptr) + i * nbpl);
        CompressedCharLine(ce,nbpl,sl);
      }
    else if (fontptr->id == id1001)
      for (i = 0; i < (int)ce->height; i++) {
        sl = (unsigned char *)(ce->where.address.pixptr + i * nwpl);
        CompressedCharLine(ce,nbpl,sl);
      }
#  else
    for (i = num_rows; i > 0; i--)
      CompressedCharLine(ce,nbpl,(bits + (i-1)*nbpl));
#  endif /* USEPXL */
  }
  else
    CChar_Off = -1;
# endif /* LJ4 */

  INT_ASCII(cnv_buffer,fontptr->plusid);
  /* Depending on whether character could be packed or not the header looks
     different! */
# ifdef LJ4
  /* printf("raw: %d (%d * %d), comp: %d\n",
     total,ce->width,ce->height,CChar_Off); */
  /* Characters that don't compress well are usually rather small so
     reading them again and writing them uncompressed won't take
     much time anyway. */
  if (CChar_Off > total)
    CChar_Off = -1;
  if (CChar_Off >= 0) {
    EMIT4("\033*c%sd%dE\033(s%ldW", cnv_buffer,
          (unsigned int)VisChar((char)c), (long)(CChar_Off + 16));
    EMITB(4, "\4\0\016\2");
  }
  else
# endif
    {
      EMIT4("\033*c%sd%dE\033(s%ldW", cnv_buffer,
            (unsigned int)VisChar((char)c), total + 16);
      EMITB(4, "\4\0\016\1");
    }
  /*    EMITC((char)(Landscape==_TRUE)); */
  EMITC((char)0);
  EMITC((char)0);
#ifdef USEPXL
  EMITWORD(-ce->xOffset);
  EMITWORD(ce->yOffset);
  EMITWORD(ce->width);
  EMITWORD(ce->height);
#else
  EMITWORD(-x_offset);
  EMITWORD(num_rows-y_offset);
  EMITWORD(num_cols);
  EMITWORD(num_rows);
#endif
  EMITWORD((int)ce->cw * 4);
#endif

#ifdef LJ4
  /* Now output compressed or uncompressed */
  if (CChar_Off >= 0) {
    EMITL(CChar_Off,buffin); /* Could compress character into buffer */
  }
  else /* Couldn't compress character - output literally */
#endif

    {
#ifdef USEPXL
      if (fontptr->id == pk89)
        PkRaster(ce, 0);
      else if (fontptr->id == id1002)
        for (i = 0; i < (int)ce->height; i++) {
          sl = ((unsigned char *)(ce->where.address.pixptr) + i * nbpl);
          EMITL(nbpl, (char *)sl);
        }
      else if (fontptr->id == id1001)
        for (i = 0; i < (int)ce->height; i++) {
          sl = (unsigned char *)(ce->where.address.pixptr + i * nwpl);
          EMITL(nbpl, (char *)sl);
        }
#else
      for (i = num_rows; i > 0; i--) {
        EMITL (nbpl, bits + (i-1) * nbpl);
      }
#endif
    }

#ifdef IBM3812
#ifdef USEPXL
  used_fontstorage += (long4)ce->height * ((ce->width + 15) >> 4) * 2 + 14;
#else
  used_fontstorage += (long4)num_rows * ((num_cols + 15) >> 4) * 2 + 14;
#endif
#endif
#ifdef LJ
#ifdef USEPXL
  used_fontstorage += 64 * (((int)((ce->height * ce->width) - 1) / 64) + 1);
#else
  used_fontstorage += 64 * ((((num_rows * num_cols) - 1) / 64) + 1);
#endif
#endif
  fontptr->ncdl += 1;
  G_ncdl += 1;
}

/*-->PkRaster*/
/*********************************************************************/
/**************************** PkRaster *******************************/
/*********************************************************************/

#ifdef USEPXL
unsigned char getnyb (
#if NeedFunctionPrototypes
                      void
#endif
);

long4 pk_packed_num (
#if NeedFunctionPrototypes
                      void
#endif
);

#define  PKBYTE   *pkloc; pkloc ++
#define  OUTCHAR(c) raster_line_buf[bp]= (unsigned char)c; bp++

unsigned char   bitweight, inputbyte;
unsigned char   dyn_f;
unsigned char   *pkloc;
int     repeatcount;

void             /* <Read and translate raster description@>*/
#if NeedFunctionPrototypes
PkRaster(struct char_entry *ce, int raster)
#else
PkRaster(ce, raster)
struct char_entry *ce;
int raster;
#endif
{
  int     rp;
  int     current_line;
  int     wordwidth;
  bool turnon;
  unsigned short  nbpl;
  long4    rowsleft, word, wordweight, hbit, count, i, j, tl;
  long4    row[101];
  unsigned char   raster_line_buf[BYTES_PER_PIXEL_LINE];
  unsigned short  bp;


  if (ce->charsize == HUGE_SIZE)
    Fatal( "cannot process currently PK font patterns of that size!\n");


  current_line = 0;
  pkloc = (unsigned char *)ce->where.address.pixptr;
  dyn_f = (unsigned char)(ce->flag_byte >> 4);
  turnon = (bool)((ce->flag_byte & 8) == 8);
  wordwidth = (int)(ce->width + 31) >> 5;
  nbpl = ((int)(ce->width) +  7) >> 3;

  bitweight = 0;
  if (dyn_f == 14) {
    /*printf("<Get raster by bits@>\n");*/
    for (i = 1; i <= (long4)ce->height; i++) {
      word = 0;
      wordweight = 31;
      bp = 0;            /* Sowa */

#ifdef DRAWGLYPH
      printf("     |");
#endif
      for (j = 1; j <= (long4)ce->width; j++) {
        bool getbit;
        /* bp = 0;               SOWA */
        /*******************************************begin Getbit *********/
        bitweight /= 2;
        if ( bitweight == 0 ) {
          inputbyte = PKBYTE;
          bitweight = 128;
        }
        getbit = (bool)
          ( inputbyte >= bitweight );
        if ( getbit )
          inputbyte -= bitweight;
        /*********************************************end Getbit *********/

        if (getbit)
          word += power[wordweight];

        wordweight --;
        if (wordweight == -1) {

#ifdef DRAWGLYPH
          { int k;
          for (k = 31; k>=0; k--) {
            if ((power[k] & word)!=0) printf("M");
            else printf(".");
          }
          }
#endif

          OUTCHAR((word >> 24 & 0xFF));
          OUTCHAR((word >> 16 & 0xFF));
          OUTCHAR((word >> 8 & 0xFF));
          OUTCHAR((word    & 0xFF));

          word = 0;
          wordweight = 31;
        }
      }
      if (wordweight < 31) {
#ifdef COMMENT
# ifdef DRAWGLYPH
        {
          int k;
          for (k = 15; k>=0; k--) {
            if ((power[k] & word)!=0) printf("Z");
            else printf(":");
          }
        }
        printf("|\n ----|");
# endif
#endif

        for (j = 3; j >= (wordwidth * 4 - (long4)nbpl); j--) {
          OUTCHAR(((word >> (j << 3)) & 0xff));
#ifdef DRAWGLYPH
          {
            int k;
            for (k = 7; k>=0; k--) {
              if ((power[k] & ((word >> (j << 3)) & 0xff))!=0) printf("M");
              else printf(".");
            }
          }
#endif
        }

      }

      switch (raster) {
      case 1:
        RasterLine(ce, nbpl, current_line, raster_line_buf);
        current_line++;
        break;
#ifdef LJ4
      case 2:
        CompressedCharLine(ce,(unsigned int)nbpl,raster_line_buf);
        break;
#endif
      default:
        EMITL(bp, (char *)raster_line_buf);
      }

#ifdef DRAWGLYPH
      printf("|\n");
#endif
    }
  } else {
    /* fprintf(ERR_STREAM, "@<Create normally packed raster@>\n"); */
    rowsleft = (long4)ce->height;
    hbit = (long4)ce->width;
    repeatcount = 0;
    wordweight = 32;
    word = 0;
    rp = 1;
    while ( rowsleft > 0 ) {
      count = pk_packed_num();
      bp = 0;

      while (count > 0) {
        if ((count < wordweight) && (count < hbit)) {
          if (turnon)
            word +=
              gpower[wordweight] -
              gpower[wordweight - count];

          hbit -= count;
          wordweight -= count;
          count = 0;
        } else if ((count >= hbit) && (hbit <=
                                       wordweight)) {

          if (turnon)
            word +=
              gpower[wordweight] -
              gpower[wordweight - hbit];

          row[rp] = word;

          /*fprintf(ERR_STREAM, " @<Send row@> \n");*/
          for (i = 0; i <= (long4)repeatcount; i++) { int ii;

#ifdef DRAWGLYPH
          printf("***  |");
#endif
          for (ii = 1; ii < wordwidth; ii++) {
            tl = row[ii];

            OUTCHAR((tl >> 24 & 0xFF));
            OUTCHAR((tl >> 16 & 0xFF));
            OUTCHAR((tl >> 8  & 0xFF));
            OUTCHAR((tl       & 0xFF));

#ifdef DRAWGLYPH
            {
              int k;
              for (k = 31; k>=0; k--) {
                if ((power[k] & row[ii])!=0) printf("M");
                else printf(".");
              }
            }
#endif
          }
          tl = row[wordwidth];
          for (j = 3; j >= (wordwidth *4 - (long4)nbpl); j--) {
            OUTCHAR(((tl >> (j << 3)) & 0xff));
#ifdef DRAWGLYPH
            {
              int k;
              for (k = 7; k>=0; k--) {
                if ((power[k] & ((tl >> (j << 3)) & 0xff))!=0) printf("M");
                else printf(".");
              }
            }
#endif
          }

          switch (raster) {
          case 1:
            RasterLine(ce, (unsigned int)nbpl, current_line, raster_line_buf);
            current_line++;
            break;
#ifdef LJ4
          case 2:
            CompressedCharLine(ce,(unsigned int)nbpl,raster_line_buf);
            break;
#endif
          default:
            EMITL(bp, (char *)raster_line_buf);
          }

          bp = 0;

#ifdef DRAWGLYPH
          printf("|  ");
          for (j = 1; j <= (long4)wordwidth; j++) printf("%02lX/",row[j]);
          printf(" raster=%d\n",raster);
#endif
          }

          rowsleft -=  (long4)repeatcount + 1;
          repeatcount = 0;
          rp = 1;
          word = 0;
          wordweight = 32;
          count -= hbit;
          hbit = (long4)ce->width;
        } else {
          if (turnon) word += gpower[wordweight];
          row[rp] = word;
          rp = rp + 1;
          word = 0;
          count -= wordweight;
          hbit -= wordweight;
          wordweight = 32;
        }
      }   /* .....while count > 0 */
      if (turnon)
        turnon = _FALSE;
      else
        turnon = _TRUE;
    } /* ...... rowsleft > 0 */
    if ((rowsleft != 0) || (hbit != (long4)ce->width))
      Fatal("Bad pk file----more bits than required!\n");
  } /* .... create normally packed raster */
}

unsigned char getnyb(
#if NeedFunctionPrototypes
                      void
#endif
                      )
{
  register unsigned char  temp;
  if ( bitweight == 0 ) {
    inputbyte = PKBYTE;
    bitweight = 16;
  }
  temp = inputbyte / bitweight;
  inputbyte -= temp * bitweight;
  bitweight /= 16;
  return ( temp );
}


long4 pk_packed_num(
#if NeedFunctionPrototypes
                     void
#endif
                     )
{ /*@<Packed number procedure@>= */
  register int    i;
  long4    j;

  i = (int)getnyb();
  if (i == 0) {
    do {
      j = (long4)getnyb();
      i++;
    } while (j == 0);
    while (i > 0) {
      j = j * 16 + (long4)getnyb();
      i--;
    };
    return (j - 15 + (13 - dyn_f) * 16 + dyn_f);
  } else if (i <= (int)dyn_f) {
    return ((long4)i);
  } else if (i < 14) {
    return ((i-(long4)dyn_f - 1) * 16 + (long4)getnyb() + dyn_f + 1);
  } else {
    if (i == 14) {
      repeatcount = (int)pk_packed_num();
    } else {
      repeatcount = 1;
    }
    /*     fprintf(ERR_STREAM,"repeatcount = [%d]\n",repeatcount);    */
    return (pk_packed_num());    /* tail end recursion !! */
  }
}
#endif

#ifndef USEPXL
void
#if NeedFunctionPrototypes
bad_gf(int n)
#else
bad_gf(int n)
int n;
#endif
{
  Fatal("Bad gf file, case %d\n",n);      /* See gf.c */
}
#endif


#ifdef LJ4
/* Compress a raster line in compression mode 2 */
int
#if NeedFunctionPrototypes
CompressLine2(unsigned char *buffer, unsigned char *buffout, int emitbytes)
#else
CompressLine2(buffer, buffout, emitbytes)
unsigned char *buffer;
unsigned char *buffout;
int emitbytes;
#endif
{
  unsigned char *pos,*ppos,*litpos,*upper;
  int lit,i,pack;
  char last,c;

  /* trap empty lines (otherwise problems with Packbits) */
  if (emitbytes == 0)
    return(0);
  /* Use Packbits compression (mode 2) on raster line */
  pos = buffer;
  litpos = buffer;
  pack = 1;
  ppos = buffout;
  last = *pos++;
  upper = buffer + emitbytes;
  while (pos < upper) {
    c = *pos++;
    if (c == last) {
      pack++;
      /* At least three equal bytes ==> write out preceding literal sequence */
      if ((pack == 3) && ((lit = (int)(pos - litpos - 3)) != 0)) {
        while (lit >= 128) {
          *ppos++ = 127;
          for (i = 1; i<=128; i++)
            *ppos++ = *litpos++;
          lit -= 128;
        }
        if (lit != 0) {
          *ppos++ = lit-1;
          while ((lit--) > 0)
            *ppos++ = *litpos++;
          /* litpos is now pos-3 (i.e. first of the sequence) */
        }
      }
    }
    else {
      while (pack >= 128) {
        *ppos++ = 129;
        *ppos++ = last;
        litpos += 128;
        pack -= 128;
      }
      /* At least 3 equal bytes or 2 that don't break a literal sequence
         ==> write out packed sequence */
      if ((pack >= 3) || ((pack == 2) && (litpos == pos-3))) {
        *ppos++ = 257 - pack;
        *ppos++ = last;
        litpos += pack;
      }
      pack = 1;
      last = c;
    }
    if (ppos > (buffout + BUFFSIZE/2 - 129)) {
      fprintf(ERR_STREAM,
              "Can't compact raster character; rerun without compression!\n");
      return(0);
    }
  }

  while (pack >= 128) {
    *ppos++ = 129;
    *ppos++ = last;
    litpos += 128;
    pack -= 128;
  }
  if ((pack >= 3) || ((pack == 2) && (litpos == pos-3))) {
    *ppos++ = 257 - pack;
    *ppos++ = last;
    litpos += pack;
  }
  else if ((lit = (int)(pos - litpos)) != 0) {
    while (lit >= 128) {
      *ppos++ = 127;
      for (i = 1; i<=128; i++)
        *ppos++ = *litpos++;
      lit -= 128;
    }
    if (lit != 0) {
      *ppos++ = lit-1;
      while ((lit--) > 0)
        *ppos++ = *litpos++;
    }
  }
  return((int)(ppos - buffout));
}


/* Compress a raster line in compression mode 3 */
#if NeedFunctionPrototypes
int CompressLine3(unsigned char *buffer, unsigned char *buffout, int emitbytes)
#else
int CompressLine3(buffer, buffout, emitbytes)
unsigned char *buffer;
unsigned char *buffout;
int emitbytes;
#endif
{
  unsigned char *pos,*ppos,*litpos,*upper,*prev;
  int lit,i,pack;

  /* Use compression mode 3 */
  pos = buffer;
  ppos = buffout;
  upper = buffer + emitbytes;
  prev = PrevLine;
  while(pos < upper) {
    litpos = pos;
    while ((*prev == *pos) && (pos < upper)) {
      prev++;
      pos++;
    }
    if (pos < upper) {
      pack = (int)(pos - litpos);
      litpos = pos;
      i = upper - pos;
      if (i > 8)
        i = 8;
      while ((*pos != *prev) && (i > 0)) {
        *prev++ = *pos++;
        i--;
      }
      i = (int)(pos - litpos - 1);
      lit = i<<5;
      if (pack < 31) {
        *ppos++ = lit + pack;
      }
      else {
        *ppos++ = lit + 31;
        pack -= 31;
        while (pack >= 255) {
          *ppos++ = 255;
          pack -= 255;
        }
        *ppos++ = pack;
      }
      while (i >= 0) {
        *ppos++ = *litpos++;
        i--;
      }
    }
    if (ppos > (buffout + BUFFSIZE/2 - 16)) {
      fprintf(ERR_STREAM,
              "Can't compact raster character; rerun without compression!\n");
      return(0);
    }
  }
  return((int)(ppos - buffout));
}
#endif

/*-->RasterLine*/
/**********************************************************************/
/****************************  RasterLine  ****************************/
/**********************************************************************/
void
#if NeedFunctionPrototypes
RasterLine(struct char_entry *ce, unsigned int nbpl,
           unsigned int current_line, unsigned char *buffer)
#else
RasterLine(ce, nbpl, current_line, buffer)
struct char_entry *ce;
unsigned short  nbpl, current_line;
char *buffer;
#endif
{
#ifdef IBM3812
  long   total;
  static unsigned short   maxlines;

  if (current_line == 0) {
# ifdef USEPXL
    maxlines = ce->height;

    MoveVert(-ce->yOffset);      /* move cursor up */
    MoveHor(-ce->xOffset);       /* move cursor right */
# else
    maxlines = num_rows;

    MoveVert(- (num_rows-y_offset) );      /* move cursor up */
    MoveHor(-x_offset);       /* move cursor right */
# endif
    last_rx = last_ry = UNKNOWN;       /* next time full positioning */
  }

  if (current_line % maxlines == 0) {
    if (current_line > 0) {    /* maxlines lines have been printed*/
      MoveVert(maxlines);   /*   move cursor down     */
      last_rx = last_ry = UNKNOWN;    /* next time full positioning */
    }
# ifdef USEPXL
    total = (long)(ce->height - current_line) * (long4)nbpl;
# else
    total = (long)(num_rows - current_line) * (long4)nbpl;
# endif
    if ((total + 9) > 65535) {
      maxlines = (unsigned short)((65535 - 9) / nbpl);
      total = (long)maxlines * (long)nbpl;
    }

    PMPcont(total + 9);
    PMPout(2, "\365\0");
    EMITWORD(maxlines);
# ifdef USEPXL
    EMITWORD(ce->width);
# else
    EMITWORD(num_cols);
# endif
    PMPoutC((unsigned char) (total >> 16) & 0xFF);
    PMPoutC((unsigned char) (total >> 8 ) & 0xFF);
    PMPoutC((unsigned char)  total     & 0xFF);
  }
  EMITL((int)nbpl, (char *)buffer);
#endif /* IBM3812 */


#ifdef LJ
  register int emitbytes;
#ifdef LJ4
  int i;
#endif

  for (emitbytes = (int)nbpl;
       (*(buffer + emitbytes - 1) == '\0') && (emitbytes > 0);
       emitbytes--);
# ifdef LJ4
  switch (CompressCharMode) {
  case 0:
    EMIT2("\033*b%dW", emitbytes);
    EMITL(emitbytes, buffer);
    break;

  case 2:
    i = CompressLine2(buffer,buffin,emitbytes);
    EMIT2("\033*b%dW", i);
    EMITL(i,buffin);
    break;

  case 3:
    i = CompressLine3(buffer,buffin + BUFFSIZE/2,(int)nbpl);
    EMIT2("\033*b%dW", i);
    EMITL(i,buffin + BUFFSIZE/2);
    break;

  default:
    fprintf(ERR_STREAM,"Unsupported compression mode!\n");
  }
# else
  EMIT2("\033*b%dW", emitbytes);
  EMITL(emitbytes, buffer);
# endif /* LJ4 */
#endif /* LJ */
}


/*-->RasterChar*/
/**********************************************************************/
/****************************  RasterChar  ****************************/
/**********************************************************************/
void                     /* raster a character bitmap */
#if NeedFunctionPrototypes
RasterChar(struct char_entry *ce)
#else
RasterChar(ce)
struct char_entry *ce;
#endif
{
  int      i;
  register unsigned char  *sl;
  unsigned short  nbpl, nwpl;
  unsigned char   raster_line_buf[BYTES_PER_PIXEL_LINE];

#ifdef DEBUG
  if (Debug)
    fprintf(ERR_STREAM,"Raster character ...size=%d \n", (int)ce->charsize);
#endif

#ifdef USEPXL
  if (fontptr->id == pk89) {
    nwpl = 0; /* initialize variable */
    nbpl = ((int)(ce->width) +  7) >> 3;
  } else if (fontptr->id == id1002) {
    nwpl = 0; /* initialize variable */
    nbpl = ((int)ce->width +  7) >> 3;
  } else if (fontptr->id == id1001) {
    nwpl = ((int)ce->width + 31) >> 5;
    nbpl = ((int)ce->width + 7) >> 3;
  } else {
    /* should never be necessary */
    nwpl = 0;
    nbpl = 0;
  }
#else
  nbpl = (num_cols + 7) >> 3;
#endif

#ifdef LJ
# ifdef LJ4
  CompressCharMode = (ce->width < CompressCharWidth) ? 0 : UseCompression;
  EMIT3("\033*t%dR\033*r1A\033*b%dM",RESOLUTION,CompressCharMode);
  if (CompressCharMode == 3) {
    /* Check if PrevLine big enough; claim more space if not */
    if (((int)nbpl) > PrevSize) {
      if (PrevLine != NULL)
        free(PrevLine);
      if ((PrevLine = (unsigned char *)malloc(nbpl*sizeof(char))) == NULL) {
        PrevSize = 0;
        Fatal("RasterChar: out of memory!\n");
      }
      PrevSize = (int)nbpl;
    }
    /* Clear previous line */
    sl = PrevLine;
    for (i = 0; i<nbpl; i++)
      *sl++ = 0;
  }
# else
  EMIT2("\033*t%dR\033*r1A\033*b0M",RESOLUTION);
# endif /* LJ4 */
#endif
  { /* read pixel from file */
    if ((ce->charsize == HUGE_SIZE) && (fontptr->id != pk89))
      OpenFontFile();
#ifdef USEPXL
    FSEEK(pxlfp, ce->where.address.fileOffset, SEEK_SET);
#else
    FSEEK(gfin, ce->where.address.fileOffset, SEEK_SET);
    gettochar();
    readbits();
#endif /* USEPXL */
  }

#ifdef USEPXL
  if (fontptr->id == pk89)
    PkRaster(ce, 1);
  else if (fontptr->id == id1002) {
    for (i = 0; i < (int)ce->height; i++) {
      if (ce->charsize == HUGE_SIZE) {
        fread(raster_line_buf, 1, (int)nbpl, pxlfp);
        sl = raster_line_buf;
      } else
        sl = ((unsigned char *)(ce->where.address.pixptr)
              + i * nbpl);
      RasterLine(ce, (unsigned int)nbpl, i, sl);
    }
  } else if (fontptr->id == id1001) {
    long filediff;
    filediff = (long)nwpl * 4 - nbpl;
    for (i = 0; i < (int)ce->height; i++) {
      if (ce->charsize == HUGE_SIZE) {
        read_multi(raster_line_buf, 1, (int)nbpl, pxlfp);
        /* skip fill bytes */
        FSEEK(pxlfp, filediff, SEEK_CUR);
        sl = raster_line_buf;
      } else
        sl = (unsigned char *)(ce->where.address.pixptr + i * nwpl);
      RasterLine(ce, (unsigned int)nbpl, i, sl);
    }
  }
#else
  for (i = num_rows; i > 0; i--)
    RasterLine(ce, (unsigned int)nbpl, i, bits + (i-1) * nbpl);
#endif
#ifdef LJ
  EMIT1("\033*rB");
#endif
  last_rx = last_ry = UNKNOWN;
}

/*-->LoadAChar*/
/**********************************************************************/
/***************************** LoadAChar ******************************/
/**********************************************************************/
void
#if NeedFunctionPrototypes
LoadAChar(long4 c, register struct char_entry *ptr)
#else
LoadAChar(c, ptr)
long4    c;
register struct char_entry *ptr;
#endif
{
  long4    *pr;
  long     bytes;

  if (ptr->where.address.fileOffset == NONEXISTANT
#ifdef LJ_RESIDENT_FONTS
      || fontptr->resident_p
#endif
      ) {
    ptr->where.isloaded = _FALSE;
    return;
  }

  OpenFontFile();

#ifdef DEBUG
  if (Debug)
    fprintf(ERR_STREAM, "LoadAChar: <%c>(%ld) from file at pos %ld\n",
            (char)c,(long)c,(long)ptr->where.address.fileOffset);
#endif

#ifdef USEPXL

  FSEEK(pxlfp, ptr->where.address.fileOffset, SEEK_SET);

  if (fontptr->id == pk89) {
#ifdef PARANOIA
    unsigned char   temp;
    temp = (unsigned char) NoSignExtend(pxlfp, 1);

    if ((int)(ptr->flag_byte) != (int)temp) {
      fprintf(ERR_STREAM,"font=%lx, ptr=%lx\n",fontptr,ptr);
      Fatal("%d: oh boy! old flag %d, new flag %d, ptr=%lx\n",
            (int)c,(int)(ptr->flag_byte),(int)temp,ptr);
    }
#endif

    if ((ptr->flag_byte & 7) == 7) {
      bytes = NoSignExtend(pxlfp, 4) - 28;
      FSEEK(pxlfp, ptr->where.address.fileOffset + 36, SEEK_SET);
      /*
        fprintf(ERR_STREAM,"bytes=%d, seeking at %ld\n",
        bytes, ptr->where.address.fileOffset + 36);
        */
    } else if ((ptr->flag_byte & 4) == 4) {
      bytes = ((long4)ptr->flag_byte & 3) * 65536l + NoSignExtend(pxlfp, 2) - 13;
      FSEEK(pxlfp, ptr->where.address.fileOffset + 16, SEEK_SET);
    } else {
      bytes = ((long4)ptr->flag_byte & 3) * 256 + NoSignExtend(pxlfp, 1) - 8;
      FSEEK(pxlfp, ptr->where.address.fileOffset + 10, SEEK_SET);
    }
  } else if (fontptr->id == id1002)
    bytes =  ((( (long4)ptr->width + 7) >> 3) * (long4)ptr->height);
  else if (fontptr->id == id1001)
    bytes =  4 * (((long4)ptr->width + 31) >> 5) * (long4)ptr->height;
  else
    bytes = 0;

  if (bytes > 0) {
    /* do NOT load Huge characters */
    if ((bytes > HUGE_CHAR_PATTERN) && (fontptr->id != pk89)) {
      qfprintf(ERR_STREAM,"Huge Character <%c> (%ld Bytes)\n",
               (char)c, bytes);
      ptr->charsize = HUGE_SIZE;
      ptr->where.isloaded = _FALSE;
    } else {
      if ( (pr = (long4 *)malloc( bytes )) == NULL )
        Fatal("Unable to allocate %ld bytes for char <%c>\n", bytes, (char)c);
      /*
       * else fprintf(ERR_STREAM,"allocating %ld bytes char <%c>(%d)\t at 0x%lx\n",
       *                      bytes, (char)c,(int)c,pr);
       */
#ifdef DEBUG
      if (Debug)
        fprintf(ERR_STREAM,
                "Allocating Char <%c>, FileOffset=%lX, Bytes=%ld (%d) <%d>\n",
                (char)c, ptr->where.address.fileOffset, bytes,
                (int)bytes, (unsigned int)bytes);
#endif
      allocated_storage += bytes;
      read_multi(pr, 1, (int)bytes , pxlfp);
      ptr->where.address.pixptr = pr;
    }
  }
#else
  FSEEK(gfin, ptr->where.address.fileOffset, SEEK_SET);
  gettochar();
  readbits();
  if (num_bytes > HUGE_CHAR_PATTERN)
    ptr->charsize = HUGE_SIZE;
#endif
  ptr->where.isloaded = _TRUE;
  if (ptr->charsize != SMALL_SIZE
#ifdef LJ
      /* we might have problems at the edge of the paper with diff. sized characters
       * the correct treatment would be to check whether the bounding box of
       * tfontptr is within the paper relative to the current position
       */
      || fontptr->max_height > CHAR_HEIGTH_LARGE
      || (rasterfont[fontptr->plusid])
#endif
      )
    return;

  EmitChar(c, ptr);
#ifdef USEPXL
  /* we should really free the space used by the PXL data after this
     point, but it is not large, and besides, we may want to be
     more clever in the future, about sending bitmaps.  So keep
     the data around */
#endif
}

/*-->SetChar*/
/**********************************************************************/
/*****************************  SetChar  ******************************/
/**********************************************************************/
void
#if NeedFunctionPrototypes
SetChar(long4 c, short command, int PassNo, bool do_posn, bool in_string)
#else
SetChar(c, command, PassNo, do_posn,in_string)
long4    c;
short   command;
int     PassNo;
bool do_posn,in_string;
#endif
{
  register struct char_entry *ptr;  /* temporary char_entry pointer */
  bool pos_after = _FALSE;

  ptr = &(fontptr->ch[c]);
  if (!((ptr->where.isloaded) || (ptr->charsize == HUGE_SIZE)))
    LoadAChar(c, ptr);
  if (PassNo == 0)
    return;

  if (do_posn) {
#ifdef IBM3812
    if (CharStringPos>0) {
      fprintf(ERR_STREAM,"!!!! That should never happen!!!\n");
      CharStringOut;
    }
#endif
    SetPosn(h, v);
  }

  /*
    fprintf(ERR_STREAM,
            "(%d) hh=%ld (+%ld/+%ld), h=%ld, xh=%ld,xhh=%ld, [%ld|%ld] ->%d\n",
            (int)do_posn,hh,(long4)ptr->cw,(long4)ptr->cw*(long4)hconv,h,
            (long)PIXROUND(h, hconv),
            (long)PIXROUND(hh, hconv),
            (long)labs((hh-h)),(long)hconv,
            (labs((hh-h))>hconv)
            );
            */

  if (in_string && (labs((hh-h))>hconv)) {
#ifdef IBM3812
    CharStringOut;
#endif
    SetPosn(h, v);
  }

  /*
    fprintf(ERR_STREAM,"raster?=%d - last_ry=%d, last_rx=%d,mmax-height=%d\n",
    (int)last_ry < fontptr->max_height, (int)last_ry,(int)last_rx,
    (int)fontptr->max_height);
    */

  if (fontptr->font_file_id != NO_FILE) {      /* ignore missing fonts */
    if (
#ifdef LJ_RESIDENT_FONTS
        !fontptr->resident_p &&
#endif
        (ptr->charsize != SMALL_SIZE
#ifdef LJ
         /* the LaserJet cannot print characters
          * where the bounding box lies outside the
          * paper edge. Missing: right paper edge
          */
         || last_ry < (int)fontptr->max_height
         || fontptr->max_height > CHAR_HEIGTH_LARGE
         || (rasterfont[fontptr->plusid])
         || (brother_mode && c == 0)
#ifdef SEVENBIT
         || (kyocera_mode && c == 32)
#endif
#endif
         )) {
#ifdef LJ
      int     tmp;
      char    sign;

      if (!do_posn)
        SetPosn(h, v);

#ifdef USEPXL
      tmp = (int)-ptr->yOffset;
#else
      tmp = (int)num_rows-y_offset;
#endif
      if (tmp != 0) {
        if (tmp < 0) {
          sign = '-';
          tmp = -tmp;
        } else
          sign = '+';
        EMIT3("\033*p%c%dY", sign, tmp);
      }
#ifdef USEPXL
      tmp = (int)-ptr->xOffset;
#else
      tmp = (int)-x_offset;
#endif
      if (tmp != 0) {
        if (tmp < 0) {
          sign = '-';
          tmp = -tmp;
        } else
          sign = '+';
        EMIT3("\033*p%c%dX", sign, tmp);
      }
#endif
#ifdef IBM3812
      CharStringOut;
#endif
#ifdef DEBUG
      if (Debug)
#ifndef vms
        fprintf(ERR_STREAM,"Raster character <%c> %hd\n", (char) c,(short)c);
#else
      fprintf(ERR_STREAM,"Raster character <%c> %d\n", (char) c,(short)c);
#endif
#endif
      RasterChar(ptr);
      pos_after = _TRUE;
    } else {
      unsigned char cc;
      cc = VisChar((char)c);
#ifdef IBM3812
#ifdef USEPXL
      if ( ptr->yyOffset || (!in_string) ) {
        CharStringOut;
        MoveVert(ptr->yyOffset);
        sprintf(PMPformat, "\01%c", cc);
        PMPout(2, PMPformat);
        MoveVert((int)-(ptr->yyOffset));
      } else {
#endif
        if (CharStringPos==CHARSTRINGMAX)
          CharStringOut;

        CharString[CharStringPos] = cc;
        CharStringPos++;
#ifdef USEPXL
      }
#endif
#endif
#ifdef LJ
#define TRANSPARENTCHAR(ch) \
      if ((ch == 0l) || (ch >= 7l && ch <= 15l) || (ch == 27l)) \
          EMIT2("\033&p1X%c", (unsigned char)ch); \
      else { EMITC((unsigned char)ch); }
#ifdef USEPXL
      if (ptr->yyOffset) {
#ifndef vms
        EMIT2("\033*p+%hdY", ptr->yyOffset);
        TRANSPARENTCHAR(cc);
        EMIT2("\033*p-%hdY", ptr->yyOffset);     /* GUGUGU 255 */
#else
        EMIT2("\033*p+%dY", ptr->yyOffset);
        TRANSPARENTCHAR(cc);
        EMIT2("\033*p-%dY", ptr->yyOffset);     /* GUGUGU 255 */
#endif
      } else
#endif
        /*                EMITC( (unsigned char)c);*/
        { TRANSPARENTCHAR(cc);}
#endif
    }
    /*
    fprintf(stderr,"--> hh(%ld) += cw(%ld) * hconv(%ld)",
            (long)hh, (long)ptr->cw, (long) hconv);
            */
#ifdef LJ
    /* the guessed position must be a multiple of pixels */
    if (RESOLUTION == 300)
      hh += (long4) ((ptr->cw)/4)*4*hconv;
    else /* RESOLUTION == 600 */
      hh += (long4) ((ptr->cw)/2)*2*hconv;
#else
    hh += (long4)(ptr->cw * hconv);
#endif
    /*
      fprintf(stderr," = hh(%ld)\n",(long)hh);
      */
  }

  if (command <= SET4)
    h += ptr->tfmw;

  if (pos_after)
    SetPosn(h, v);
  else
    last_rx = (int)PIXROUND(h, hconv) + x_goffset;
}

#if NeedFunctionPrototypes
void DoBop(void)
#else
void DoBop()
#endif
{
  struct font_entry *p;
#ifdef LJ
  register short i;
  if (fonts_used_on_this_page > MAX_FONTS_PER_PAGE) {
    for (i = 0; i < HANDLE_MAX_FONTS; i++)
      rasterfont[i] = _FALSE;
  }
  fonts_used_on_this_page = 0;
#endif
  for (p = hfontptr; p; p = p->next)
    p->used_on_this_page = _FALSE;
}

/*-->SetString*/
/**********************************************************************/
/*****************************  SetString  ****************************/
/**********************************************************************/
void
#if NeedFunctionPrototypes
SetString(short firstch, int PassNo)
#else
SetString(firstch, PassNo)    /* read and set a consecutive string of chars */
short   firstch;
int     PassNo;
#endif
{
  short   c;
  register unsigned short i;

#ifdef DEBUG
  if (Debug)
    fprintf(ERR_STREAM, "SetString ");
#endif
  for (i = 0, c = firstch; c >= SETC_000 && c <= SETC_127; i++) {
#ifdef DEBUG
    if (Debug)
      fprintf(ERR_STREAM, "%d(%c) ", c, c);
#endif
    SetChar((long4)c, c, PassNo, (bool)(i==0), _TRUE);
    c = (short)NoSignExtend(dvifp, 1);
  }
  FSEEK(dvifp, -1l, SEEK_CUR);    /* backup one character */
#ifdef IBM3812
  CharStringOut;
#endif
#ifdef DEBUG
  if (Debug)
    fprintf(ERR_STREAM, "...SetString\n");
#endif
}

/*-->SetPosn*/
/**********************************************************************/
/*****************************  SetPosn  ******************************/
/**********************************************************************/
void                  /* output a positioning command */
#if NeedFunctionPrototypes
SetPosn(long4 x, long4 y)
#else
SetPosn(x, y)
long4    x, y;
#endif
{
  int     rx, ry;
  rx = (int)PIXROUND(x, hconv) + x_goffset;
  ry = (int)PIXROUND(y, vconv) + y_goffset;

  /*
  fprintf(ERR_STREAM,
	  "setposn to %ld/%ld, %d/%d, last: %d/%d\n",
	  (long)x,(long)y,
	  rx,ry,
	  last_rx,last_ry
      );
      */

#ifdef IBM3812
  PMPcont(3);
  PMPoutC('\340');
  EMITWORD(LARGER(rx,0));

  if (last_ry != ry) { /* necessary to set new y-position */
    PMPcont(3);
    PMPoutC('\341');
    EMITWORD(LARGER(ry,0));
  }
#endif
#ifdef LJ
#if 0
/* this optimization doesn't work, as last_XX is set to the
   starting(!) position of the last string not to the end position! */

  if (last_rx != rx || last_ry != ry) {
    if (last_ry == ry)   /* not necessary to set new y-position */
      EMIT2("\033*p%dX", LARGER(rx,0));
    else if (last_rx == rx)
      EMIT2("\033*p%dY", LARGER(ry,0));
    else
      EMIT3("\033*p%dx%dY", LARGER(rx,0), LARGER(ry,0));
  }
#endif
  if (last_ry == ry)   /* not necessary to set new y-position */
    EMIT2("\033*p%dX", LARGER(rx,0));
  else
    EMIT3("\033*p%dx%dY", LARGER(rx,0), LARGER(ry,0));
#endif

  last_ry = ry;    /* last y-position on output device */
  last_rx = rx;    /* last x-position on output device */
  /*
   * must know where device "really" is horizontally, for rel. posning.
   * (maybe in the future), but we always use direct positioning for
   * vertical movement.
   */
  /* hh = rx * hconv; */
  hh = x;
  vv = y;
  /*
   * fprintf(ERR_STREAM,"DoPosn: x=%ld, y=%ld, rx=%d, ry=%d, hh=%ld, vv=%ld\n",
   *         (long)x,(long)y,rx,ry,(long)hh,(long)vv);
   */
}



#ifdef LJ4
/* Compresses a rasterline of font data and appends it to buffin (used
   for storage of the compressed character). CChar_Off is the current
   offset in the buffer, CChar_Last is the first byte of the last
   compacted row (line repeat count).  Updates the previous line
   (PrevLine) if necessary. */
void
#if NeedFunctionPrototypes
CompressedCharLine(struct char_entry *ce, int nbpl, unsigned char *buffer)
#else
CompressedCharLine(ce, nbpl, buffer)
struct char_entry *ce;
int nbpl;
unsigned char *buffer;
#endif
{
  if (CChar_Off >= 0) {
    register unsigned char *obuf,*buff;
    unsigned char *prev,*end;
#undef max /* cc thinks any max macro overrides a variable */
    int t,mode,max;
    register int x,y,i;

    prev = PrevLine;
    obuf = buffer;
    end = buffer + nbpl;
    x = 0;
    while (obuf < end) {
      if (*obuf != *prev) {
        *prev = *obuf;
        x = 1;
      }
      obuf++;
      prev++;
    }
    if (x == 0 && CChar_Last >= 0) {
      (buffin[CChar_Last])++;
      return; /* line repeat count +1 */
    }

    end = buffin + BUFFSIZE - 16;
    obuf = buffin + CChar_Off;
    buff = buffer;
    *obuf++ = 0; /* Line repeat count = 0 */
    t = 0;
    CChar_Last = CChar_Off; /* Next line */
    mode = 0;
    y = *buff++;
    i = 7; /* i = current bit */
    while ((t < ce->width) && (obuf < end)) {
      max = ce->width - t; /* maximum pixels left to do */
      x = 0;
      if (mode == 0) {
        /* white run */
        while ((y & (1<<i)) == 0 && x < max) {
          x++;
          i--;
          if (i < 0) {
            i = 7;
            y = *buff++;
            while (y == 0 && x < max) {
              x += 8;
              y = *buff++;
            }
          }
        }
        mode = 1;
      }
      else {
        /* black run */
        while ((y & (1<<i)) != 0 && x < max) {
          x++;
          i--;
          if (i < 0) {
            i = 7;
            y = *buff++;
            while (y == 0xff && x < max) {
              x += 8;
              y = *buff++;
            }
          }
        }
        mode = 0;
      }
      if (x > max)
        x = max;
      t += x;
      /* make precautions for very long runs */
      while (x > 0xff) {
        *obuf++ = 0xff;
        *obuf++ = 0;
        x -= 0xff;
      }
      *obuf++ = x;
    }
    CChar_Off = obuf >= end ? -1 : obuf - buffin;
  }
}
#endif

/*------------------------ end dvichars.c ------------------------------*/


/* Report a warning if both checksums are nonzero, they don't match, and
   the user hasn't turned it off.  */

static void
check_checksum (c1, c2, name)
    unsigned c1, c2;
    const char *name;
{
  if (c1 && c2 && c1 != c2
#ifdef KPATHSEA
      && !kpse_tex_hush ("checksum")
#endif
      ) {
     Warning ("Checksum mismatch in %s", name) ;
   }
}


/*------------------------ begin dviconv.c -----------------------------*/
/*-->ActualFactor*/
/**********************************************************************/
/**************************  ActualFactor  ****************************/
/**********************************************************************/
double  /* compute the actual size factor given the approximation */
#if NeedFunctionPrototypes
ActualFactor(long4 unmodsize)
#else
ActualFactor(unmodsize)
long4    unmodsize;                 /* actually factor * 1000 */
#endif
{
  double  realsize;     /* the actual magnification factor */
  realsize = (double)unmodsize / 1000.0;
  if (abs((int)(unmodsize - 1095l))<2)
    realsize = 1.095445115; /*stephalf*/
  else if (abs((int)(unmodsize - 1315l))<2)
    realsize = 1.31453414; /*stepihalf*/
  else if (abs((int)(unmodsize - 1577l))<2)
    realsize = 1.57744097; /*stepiihalf*/
  else if (abs((int)(unmodsize - 1893l))<2)
    realsize = 1.89292916; /*stepiiihalf*/
  else if (abs((int)(unmodsize - 2074l))<2)
    realsize = 2.0736;   /*stepiv*/
  else if (abs((int)(unmodsize - 2488l))<2)
    realsize = 2.48832;  /*stepv*/
  else if (abs((int)(unmodsize - 2986l))<2)
    realsize = 2.985984; /*stepvi*/
  /* the remaining magnification steps are represented with sufficient
     accuracy already */
  return(realsize);
}


/*-->DecodeArgs*/
/*********************************************************************/
/***************************** DecodeArgs ****************************/
/*********************************************************************/
void
#if NeedFunctionPrototypes
DecodeArgs(int argc, char *argv[])
#else
DecodeArgs(argc, argv)
int     argc;
char    *argv[];
#endif
{
  int     argind;            /* argument index for flags      */
  char    *curarea;	     /* current file area             */
  char    *curname;   	     /* current file name             */
  char    *tcp, *tcp1;       /* temporary character pointers  */
  char    *this_arg;
  double  x_offset = 0.0, y_offset = 0.0;
#ifdef __riscos
  int     ddi;
#endif


#ifndef KPATHSEA
  if ((tcp = getenv("TEXPXL")) != NULL) PXLpath = tcp;
#ifdef LJ_RESIDENT_FONTS
  if ((tcp = getenv("TFMFONTS")) != NULL)
    TFMpath = tcp;
  else if ((tcp = getenv("TEXFONTS")) != NULL)
    TFMpath = tcp;
#endif
#endif

  if (argc == 2 && EQ(argv[1], "--version")) {
    extern KPSEDLL char *kpathsea_version_string;
    puts (VERSION);
    puts (kpathsea_version_string);
    puts ("Copyright (C) 1997 Gustaf Neumann.\n\
There is NO warranty.  You may redistribute this software\n\
under the terms of the GNU General Public License.\n\
For more information about these matters, see the files\n\
named COPYING and dvi2xx.c.\n\
Primary author of Dvi2xx: Gustaf Neumann; -k maintainer: K. Berry.");
    exit (0);
  }

#ifdef LJ4
  /* check if last character is a 6 */
  LJ6 = ('6' == argv[0][strlen(argv[0])-1]);
#endif

  argind = 1;
  while (argind < argc) {
    tcp = argv[argind];
    if (tcp[0] == '-' && tcp[1] != '\0') {
      ++tcp;
      switch (*tcp) {
#ifndef KPATHSEA
      case 'a':       /* a selects different pxl font area */
        PXLpath = ++tcp;
        break;
#endif
      case 'A':
        ManualFeed = _TRUE;
        break;
#ifdef IBM3812
      case 'b':       /* first page from alternate casette */
        FirstAlternate = _TRUE;
        break;
#endif
      case 'c':       /* number of copies to print */
        if ( sscanf(tcp + 1, "%hd", &ncopies) != 1 )
          Fatal("Argument of -c is not a valid integer\n");
        if (ncopies<1) {
          Warning("argument of -c < 1; set to 1!");
          ncopies = 1;
        }
        break;
#ifdef DEBUG
      case '-':       /* --D selects Debug output */
        tcp++;
        if (*tcp == 'D') {
          Debug = _TRUE;
#ifdef KPATHSEA
          sscanf(tcp + 1, "%u", &kpathsea_debug);
#endif
          qfprintf(ERR_STREAM,"Debug output enabled\n");
        }
        break;
#endif
#ifdef LJ2P
      case 'd':       /* d selects DUPLEX mode  */
        tcp++;
        if (*tcp == '1' )
          DuplexMode = 1;
        else if (*tcp == '2')
          DuplexMode = 2;
        else {
          Warning("Invalid DUPLEX mode, assuming DUPLEX=1, Long-Edge Binding");
          DuplexMode = 1;
        }
        break;
#endif
      case 'D':       /* D selects DoublePage  */
        DoublePage = _TRUE;
        tcp++;
        if (*tcp == '1' || *tcp == '2') {
          if (*tcp == '2')
            PrintFirstPart = _FALSE;
          else
            PrintSecondPart = _FALSE;
          tcp++;
        }
        if (*tcp == '-')
          PrintEmptyPages = _FALSE;
        break;
#ifdef LJ4
      case 'E':       /* do not reset printer (go) */
        econoMode = _TRUE;
        break;
#endif
      case 'e':       /* emit file is specified */
        EmitFileName = ++tcp;
#ifdef MSDOS
        /* delete trailing ':' (causing hangup) */
        if (EmitFileName[strlen(EmitFileName)-1] == ':')
          EmitFileName[strlen(EmitFileName)-1] = '\0';
#endif
#ifdef OS2  /* repeated to avoid problems with stupid c preprocessors  */
        /* delete trailing ':' (causing hangup) */
        if (EmitFileName[strlen(EmitFileName)-1] == ':')
          EmitFileName[strlen(EmitFileName)-1] = '\0';
#endif
        break;
      case 'f':       /* next arg is starting pagenumber */
        if ( sscanf(tcp + 1, "%ld", &FirstPage) != 1 )
          Fatal("Argument is not a valid integer\n");
        FirstPageSpecified = _TRUE;
        break;
#ifdef LJ
      case 'g':       /* do not reset printer (go) */
        ResetPrinter = _FALSE;
        break;
#endif
      case 'h':     /* copy header file through to output  */
        HeaderFileName = ++tcp;
        G_header = _TRUE;
        break;
#if defined(LJ2P) || defined(IBM3812)
      case 'l':       /* landscape  */
        Landscape = _TRUE;
        break;
#endif
#ifdef MAKETEXPK
      case 'M':
        /* -M, -M1 => don't make font; -M0 => do.  */
        makeTexPK = *(tcp + 1) == '0';
#ifdef KPATHSEA
        kpse_set_program_enabled (kpse_pk_format, MAKE_TEX_PK_BY_DEFAULT, kpse_src_cmdline);
#endif /* KPATHSEA */
        break;
#endif /* MAKETEXPK */
      case 'x':       /* specify x-offset */
        this_arg = 0;
        if (!(*++tcp)) {
          this_arg = (++argind >= argc ? 0 : argv[argind]);
        } else {
          this_arg = tcp;
        }
        if (!this_arg
            || sscanf(this_arg,"%lf", &x_offset) != 1)
          Fatal("Argument of -x is not a valid floating point number\n");
        break;
      case 'y':       /* specify y-offset */
        this_arg = 0;
        if (!(*++tcp)) {
          this_arg = (++argind >= argc ? 0 : argv[argind]);
        } else {
          this_arg = tcp;
        }
        if (!this_arg || sscanf(this_arg, "%lf", &y_offset) != 1)
          Fatal("Argument of -y is not a valid floating point number\n");
        break;
      case 'X':       /* specify X-origin in dots */
        this_arg = 0;
        if (!(*++tcp)) {
          this_arg = (++argind >= argc ? 0 : argv[argind]);
        } else {
          this_arg = tcp;
        }
        if (!this_arg || sscanf(this_arg,"%hd", &x_origin) != 1)
          Fatal("Argument of -X is not a valid integer\n");
        break;
      case 'Y':       /* specify Y-origin in dots */
        this_arg = 0;
        if (!(*++tcp)) {
          this_arg = (++argind >= argc ? 0 : argv[argind]);
        } else {
          this_arg = tcp;
        }
        if (!this_arg ||
            sscanf(this_arg, "%hd", &y_origin) != 1)
          Fatal("Argument of -Y is not a valid integer\n");
        break;
      case 'm':       /* specify magnification to use */
        switch ( (*++tcp) ) {
        case '#':
          /* next arg is a magnification to use */
          if ( sscanf(tcp + 1, "%ld", &usermag) != 1 )
            Fatal("Argument of mag is not a valid integer\n");
          break;
        case '0':
          usermag = 1000;
          break;
        case 'h':
        case 'H':
          usermag = 1095;
          break;
        case '1':
          usermag = 1200;
          break;
        case 'q':
          usermag = 1250;
          break;
        case '2':
          usermag = 1440;
          break;
        case '3':
          usermag = 1728;
          break;
        case '4':
          usermag = 2074;
          break;
        case '5':
          usermag = 2488;
          break;
        default:
          Fatal("%c is a bad mag step\n", *tcp);
        }
        break;
#ifdef SUPERCOMMENT
      case 'o':     /* PostScript command to send */
        if ( ++argind >= argc )
          Fatal("No argument following -o\n", 0);
        PScmd[nps++] = argv[argind];
        break;
#endif
      case 'p':       /* print n pages  */
        if ( sscanf(tcp + 1, "%ld", &PrintPages) != 1 )
          Fatal("Argument is not a valid integer\n");
        if (PrintPages < 1)
          Fatal("Argument of -p must be greater than 0\n");
        break;
      case 'q':       /* quiet operation */
        G_quiet = _TRUE;
        break;
      case 'r':       /* switch order to process pages */
        Reverse = (bool)(!Reverse);
        break;
#ifdef LJ
      case 's':       /* specify X-origin in dots */
        this_arg = 0;
        if (!(*++tcp)) this_arg = (++argind >= argc ? 0 : argv[argind]);
        else           this_arg = tcp;
        if (!this_arg || sscanf(this_arg,"%hd", &pagesize) != 1)
          Fatal("Argument of -s is not a valid integer\n");
        /*
         * The pgsiz_dots value assumes a resolution of 300dpi. This loses
         * at 600dpi so we will scale them below for the LJ4.
         */
        switch (pagesize) {
        case  1: pgsiz_dots = 10.5 * 300; break;       /* executive */
        case  2: pgsiz_dots = 11 * 300; break;	       /* letter */
        case  3: pgsiz_dots = 14 * 300; break;	       /* legal */
        case  6: pgsiz_dots = 17 * 300; break;	       /* ledger */
        case 25: pgsiz_dots = 210 * 300 / 25.4; break; /* a5 */
        case 26: pgsiz_dots = 297 * 300 / 25.4; break; /* a4 */
        case 27: pgsiz_dots = 420 * 300 / 25.4; break; /* a3 */
        case 45: pgsiz_dots = 257 * 300 / 25.4; break; /* jis b5 */
        case 46: pgsiz_dots = 354 * 300 / 25.4; break; /* jis b4 */
        case 71: pgsiz_dots = 148 * 300 / 25.4; break; /* hagaki postcard */
        case 72: pgsiz_dots = 148 * 300 / 25.4; break; /* oufuku-hagaki */
        case 80: pgsiz_dots = 7.5 * 300; break;        /* monarch envelope */
        case 81: pgsiz_dots = 9.5 * 300; break;        /* com10 envelope */
        case 90: pgsiz_dots = 220 * 300 / 25.4; break; /* int dl */
        case 91: pgsiz_dots = 229 * 300 / 25.4; break; /* int c5 */
        case 100: pgsiz_dots = 250 * 300 / 25.4; break; /* int b5 */
        default: Fatal(
#ifndef vms
                       "%hd is a bad value for pagesize (1,2,3,26,80,81,90,91)",
#else
                       "%d is a bad value for pagesize (1,2,3,26,80,81,90,91)",
#endif
                       pagesize);
        }
        break;
#endif
      case 't':       /* ending pagenumber */
        if ( sscanf(tcp + 1, "%ld", &LastPage) != 1 )
          Fatal("Argument is not a valid integer\n");
        LastPageSpecified = _TRUE;
        break;
      case 'v':    /* verbatim mode (print pxl-file names) */
        G_verbose = _TRUE;
        break;

#ifdef LJ
      case 'V':   /* bugfixes for various vendor's PCL emulations */
        tcp++;
        if (*tcp == 'K' || *tcp == 'k')
          kyocera_mode = _TRUE;
        else
          if (*tcp == 'B' || *tcp == 'b')
            brother_mode = _TRUE;
# ifdef LJ4
	else
        if (*tcp == '6' || *tcp == '6')
	    LJ6 = _TRUE;
# endif
        break;
#endif

      case 'w':       /* don't print out warnings */
        G_nowarn = _TRUE;
        break;
#ifdef LJ
      case 'z':
        PrintTestPage = (bool)(!PrintTestPage);
        break;
#endif
#ifdef LJ4
      case 'R':       /* number of copies to print */
        if ( sscanf(tcp + 1, "%d", &RESOLUTION) != 1 )
          Fatal("Argument of -R is not a valid integer\n");
        if (RESOLUTION != 300 && RESOLUTION != 600 ) {
          Warning("Resolution must be 300 or 600! Assuming 300.dpi.");
          RESOLUTION = 300;
        } else {
          if (RESOLUTION == 600) {
            MFMODE = MFMODE600;
            x_origin = 600;
            y_origin = 600;
          }
        }
        break;
      case 'W':  /* Set minimum width of compressed raster characters */
        CompressCharWidth = atoi(tcp+1);
        break;
      case 'C':  /* Set compression mode to use for raster characters */
        UseCompression = atoi(tcp+1);
        if ((UseCompression != 0) && (UseCompression != 2) && (UseCompression != 3))
          Fatal("Unsupported compression mode %d\n",UseCompression);
        break;
      case 'n': /* Download fonts raw */
        CompressFontMode = _FALSE;
        break;
#endif
#ifdef __riscos
      case 'i': /* name of directory to store diagrams in */
        tcp++;
        ddi = 0;
        while (*tcp != ' ' && *tcp != '\0' && ddi < DIAGDIRSIZE-1) {
          diagdir[ddi++] = *tcp++;
        }
        diagdir[ddi] = '\0';
        break;
      case 'j': /* don't print digrams */
        printdiag = _FALSE;
        break;
      case 'k': /* cache diagram bitmap in document folder */
        cachediag = _TRUE;
        break;
      case 'P':
        RasterMultipass = 1;
        break;
#endif
      default:
        fprintf(ERR_STREAM, "%c is not a valid flag\n", *tcp);
      }
    } else {

      filename = tcp;
      if (EQ(filename, "-")) {
        EmitFileName = "-";
#ifdef RISC_USE_OSL
        dvifp = BINOPEN("Kbd:");
#else
        dvifp = stdin;
	if (O_BINARY && !isatty(fileno(dvifp)))
	  AssureBinary(fileno(dvifp));
#endif
      } else {
	/* Since this code is used only once during startup, we don't care
	   about free()ing the allocated strings that represent filenames.
	   It will be more work to realize proper deallocation handling than
	   it's worth in terms of saving a few bytes. We consider these
	   bytes actually static memory where we don't know the size in
	   advance and don't add them to the allocated_storage count.
	   [27 Jun 07 -js] */
#ifdef KPATHSEA
        /* split into directory + file name */
	int tcplen, argvlen;
	tcp = (char *)xbasename(argv[argind]);/* this knows about any kind of slashes */
	tcplen = strlen(tcp);
	if ( tcplen == 0 ) {
	  /* This happens when the DVI file name has a trailing slash; this
	     is not a valid name. Then we terminate the argument parsing
	     loop, a usage message will be output below. */
	  break;
	}
	argvlen = strlen(argv[argind]);
	if (tcplen == argvlen)
	  curarea = "";
	else {
	  curarea = xstrdup(argv[argind]);
	  curarea[argvlen-tcplen] = '\0';
	}
#else
        tcp = strrchr(argv[argind], '/');
        /* split into directory + file name */
        if (tcp == NULL) {
          curarea[0] = "";
          tcp = argv[argind];
        } else {
	  curarea = xstrdup(argv[argind]);
          curarea[tcp-argv[argind]+1] = '\0';
          tcp += 1;
        }
#endif

        curname = (char *) xmalloc(strlen(tcp)+5);  /* + space for ".dvi" */
	(void) strcpy(curname, tcp);
        /* split into file name + extension */
        tcp1 = strrchr(curname, '.');
        if (tcp1 == NULL) {
          rootname = xstrdup(curname);
          strcat(curname, ".dvi");
        } else {
          *tcp1 = '\0';
          rootname = xstrdup(curname);
          *tcp1 = '.';
        }

	filename = (char *) xmalloc(strlen(curarea)+strlen(curname)+1);
        (void) strcpy(filename, curarea);
        (void) strcat(filename, curname);

        if ((dvifp = BINOPEN(filename)) == FPNULL) {
          /* do not insist on .dvi */
          if (tcp1 == NULL) {
	    filename[strlen(filename) - 4] = '\0';
	    dvifp = BINOPEN(filename);
          }
          if (dvifp == FPNULL) {
#ifdef MSC5
            Fatal("%s: can't find DVI file \"%s\"\n\n",
                  G_progname, filename);
#else
            perror(filename);
            exit (EXIT_FAILURE);
#endif
          }
        }
      } /* dvi filename != '-" */
    }
    argind++;
  }

#ifdef LJ4
  pgsiz_dots *= (int)(RESOLUTION/300); /* rescale dots to page */
#endif
  x_goffset = (short) MM_TO_PXL(x_offset) + x_origin;
  y_goffset = (short) MM_TO_PXL(y_offset) + y_origin;

  if (dvifp == FPNULL) {
    fprintf(ERR_STREAM,"\nThis is the DVI to %s converter %s",
            PRINTER, VERSION);
#ifdef SEVENBIT
    fprintf(ERR_STREAM,", 7bit");
#endif
    fprintf(ERR_STREAM," (%s)\n", OS);
    fprintf(ERR_STREAM,"usage: %s [OPTION]... DVIFILE\n", G_progname);

    fprintf(ERR_STREAM,"OPTIONS are:\n");
#ifdef DEBUG
    fprintf(ERR_STREAM,"\t--D ..... turns debug output on\n");
#endif
#ifndef KPATHSEA
    fprintf(ERR_STREAM,
            "\t-aX ..... X= searchpath leading to pixel-files (.pk or .pxl)\n");
#endif
#ifdef IBM3812
    fprintf(ERR_STREAM,
            "\t-b  ..... take paper for first page from alternate casette\n");
#endif
    fprintf(ERR_STREAM,"\t-cX ..... X= number of copies\n");
#ifdef LJ4
    fprintf(ERR_STREAM,"\t-CX ..... X= compression mode for raster chars; can be 0,2,3 (default=%d)\n", DEFAULT_COMPRESS_MODE);
#endif
#ifdef LJ2P
    fprintf(ERR_STREAM,"\t-dX ..... duplex, X=1: long-edge, 2: short-edge binding\n");
#endif
    fprintf(ERR_STREAM,"\t-D  ..... turns doublepage output on; ");
    fprintf(ERR_STREAM,"-D1 odd pages only, -D2 even\n");
#ifdef LJ4
    fprintf(ERR_STREAM,"\t-E  ..... print in econo-mode\n");
#endif
    fprintf(ERR_STREAM,"\t-eX ..... X= output file\n");
    fprintf(ERR_STREAM,"\t-fX ..... print from begin of page number X\n");
#ifdef LJ
    fprintf(ERR_STREAM,
            "\t-g  ..... do not reset printer at begin of job (go)\n");
#endif
#ifdef __riscos
    fprintf(ERR_STREAM,"\t-iX ..... X= name of dir to cache diagrams in\n");
    fprintf(ERR_STREAM,"\t-j  ..... don't print diagrams\n");
    fprintf(ERR_STREAM,"\t-k  ..... cache diagram bitmaps\n");
#endif
    fprintf(ERR_STREAM,"\t-hX ..... X= name of headerfile\n");
#ifdef LJ2P
    fprintf(ERR_STREAM,"\t-l  ..... landscape mode\n");
#endif
#ifdef MAKETEXPK
    fprintf(ERR_STREAM,"\t-MX ..... Don't generate missing PK files\n");
#endif
    fprintf(ERR_STREAM,"\t-mX ..... magnification X=0;h;1;2;3;4;5;#xxxx\n");
#ifdef LJ4
    fprintf(ERR_STREAM,"\t-n  ..... download fonts raw (default: compressed)\n");
#endif
    fprintf(ERR_STREAM,"\t-pX ..... print X pages\n");
#ifdef __riscos
    fprintf(ERR_STREAM,"\t-P  ..... Process printouts in 2 passes\n");
#endif
    fprintf(ERR_STREAM,"\t-q  ..... quiet operation\n");
    fprintf(ERR_STREAM,"\t-r  ..... process pages in reverse order\n");
#ifdef LJ4
    fprintf(ERR_STREAM,"\t-RX ..... set resolution to 300 or 600 dpi\n");
#endif
#ifdef LJ
    fprintf(ERR_STREAM,"\t-sX ..... set paper size to X (see documentation)\n");
#endif
    fprintf(ERR_STREAM,"\t-tX ..... print to end of page number X\n");
    fprintf(ERR_STREAM,"\t-w  ..... don't print out warnings\n");
#ifdef LJ4
    fprintf(ERR_STREAM,"\t-WX ..... X= minimum width of compressed chars (default=%d)\n",
            DEFAULT_COMPRESS_WIDTH);
#endif
    fprintf(ERR_STREAM,"\t-v  ..... tell user which pixel-files are used\n");
#ifdef LJ
    fprintf(ERR_STREAM,"\t-VX  .... Vendor options (kyocara or brother)\n");
#endif
    fprintf(ERR_STREAM,"\t-xX ..... X= x-offset on printout in mm\n");
    fprintf(ERR_STREAM,"\t-yX ..... X= y-offset on printout in mm\n");
    fprintf(ERR_STREAM,"\t-XO ..... O= x page origin in dots (default=%d)\n",
            XDEFAULTOFF );
    fprintf(ERR_STREAM,"\t-YO ..... O= y page origin in dots (default=%d)\n",
            YDEFAULTOFF );
#ifdef LJ
    fprintf(ERR_STREAM,"\t-z  ..... print test page with pagecounter after job\n");
#endif
    fprintf(ERR_STREAM,"\t-   ..... dvifile is stdin (must be seekable); implies -e-\n");
#ifdef KPATHSEA
    {
      extern KPSEDLL char *kpse_bug_address;
      putc ('\n', ERR_STREAM);
      fputs (kpse_bug_address, ERR_STREAM);
    }
#endif
    exit(1);
  }
  if (EQ(EmitFileName, "")) {
    EmitFileName = (char *) xmalloc(strlen(rootname)+sizeof(EMITFILE_EXTENSION));
    (void) strcpy(EmitFileName, rootname);
    strcat(EmitFileName, EMITFILE_EXTENSION);
  }
  if (G_quiet)
    G_verbose = _FALSE;
}

/*-->DoConv*/
/*********************************************************************/
/********************************  DoConv  ***************************/
/*********************************************************************/
long4
#if NeedFunctionPrototypes
DoConv(long4 num, long4 den, int convResolution)
#else
DoConv(num, den, convResolution)
long4    num, den;
int     convResolution;
#endif
{
  /*register*/ double conv;
  conv = ((double)num / (double)den) *
    ((double)mag / 1000.0) *
    ((double)convResolution/254000.0);

  return((long4)((1.0/conv)+0.5));
}
/*------------------------ end dviconv.c -------------------------------*/


/*------------------------ begin dvimisc.c -----------------------------*/
/*-->AllDone*/
/**********************************************************************/
/****************************** AllDone  ******************************/
/**********************************************************************/
#if NeedFunctionPrototypes
void AllDone(bool PFlag)
#else
void AllDone(PFlag)
bool PFlag;
#endif
{
#ifdef TIMING
  double  time;
#endif

  if (DoublePage && (PageParity==1)) { /* Shall we go around again?*/
    int k;
    char    n[STRSIZE];

    if (PrintEmptyPages && EvenPage && Reverse && PrintFirstPart) {
      WouldPrint ++;
      qfprintf(ERR_STREAM,"[EvenPage] ");
      FormFeed();
    }
#ifdef LJ
    Reverse = (bool)!Reverse;
#endif
    if (Reverse) {
      if (!PFlag) {
        FSEEK(dvifp, postambleptr, SEEK_SET);
        (void) NoSignExtend(dvifp, 1);
        ppagep = (long) NoSignExtend(dvifp, 4);
      }
      FSEEK(dvifp, ppagep, SEEK_SET);
    } else {
      FSEEK(dvifp,  14l, SEEK_SET);
      k = (int)NoSignExtend(dvifp, 1);
      GetBytes(dvifp, n, k);
    }

    if (PrintSecondPart) {
      if (PrintFirstPart) {
        qfprintf(ERR_STREAM,"\n----------------------starting second pass\n");
#ifdef LJ
        EMIT1("\033&l2H"); /* Manual Feed */
#endif
#ifdef IBM3812
        PMPout(6,"\326\001\305\300\326\252");
        /* set display; ring bell; stop; clear display */
        PMPflush;
#endif
      }

      if (PrintEmptyPages && Reverse) {
        if (ZeroPage) WouldPrint++;
        if ((WouldPrint%2) == 1) {
          qfprintf(ERR_STREAM,"[Padding] ");
          FormFeed();
        }
      }
      WouldPrint = 0;
      if (PrintEmptyPages && !Reverse && ZeroPage) {
        WouldPrint++;
        qfprintf(ERR_STREAM,"[ZeroPage] ");
        FormFeed();
      }
      PageParity = 0;
      PrintPages = StartPrintPages;
      return;
    }
  }

  if (EvenPage && DoublePage && !Reverse) WouldPrint++;

  if (PrintEmptyPages && DoublePage && PrintSecondPart) {
    if (Reverse) {
      if (ZeroPage) {
        WouldPrint ++;
        qfprintf(ERR_STREAM,"[ZeroPage] ");
        FormFeed();
      }
    }
    else if ((WouldPrint%2) != 0) {
      qfprintf(ERR_STREAM,"[Padding] ");
      FormFeed();
    }
  }

#ifdef IBM3812
  PMPout(10, "\373\010PMP.init");  /* re-init printer  */
  PMPflush;

  if (used_fontstorage > MAXFONTSTORAGE) {
    Warning("\n\7used font_storage of %s: %ld Bytes (of %ld)\7",
            PRINTER, (long)used_fontstorage, MAXFONTSTORAGE);
    Warning("Try to format file in separate runs!");
  } else
    qfprintf(ERR_STREAM,"\nAll done, used font_storage of %s: %ld Bytes (of %ld)",
              PRINTER, (long)used_fontstorage, MAXFONTSTORAGE);
#endif
#ifdef LJ
# ifdef SHARP_JX_9500
  if (used_fontstorage > MAXFONTSTORAGE) {
    Warning("\n\7used font_storage of %s: %ld Bytes (of %ld)\7",
            PRINTER, (long)used_fontstorage, MAXFONTSTORAGE);
    Warning("Try to format file in separate runs!");
  } else
    qfprintf(ERR_STREAM,"\nAll done, used font_storage of %s: %ld Bytes (of %ld)",
              PRINTER, (long)used_fontstorage, MAXFONTSTORAGE);
# else
  qfprintf(ERR_STREAM,"\nAll done, used font_storage of %s: %ld Bytes",
            PRINTER, (long)used_fontstorage);
# endif
#ifdef LJ_RESIDENT_FONTS
  qfprintf(ERR_STREAM," + %d resident font%s", resident_count,
           resident_count == 1 ? "" : "s");
#endif
  EMIT1("\033E");
#ifdef LJ4
  EMIT1("\033%%-12345X");   /* what does it? */
#endif
  if (PrintTestPage) EMIT1("\033z");
#ifdef vms
  /* last record is not flushed to file, unless it is completely filled */
  for (kk = (int)((*outfp)->_cnt); kk > 0; --kk)
    putc('\0',outfp);
  fflush(outfp);
#endif
#endif

  if (!G_quiet) {
    fprintf(ERR_STREAM,"\nDynamically allocated storage: %ld Bytes \n",
            (long)allocated_storage);
    fprintf(ERR_STREAM,"%d characters downloaded as soft fonts\n", G_ncdl);

#ifdef TIMING
#ifdef BSD_TIME_CALLS
    ftime(&timebuffer);
    time = (timebuffer.time + (float)(timebuffer.millitm)/1000.0) - start_time;
#else
    gettimeofday(&Tp, NULL);
    time = (Tp.tv_sec + (float)(Tp.tv_usec)/1000000.0) - start_time;
#endif

    if (ndone > 0) {
      fprintf(ERR_STREAM,
              "Time of complete run: %.2f seconds, %d page(s), %.2f seconds/page",
              time, ndone, time / ndone);
      fprintf(ERR_STREAM," (%.2f ppm)\n",(ndone * 60) / time);
    }
    fprintf(ERR_STREAM,"\n");
#endif
  }
  CloseFiles();
  if ( tmp_dir[0] != '\0' )
    rmdir (tmp_dir);			/* ignore errors */
  exit(G_errenc);
}

/*-->DoSpecial*/
/*********************************************************************/
/*****************************  DoSpecial  ***************************/
/*********************************************************************/

typedef enum {
  ORIENTATION,
  RESETPOINTS,
  DEFPOINT,
  FILL,
  GRAY,
  PATTERN,
  COMMENT,
  HPFILE,
  HPFILE_VERBATIM,
  PSFILE_SYNTAX,
  PSFILE,
  LLX,
  LLY,
  URX,
  URY,
  RWI,
  RHI
} SpecialKeywords;

KeyDesc KeyTab[] = {
  { ORIENTATION, "orientation", Integer},
  { RESETPOINTS, "resetpoints", String},
  { DEFPOINT, "defpoint", String},
  { FILL, "fill", String},
  { GRAY, "gray", Integer},
  { GRAY, "grey", Integer},
  { PATTERN, "pattern", Integer},
  { COMMENT, "comment", String},
  { HPFILE, "hpfile", String},
  { HPFILE_VERBATIM, "hpfile-verbatim", String},
  { PSFILE_SYNTAX, "dvilj-psfile-syntax", String },
  { PSFILE, "psfile", String },
  { LLX, "llx", Integer},
  { LLY, "lly", Integer},
  { URX, "urx", Integer},
  { URY, "ury", Integer},
  { RWI, "rwi", Integer},
  { RHI, "rhi", Integer}
  /*,
    {"hsize", Dimension},
    {"vsize", Dimension},
    {"hoffset", Dimension},
    {"voffset", Dimension},
    {"hscale", Number},
    {"vscale", Number}*/
};

#define NKEYS (sizeof(KeyTab)/sizeof(KeyTab[0]))

#ifdef __riscos
# ifdef LJ

/* Compare two strings, ignoring case;
   s1 pointer to null-terminated keyword, s2 pointer to parseline;
   returns (if successful) pointer to character following keyword in s2 */
#if NeedFunctionPrototypes
bool StrCompare(char *s1, char *s2, char **end)
#else
bool StrCompare(s1, s2, end)
char *s1;
char *s2;
char **end;
#endif
{
  char *a,*b;

  a = s1;
  b = s2;
  while (*a != '\0') {
    if (tolower(*a) != tolower(*b)) return(_FALSE);
    a++;
    b++;
  }
  *end = b;
  return(_TRUE);
}

/* Read <number> integer values from string and store results in
   <result>. Returns number + of arguments actually read, end =
   pointer to char following last number */
#if NeedFunctionPrototypes
int ParseNumbers(char *str, int *result, int number, char **end)
#else
int ParseNumbers(str, result, number, end)
char *str;
int *result;
int number;
char **end;
#endif
{
  char *s;
  int count = 0;

  s = str;
  while ((*s != '\0') && (count < number)) {
    while ((*s == ' ') || (*s == ',') || (*s == '='))
      s++;
    if (*s != '\0') {
      result[count++] = strtod(s,&s);
    }
  }
  while ((*s == ' ') || (*s == ',') || (*s == '='))
    s++;
  *end = s;
  return(count);
}


/* Diagram commands are parsed separately since the format varies from the one
+    used by the other special commands */
#if NeedFunctionPrototypes
bool ParseDiagram(char *str)
#else
bool ParseDiagram(str)
char *str;
#endif
{
  diagtrafo dt;
  char *s,*sh;
  char diagname[STRSIZE];
  int results[4],no;

  s = str;
  while (*s == ' ')
    s++;
  if ((StrCompare("drawfile",s,&s)) || (StrCompare("DVIview_diagram",s,&s))) {

    if (printdiag == _FALSE)
      return(_TRUE); /* it's a diagram, but don't print */

    while ((*s == ' ') || (*s == '='))
      s++; /* space or '=' separates keyword/keyval */

    if (*s == '\0') {
      fprintf(ERR_STREAM,"No filename given for \\special-diagram!\n");
      return(_TRUE);
    }
    sh = diagname;
    while ((*s != ' ') && (*s != ',') && (*s != '\0'))
      *sh++ = *s++;
    *sh = '\0';

    /* Set up default values */
    dt.scalex = dt.scaley = 100;
    dt.cropl = dt.cropb = dt.cropr = dt.cropt = 0;
    while (*s != '\0') {
      while ((*s == ' ') || (*s == ','))
        s++;
      if (*s != '\0') {
        if (StrCompare("scale",s,&s)) {
          if ((no = ParseNumbers(s,results,2,&s)) != 2) {
            fprintf(ERR_STREAM,
                   "Too few arguments (%d) given for <scale> - ignored.\n",no);
          }
          dt.scalex = results[0];
          dt.scaley = results[1];
        }
        else if (StrCompare("crop",s,&s)) {
          if ((no = ParseNumbers(s,results,4,&s)) != 4) {
            fprintf(ERR_STREAM,
                   "Too few arguments (%d) given for <crop> - ignored.\n",no);
          }
          dt.cropl = results[0];
          dt.cropr = results[1];
          dt.cropt = results[2];
          dt.cropb = results[3];
        }
        else {
          fprintf(ERR_STREAM,"Bad \\special keyword - <%s> ignored\n",s);
          /* skip over this word */
          while ((*s != ' ') && (*s != ',') && (*s != '=') && (*s != '\0'))
            s++;
        }
      }
    }
    /* fprintf(ERR_STREAM,"Diagram: %s, scale %d %d, crop %d %d %d %d\n",
       diagname,dt.scalex,dt.scaley,dt.cropl,dt.cropb,dt.cropr,dt.cropt);*/
    diagram(diagname,&dt);
    return(_TRUE);
  }
  else
    return(_FALSE);
}
# endif /* LJ */
#endif /* __riscos */


#ifndef HAVE_MKDTEMP
/* If mkdtemp() is not available, supply an (unsecure) version of it. We try
   to use mktemp() to get the temporary directory name, since that maps best
   to mkdtemp() behavior. But if mktemp() is also not available, we resort
   to tmpnam() which is supposed to be there from the C standard. */
#ifndef HAVE_MKTEMP
#define mktemp tmpnam
#endif
char * mkdtemp ( char * template )
{
  if ( mktemp(template) == NULL  ||  template[0] == '\0' ) {
    if ( errno == 0 )  errno = EINVAL;	/* if it's tmpnam() */
    return NULL;
  }
  if ( mkdir(template, 0700) == -1 ) {
    return NULL;
  }
  return template;
}
#endif


/* interpret a \special command, made up of keyword=value pairs */
#if NeedFunctionPrototypes
void DoSpecial(char *str, int n)
#else
void DoSpecial(str, n)
char *str;
int  n;
#endif
{
  bool	  first_keyword = _TRUE;
  char    xs[STRSIZE], ys[STRSIZE];
  char    *include_file = NULL;
  enum    { None, VerbFile, HPFile, PSFile } file_type = None;
  float   x,y;
  long4   x_pos, y_pos;
  KeyWord k;
  int     i, j, j1;
  static  int   GrayScale = 10, Pattern = 1;
  static  bool  GrayFill = _TRUE;
  static  long4 p_x[MAX_SPECIAL_DEFPOINTS], p_y[MAX_SPECIAL_DEFPOINTS];
  static  bool  need_init_pxy = _TRUE;
  int llx=0, lly=0, urx=0, ury=0, rwi=0;

  str[n] = '\0';
  if ( need_init_pxy ) {
    for ( i=0 ; i<MAX_SPECIAL_DEFPOINTS ; i++ )
      p_x[i] = p_y[i] = -1;
    need_init_pxy = _FALSE;
  }

  SetPosn(h, v);
#ifdef __riscos
#ifdef LJ
  if (ParseDiagram(str))
    return;
#endif
#endif

  /* When the first keyword is already unknown, we skip the whole special.
     This is probably one for another driver and the user got notified
     already about the problem. */
  while ( (str = GetKeyStr(str, &k)) != NULL ) {
    /* get all keyword-value pairs */
    if ( k.vt == None ) {		/* no value */
      /* Single word might also be "comment", then ignore the rest */
      if ( EQ(k.Key, "comment") )
	return;
      /* For compatibility, single words are taken as file names. But then
	 the include file must be accessible without being searched with
	 kpathsea. */
      if ( access(k.Key, 0) == 0 ) {
	if ( include_file && !kpse_tex_hush ("special") ) {
	  Warning("More than one \\special file name given, %s ignored", include_file);
	  free (include_file);
	}
	include_file = xstrdup(k.Key);
	file_type = VerbFile;
      } else {
	if ( !kpse_tex_hush ("special") )
	  Warning("Invalid keyword or value in \\special - <%s> ignored", k.Key);
	if ( first_keyword )
	  return;
      }
    } else if ( GetKeyVal( &k, KeyTab, NKEYS, &i ) && i != -1 ) {
      switch (i) {

      case ORIENTATION:
#ifdef IBM3812
        if ((k.v.i >= 0) && (k.v.i < 4)) {
          last_ry = UNKNOWN;
          sprintf(PMPformat, "\322%c", (unsigned char)k.v.i);
          PMPout(2, PMPformat);
          if (k.v.i == 1) Landscape = _TRUE;
          else if (k.v.i == 0) Landscape = _FALSE;
        }
#endif
#ifdef LJ
        if ( k.v.i >= 0 && k.v.i <= 3 ) {
          last_rx = last_ry = UNKNOWN;
          EMIT2("\033&l%dO\033*rF", (unsigned char)k.v.i);
        }
#endif
        else {
	  Warning( "Invalid orientation (%d) given; ignored.", k.v.i);
	}
        break;

      case RESETPOINTS:
	for ( i=0 ; i<MAX_SPECIAL_DEFPOINTS ; i++ )
	  p_x[i] = p_y[i] = -1;
        break;

      case DEFPOINT:
	/* 254 is STRSIZE-1. cpp should be used to construct that number. */
        i = sscanf(k.Val,"%d(%254[^,],%254s)",&j,xs,ys);
        if (i>0) {
	  if ( j < 0  ||  j >= MAX_SPECIAL_DEFPOINTS ) {
	    Warning ("defpoint %d ignored, must be between 0 and %d",
		     j, MAX_SPECIAL_DEFPOINTS-1);
	    break;
	  }
          x_pos = h;
          y_pos = v;
          if ( i > 1  &&  sscanf(xs,"%fpt",&x) > 0 )
              x_pos = PT_TO_DVI(x);
          if ( i > 2  &&  sscanf(ys,"%fpt",&y) > 0 )
              y_pos = PT_TO_DVI(y);
          p_x[j]=x_pos;
          p_y[j]=y_pos;
        } else {
	  Warning("invalid point definition");
	}
        break;

      case FILL:
	/* 254 is STRSIZE-1. cpp should be used to construct that number. */
        i = sscanf(k.Val,"%d/%d",&j,&j1);
        if (i>1) {
#ifdef LJ
	  if ( j < 0 || j >= MAX_SPECIAL_DEFPOINTS ) {
	    Warning ("fill ignored, point %d must be between 0 and %d",
		     j, MAX_SPECIAL_DEFPOINTS);
	    break;
	  }
	  if ( p_x[j] == -1 ) {
	    Warning ("fill ignored, point %d is undefined\n", j);
	    break;
	  }
	  if ( j1 < 0 || j1 >= MAX_SPECIAL_DEFPOINTS ) {
	    Warning ("fill ignored, point %d must be between 0 and %d",
		     j1, MAX_SPECIAL_DEFPOINTS);
	    break;
	  }
	  if ( p_x[j1] == -1 ) {
	    Warning ("fill ignored, point %d is undefined\n", j1);
	    break;
	  }
          SetPosn(p_x[j], p_y[j]);
          x_pos = (long4)PIXROUND(p_x[j1]-p_x[j], hconv);
          y_pos = (long4)PIXROUND(p_y[j1]-p_y[j], vconv);
          if (labs(x_pos)<labs(y_pos)) x_pos = x_pos+3;
          else                         y_pos = y_pos+3;
          if (GrayFill) {
            EMIT4("\033*c%lda%ldb%dg2P", x_pos, y_pos, GrayScale);
          } else {
            EMIT4("\033*c%lda%ldb%dg3P", x_pos, y_pos, Pattern);
          }
          last_rx = last_ry = UNKNOWN;
#endif
        }
        break;

      case GRAY:
        if ((k.v.i >= 0) && (k.v.i < 101)) {
          GrayScale = k.v.i;
          GrayFill = _TRUE;
        } else {
          Warning( "Invalid gray scale (%d) given; ignored.", k.v.i);
	}
        break;

      case PATTERN:
        if ((k.v.i >= 0) && (k.v.i < 7)) {
          Pattern = k.v.i;
          GrayFill = _FALSE;
        } else {
          Warning( "Invalid pattern (%d) given; ignored.", k.v.i);
	}
        break;

      case COMMENT:
	return;
	/*NOTREACHED*/
	break;

      case HPFILE:
        if ( include_file && !kpse_tex_hush ("special") ) {
	  Warning("More than one \\special file name given. %s ignored", include_file);
	  free(include_file);
	}
        include_file = xstrdup(k.Val);
	file_type = HPFile;
        break;

      case HPFILE_VERBATIM:
        if ( include_file && !kpse_tex_hush ("special") ) {
	  Warning("More than one \\special file name given. %s ignored", include_file);
	  free(include_file);
	}
        include_file = xstrdup(k.Val);
	file_type = VerbFile;
        break;

      case PSFILE_SYNTAX:
	if ( EQ(k.Val, "ignore") )
	  PSFileSyntaxTyp = Ignore;
	else if ( EQ(k.Val, "dvilj") )
	  PSFileSyntaxTyp = PSFile_dvilj;
	else
	  Warning("Ignored invalid value '%s' for dvilj-psfile-syntax", k.Val);
	break;

      case PSFILE:
        if ( include_file ) {
	  Warning("More than one \\special file name given. %s ignored", include_file);
	  free(include_file);
	}
	if ( PSFileSyntaxTyp != Ignore ) {
	  include_file = xstrdup(k.Val);
	  file_type = PSFile;
	} else {
	  include_file = NULL;
	}
        break;

      case LLX: llx = k.v.i; break;
      case LLY: lly = k.v.i; break;
      case URX: urx = k.v.i; break;
      case URY: ury = k.v.i; break;
      case RWI: rwi = k.v.i; break;
      case RHI:
	if (!kpse_tex_hush ("special"))
	  Warning("Whatever rhi was good for once, it is ignored now.");
	break;

      default:
	if ( !kpse_tex_hush ("special") )
	  Warning("Can't handle %s=%s command; ignored.", k.Key, k.Val);
	if ( first_keyword )
	  return;
        break;
      }

    } else {
      if ( !kpse_tex_hush ("special") )
	Warning("Invalid keyword or value in \\special - <%s> ignored", k.Key);
      if ( first_keyword )
	return;
    }

    free (k.Key);
    if ( k.Val != NULL )  free(k.Val);
    first_keyword = _FALSE;
  }

  if ( include_file ) {
    char * include_path;
    last_rx = last_ry = UNKNOWN;
#ifdef IBM3812
    PMPflush;
#endif

    /* Search the include file with kpathsea, but don't open it immediately.
       If it's a psfile special, it will get passed to Ghostscript. An
       include file is often placed at the same place as documents: We use
       both a program specific search path and the tex search path. We can
       not use kpse_find_tex() as it would call mktex, which we don't want
       to do for included PCL files. */
    if ( (include_path = kpse_find_file(include_file, kpse_program_binary_format, false)) == NULL &&
	 (include_path = kpse_find_file(include_file, kpse_tex_format, false)) == NULL ) {
      Warning ("Could not locate %s, ignoring inclusion special", include_file);
      file_type = None;
    } else {
      free (include_file);
      include_file = include_path;
    }

#ifdef LJ
    if ( file_type == PSFile) {
      /* int height = rwi * (urx - llx) / (ury - lly);*/
      int width  = urx - llx;
      int height = ury - lly;
      char cmd[255];
      char *cmd_format = "%s -q -dSIMPLE -dSAFER -dNOPAUSE -sDEVICE=%s -sOutputFile=%s %s %s showpage.ps -c quit";
      char *gs_cmd;
      int scale_factor, adjusted_height, adjusted_llx;
      char *printer = "ljetplus"; /* use the most stupid one */

      char pcl_file[STRSIZE];
      char scale_file[STRSIZE];
      FILEPTR scalef;

      if ( urx == 0 || ury == 0 || rwi == 0 ) {
	/* Since dvips' psfile special has a different syntax, this might
	   well be one of those specials, i.e., a non-dviljk special. Then
	   the Warning should be suppressable. */
	if ( !kpse_tex_hush ("special") )
	  Warning ("Ignoring psfile special without urx, ury and rwi attributes");
	free (include_file);
	return;
      }
      scale_factor    = 3000 * width / rwi;
      adjusted_height = height * 300/scale_factor;
      adjusted_llx    = llx    * 300/scale_factor;

      /* We cannot use mkstemp, as we cannot pass two open file descriptors
	 portably to Ghostscript. We don't want to use tmpnam() or tempnam()
	 either, as they have tempfile creation race conditions. Instead we
	 create a temporary directory with mkdtemp().
	 We need to create the temporary directory only once per
	 run; it will be deleted in AllDone(). */
      if ( tmp_dir[0] == '\0' ) {
	char * base_dir;
	if ( (base_dir = getenv("TMPDIR")) == NULL ) {
	  base_dir = "/tmp";
	} else if ( strlen(base_dir) > STRSIZE - sizeof("/dviljkXXXXXX/include.pcl") ) {
	  Warning ("TMPDIR %s is too long, using /tmp instead", base_dir);
	  base_dir = "/tmp";
	}
	/* FIXME: Actually, we would need a function to sanitize base_dir here.
	   There may still be constructs like /.. or similar. [03 Jul 07 -js] */
	if ( base_dir[0] == '/'  && base_dir[1] == '\0' ) {
	  Warning ("Feeling naughty, do we? / is no temporary directory, dude");
	  base_dir = "/tmp";
	}
	strcpy (tmp_dir, base_dir);
	strcat (tmp_dir, "/dviljkXXXXXX");
	if ( mkdtemp(tmp_dir) == NULL ) {
	  Warning ("Could not create temporary directory %s, errno = %d; ignoring include file special",
		   tmp_dir, errno);
	  return;
	}
      }
      strcpy(pcl_file, tmp_dir);
      strcat(pcl_file, "/include.pcl");
      strcpy(scale_file, tmp_dir);
      strcat(scale_file, "/scale.ps");

      if ( (scalef = BOUTOPEN(scale_file)) == FPNULL ) {
	Warning("Unable to open file %s for writing", scale_file );
	free (include_file);
	unlink(scale_file);		/* ignore error */
	return;
      }
      fprintf(scalef, "%.2f %.2f scale\n%d %d translate\n",
	      300.0/scale_factor, 300.0/scale_factor,
	      0, adjusted_height == height ? 0 : ury);
      BCLOSE( scalef );

#ifdef WIN32
      if ( (gs_cmd = getenv("GS_PATH")) == NULL )
	gs_cmd = "gswin32c.exe";
#else
      gs_cmd = "gs";
#endif
      if ( strlen(cmd_format)-10 + strlen(gs_cmd) + strlen(printer) +
	       strlen(pcl_file) + strlen(scale_file) + strlen(include_file) +1 >
	   sizeof(cmd) ) {
	Warning ("Ghostscript command for %s would be too long, skipping special", include_file);
	free (include_file);
	unlink(scale_file);		/* ignore errors */
	unlink(pcl_file);
	return;
      }
      sprintf(cmd, cmd_format,
	      gs_cmd, printer, pcl_file, scale_file, include_file);
#ifdef DEBUGGS
      fprintf(stderr,
	"PS-file '%s' w=%d, h=%d, urx=%d, ury=%d, llx=%d, lly=%d, rwi=%d\n",
	      include_file, urx - llx, height, urx,ury,llx,lly, rwi);
      fprintf(stderr,"%s\n",cmd);
#endif
      if (system(cmd)) {
	Warning("execution of '%s' returned an error", cmd);
      } else {
#ifdef DEBUGGS
	fprintf(stderr, "o=%d, h=%d, so=%d, sh=%d\n",
		llx, height, adjusted_llx, adjusted_height);

	fprintf(stderr, "OLD x=%d, y=%d\n",
		(int)PIXROUND(h, hconv) + x_goffset,
		(int)PIXROUND(v, vconv) + y_goffset);
#endif
	v -= 65536l*adjusted_height; /**300/scale_factor;*/
	h -= 65536l*adjusted_llx; /* *300/scale_factor;*/
	SetPosn(h, v);
#ifdef DEBUGGS
	fprintf(stderr, "NEW x=%d, y=%d\n",
		(int)PIXROUND(h, hconv) + x_goffset,
		(int)PIXROUND(v, vconv) + y_goffset);
#endif

	CopyHPFile( pcl_file );
      }
      unlink(scale_file);		/* ignore errors */
      unlink(pcl_file);
    }
    else
#endif /* LJ */

    if ( file_type == HPFile )
      CopyHPFile( include_file );
    else if ( file_type == VerbFile )
      CopyFile( include_file );
    else if ( file_type == None )
      /* do nothing */ ;
    else
      Warning ("This can't happen: unknown file_type value %d", file_type);

    if ( include_file != NULL )  free(include_file);
  }
}




/*-->GetKeyStr*/
/**********************************************************************/
/*****************************  GetKeyStr  ****************************/
/**********************************************************************/
/* Extract first keyword-value pair from string (value part may be null),
 * keyword and value are allocated and must be free by caller.
 * Return pointer to remainder of string,
 * return NULL if none found.
 */
#if NeedFunctionPrototypes
char *GetKeyStr(char *str, KeyWord *kw )
#else
char    *GetKeyStr( str, kw )
char    *str;
KeyWord *kw;
#endif
{
  char *s, *start;
  char save_char, quote_char;
  if ( !str )
    return( NULL );
  for (s = str; *s == ' '; s++)
    ;          /* skip over blanks */
  if (*s == '\0')
    return( NULL );
  start = s++;				/* start of keyword */
  while ( *s != ' ' && *s != '\0' && *s != '=' )  /* locate end */
    s++;
  save_char = *s;
  *s = '\0';
  kw->Key = xstrdup(start);
  kw->Val = NULL;
  kw->vt = None;
  if ( save_char == '\0' )		/* shortcut when we're at the end */
    return (s);
  *s = save_char;			/* restore keyword end char */
  while ( *s == ' ' ) s++ ;		/* skip over blanks */
  if ( *s != '=' )			/* no "=" means no value */
    return( s );
  for (s++; *s == ' '; s++)
    ;					/* skip over blanks */
  if ( *s == '\'' || *s == '\"' )	/* get string delimiter */
    quote_char = *s++;
  else
    quote_char = ' ';
  start = s;				/* no increment, might be "" as value */
  while ( *s != quote_char && *s != '\0' )
    s++;			  /* locate end of value portion */
  save_char = *s;
  *s = '\0';
  kw->Val = xstrdup(start);
  kw->vt = String;
  if ( save_char != '\0' ) {		/* save_char is now quote_char */
    *s = save_char;
    if ( quote_char != ' ' )		/* we had real quote chars */
      s++;
  }
  return( s );
}


/*-->GetKeyVal*/
/**********************************************************************/
/*****************************  GetKeyVal  ****************************/
/**********************************************************************/
/* get next keyword-value pair decode value according to table entry  */
#if NeedFunctionPrototypes
bool GetKeyVal(KeyWord *kw, KeyDesc tab[], int nt, int *tno)
#else
bool    GetKeyVal( kw, tab, nt, tno)
KeyWord *kw;
KeyDesc tab[];
int     nt;
int     *tno;
#endif
{
  int     i;
  char    c = '\0';
  *tno = -1;
  for (i = 0; i < nt; i++)
    if ( IsSame(kw->Key, tab[i].Entry) ) {
      *tno = tab[i].KeyId;
      switch ( tab[i].Typ ) {
      case None:
        if ( kw->vt != None )
          return( _FALSE );
        break;
      case String:
        if ( kw->vt != String )
          return( _FALSE );
        break;
      case Integer:
        if ( kw->vt != String )
          return( _FALSE );
        if ( sscanf(kw->Val, "%d%c", &(kw->v.i), &c) != 1 || c != '\0' )
          return( _FALSE );
        break;
      }
      kw->vt = tab[i].Typ;
      return( _TRUE );
    }
  return( _TRUE );
}


/*-->IsSame*/
/**********************************************************************/
/*******************************  IsSame  *****************************/
/**********************************************************************/
/* compare strings, ignore case */
#if NeedFunctionPrototypes
bool IsSame(char *a, char *b)
#else
bool IsSame(a, b)
char    *a, *b;
#endif
{
  char *x, *y;

  for (x = a, y = b; *a; a++, b++)
    if ( tolower(*a) != tolower(*b) )
      return( _FALSE );

  return( *a == *b ? _TRUE : _FALSE );
}


/*-->FindPostAmblePtr*/
/**********************************************************************/
/************************  FindPostAmblePtr  **************************/
/**********************************************************************/
/* this routine will move to the end of the file and find the start
    of the postamble */
#if NeedFunctionPrototypes
void FindPostAmblePtr(long *postambleptr)
#else
void FindPostAmblePtr(postambleptr)
long *postambleptr;
#endif
{
  long4    i;
  FSEEK(dvifp,  0l, SEEK_END);   /* goto end of file */
  *postambleptr = FTELL(dvifp) - 4;
  FSEEK(dvifp, *postambleptr, SEEK_SET);
  while (_TRUE) {
    FSEEK(dvifp, --(*postambleptr), SEEK_SET);
    if (((i = NoSignExtend(dvifp, 1)) != 223) &&
        (i != DVIFORMAT))
      Fatal("Bad end of DVI file");
    if (i == DVIFORMAT)
      break;
  }
  FSEEK(dvifp, (*postambleptr) - 4, SEEK_SET);
  (*postambleptr) = NoSignExtend(dvifp, 4);
  FSEEK(dvifp, *postambleptr, SEEK_SET);
}


/*-->ReadPostAmble*/
/**********************************************************************/
/**************************  ReadPostAmble  ***************************/
/**********************************************************************/
/***********************************************************************
    This routine is used to read in the postamble values.  It
    initializes the magnification and checks the stack height prior to
    starting printing the document.
***********************************************************************/
#if NeedFunctionPrototypes
void ReadPostAmble(bool load)
#else
void ReadPostAmble(load)
bool load;
#endif
{
  FindPostAmblePtr(&postambleptr);
  if (NoSignExtend(dvifp, 1) != POST)
    Fatal("POST missing at head of postamble");
#ifdef DEBUG
  if (Debug)
    fprintf(ERR_STREAM,"got POST command\n");
#endif
  ppagep = (long)NoSignExtend(dvifp, 4);
  num = NoSignExtend(dvifp, 4);
  den = NoSignExtend(dvifp, 4);
  mag = NoSignExtend(dvifp, 4);
  if ( usermag > 0 && usermag != mag )
    Warning("DVI magnification of %ld over-ridden by user (%ld)",
            (long)mag, usermag );
  if ( usermag > 0 )
    mag = usermag;
  hconv = DoConv(num, den, hconvRESOLUTION);
  vconv = DoConv(num, den, vconvRESOLUTION);
  (void) NoSignExtend(dvifp, 4);   /* height-plus-depth of tallest page */
  (void) NoSignExtend(dvifp, 4);   /* width of widest page */
  if (NoSignExtend(dvifp, 2) >= STACK_SIZE)
    Fatal("Stack size is too small");
  (void) NoSignExtend(dvifp, 2);   /* this reads the number of pages in */
  /* the DVI file */
#ifdef DEBUG
  if (Debug)
    fprintf(ERR_STREAM,"now reading font defs");
#endif
  if (load)
    GetFontDef();
}

#ifdef IBM3812
/*-->PMPLine*/
/**********************************************************************/
/*****************************  PMPLine  ******************************/
/**********************************************************************/
/* drawing lines on the 3812 using PMP vector commands */
#if NeedFunctionPrototypes
void PMPLine(int w, int y, int x