/*
*      Written by Eric C. Cooper, CMU
*/

/********************************
*      The C environment       *
*******************************/

#ifndef X10
#include <X11/Xlib.h>   /* include Xfuncs.h, if available */
#include <X11/Xutil.h>  /* needed for XDestroyImage */
#include <X11/Xos.h>    /* same as below */
#else   /* X10 */
#include <X/Xlib.h>     /* get type of Window */
#include <sys/types.h>  /* for sites without X11 */
#ifdef  SYSV
#include <string.h>
#define index   strchr
#define rindex  strrchr
#include <fcntl.h>
#else /* SYSV */
#include <strings.h>
#endif /* SYSV */
#include <sys/file.h>
#endif  /* X10 */

#ifndef XlibSpecificationRelease
#define XlibSpecificationRelease 0
#endif

#if     XlibSpecificationRelease >= 5
#include <X11/Xfuncs.h>
#endif

#ifdef  VMS
#include <string.h>
#define index   strchr
#define rindex  strrchr
#define bzero(a, b)     (void) memset ((void *) (a), 0, (size_t) (b))
#define bcopy(a, b, c)  (void) memmove ((void *) (b), (void *) (a), (size_t) (c))
#endif

#include <stdio.h>
#include <setjmp.h>

#ifndef OPEN_MODE
#ifndef VMS
#define OPEN_MODE "rb"
#else   /* VMS */
#define OPEN_MODE       "r", "ctx=stm"
#endif  /* VMS */
#endif  /* OPEN_MODE */

#ifndef SYSV
#ifndef VMS
#define HAS_SIGIO               /* has SIGIO on _sockets_ */
#endif
#endif

#ifndef NeedFunctionPrototypes
#ifdef  __STDC__
#define NeedFunctionPrototypes  1
#else   /* STDC */
#define NeedFunctionPrototypes  0
#endif  /* STDC */
#endif  /* NeedFunctionPrototypes */

#ifndef NeedWidePrototypes
#define NeedWidePrototypes      NeedFunctionPrototypes
#endif

#if     NeedWidePrototypes
#define WIDEARG(a, b)   b
#else
#define WIDEARG(a, b)   a
#endif

#ifndef NeedVarargsPrototypes
#define NeedVarargsPrototypes   NeedFunctionPrototypes
#endif

#ifndef _XFUNCPROTOBEGIN
#define _XFUNCPROTOBEGIN
#define _XFUNCPROTOEND
#endif

#ifndef _Xconst
#ifdef  __STDC__
#define _Xconst const
#else   /* STDC */
#define _Xconst
#endif  /* STDC */
#endif  /* _Xconst */

#ifndef VOLATILE
#if     defined(__STDC__) || (defined(__stdc__) && defined(__convex__))
#define VOLATILE        volatile
#else
#define VOLATILE        /* nothing */
#endif
#endif

#ifndef NORETURN
#ifdef  __GNUC__
#define NORETURN        volatile
#else
#define NORETURN        /* nothing */
#endif
#endif

#define Printf  (void) printf
#define Puts    (void) puts
#define Fprintf (void) fprintf
#define Sprintf (void) sprintf
#define Fseek   (void) fseek
#define Fread   (void) fread
#define Fputs   (void) fputs
#define Putc    (void) putc
#define Putchar (void) putchar
#define Fclose  (void) fclose
#define Strcpy  (void) strcpy

/********************************
*       Types and data         *
*******************************/

#ifndef EXTERN
#define EXTERN  extern
#define INIT(x)
#define NTINIT(x)
#endif

typedef unsigned char ubyte;
#define Boolean char
#define True    1
#define False   0

#define MAXDIM          32767

/*
*      pixel_conv is currently used only for converting absolute positions
*      to pixel values; although normally it should be
*              ((int) ((x) / shrink_factor + (1 << 15) >> 16)),
*      the rounding is achieved instead by moving the constant 1 << 15 to
*      PAGE_OFFSET in dvi_draw.c.
*/
#define pixel_conv(x)           ((int) ((x) / shrink_factor >> 16))
#define pixel_round(x)          ((int) ROUNDUP(x, shrink_factor << 16))
#define spell_conv0(n, f)       ((long) (n * f))
#define spell_conv(n)           spell_conv0(n, dimconv)

#ifdef X10
#undef  MSBITFIRST
#undef  BMLONG
#define BMSHORT
#endif

#ifdef  BMLONG
#define BMUNIT                  unsigned long
#define BITS_PER_BMUNIT         32
#define BYTES_PER_BMUNIT        4
#else   /* BMLONG */
#ifdef  BMSHORT
#define BMUNIT                  unsigned short
#define BITS_PER_BMUNIT         16
#define BYTES_PER_BMUNIT        2
#else   /* BMSHORT */
#define BMUNIT                  unsigned char
#define BITS_PER_BMUNIT         8
#define BYTES_PER_BMUNIT        1
#endif  /* BMSHORT */
#endif  /* BMLONG */

#define ADD(a, b)       ((BMUNIT *) (((char *) a) + b))
#define SUB(a, b)       ((BMUNIT *) (((char *) a) - b))

extern  BMUNIT  bit_masks[BITS_PER_BMUNIT + 1];

struct frame {
       struct framedata {
               long dvi_h, dvi_v, w, x, y, z;
               int pxl_v;
       } data;
       struct frame *next, *prev;
};

#if     NeedFunctionPrototypes
#ifndef TEXXET
typedef long    (*set_char_proc)(WIDEARG(ubyte, int));
#else   /* TEXXET */
typedef void    (*set_char_proc)(WIDEARG(ubyte, int), WIDEARG(ubyte, int));
#endif  /* TEXXET */
#else   /* NeedFunctionPrototypes */
#ifndef TEXXET
typedef long    (*set_char_proc)();
#else   /* TEXXET */
typedef void    (*set_char_proc)();
#endif  /* TEXXET */
#endif  /* NeedFunctionPrototypes */

struct drawinf {        /* this information is saved when using virtual fonts */
       struct framedata data;
       struct font     *fontp;
       set_char_proc   set_char_p;
       struct tn       *tn_head;
       ubyte           *pos, *end;
       struct font     *virtual;
#ifdef  TEXXET
       int             dir;
#endif
};

EXTERN  struct drawinf  currinf;

/* entries below with the characters 'dvi' in them are actually stored in
  scaled pixel units */

#define DVI_H   currinf.data.dvi_h
#define PXL_H   pixel_conv(currinf.data.dvi_h)
#define DVI_V   currinf.data.dvi_v
#define PXL_V   currinf.data.pxl_v
#define WW      currinf.data.w
#define XX      currinf.data.x
#define YY      currinf.data.y
#define ZZ      currinf.data.z
#define ROUNDUP(x,y) (((x)+(y)-1)/(y))

EXTERN  int     current_page;
EXTERN  int     total_pages;
EXTERN  double  dimconv;
EXTERN  int     n_files_left    INIT(32767);    /* for LRU closing of fonts */
EXTERN  time_t  dvi_time;               /* last mod. time for dvi file */
EXTERN  int     page_w, page_h;

/*
* Table of page offsets in DVI file, indexed by page number - 1.
* Initialized in prepare_pages().
*/
EXTERN  long    *page_offset;

/*
* Mechanism for reducing repeated warning about specials, lost characters, etc.
*/
EXTERN  Boolean hush_spec       NTINIT(False);
EXTERN  Boolean hush_spec_now;
EXTERN  Boolean hush_chars      NTINIT(False);


/*
* Bitmap structure for raster ops.
*/
struct bitmap {
       short w, h;             /* width and height in pixels */
       short bytes_wide;       /* scan-line width in bytes */
       char *bits;             /* pointer to the bits */
};

/*
* Per-character information.
* There is one of these for each character in a font (raster fonts only).
* All fields are filled in at font definition time,
* except for the bitmap, which is "faulted in"
* when the character is first referenced.
*/
struct glyph {
       long addr;              /* address of bitmap in font file */
       long dvi_adv;           /* DVI units to move reference point */
       short x, y;             /* x and y offset in pixels */
       struct bitmap bitmap;   /* bitmap for character */
       short x2, y2;           /* x and y offset in pixels (shrunken bitmap) */
#ifdef  GREY
       XImage *image2;
       char *pixmap2;
#endif
       struct bitmap bitmap2;  /* shrunken bitmap for character */
};

/*
* Per character information for virtual fonts
*/
struct macro {
       ubyte   *pos;           /* address of first byte of macro */
       ubyte   *end;           /* address of last+1 byte */
       long    dvi_adv;        /* DVI units to move reference point */
       Boolean free_me;        /* if free(pos) should be called when */
                               /* freeing space */
};

/*
* The layout of a font information block.
* There is one of these for every loaded font or magnification thereof.
* Duplicates are eliminated:  this is necessary because of possible recursion
* in virtual fonts.
*
* Also note the strange units.  The design size is in 1/2^20 point
* units (also called micro-points), and the individual character widths
* are in the TFM file in 1/2^20 ems units, i.e., relative to the design size.
*
* We then change the sizes to SPELL units (unshrunk pixel / 2^16).
*/

#define NOMAGSTP (-29999)

#if     NeedFunctionPrototypes
typedef void (*read_char_proc)(struct font *, WIDEARG(ubyte, int));
#else
typedef void (*read_char_proc)();
#endif

struct font {
       struct font *next;              /* link to next font info block */
       char *fontname;                 /* name of font */
       float fsize;                    /* size information (dots per inch) */
       int magstepval;                 /* magstep number * two, or NOMAGSTP */
       FILE *file;                     /* open font file or NULL */
       char *filename;                 /* name of font file */
       unsigned short timestamp;       /* for LRU management of fonts */
       ubyte flags;                    /* flags byte (see values below) */
       ubyte maxchar;                  /* largest character code */
       double dimconv;                 /* size conversion factor */
       set_char_proc set_char_p;       /* proc used to set char */
               /* these fields are used by (loaded) raster fonts */
       read_char_proc read_char;       /* function to read bitmap */
       struct glyph *glyph;
               /* these fields are used by (loaded) virtual fonts */
       struct tn *vf_chain;            /* list of fonts used by this vf */
       struct font *first_font;        /* first font defined */
       struct macro *macro;
               /* I suppose the above could be put into a union, but we */
               /* wouldn't save all that much space. */
};

#define FONT_IN_USE     1       /* used for housekeeping */
#define FONT_LOADED     2       /* if font file has been read */
#define FONT_VIRTUAL    4       /* if font is virtual */

struct tn {
       struct tn *next;                /* link to next TeXnumber info block */
       int TeXnumber;                  /* font number (in DVI file) */
       struct font *fontp;             /* pointer to the rest of the info */
};

EXTERN  struct font     *font_head      INIT(NULL);
EXTERN  struct tn       *tn_head        INIT(NULL);
EXTERN  ubyte           maxchar;
EXTERN  unsigned short  current_timestamp INIT(0);

/*
* Command line flags.
*/

EXTERN  int     debug   INIT(0);

#define DBG_BITMAP      0x1
#define DBG_DVI         0x2
#define DBG_PK          0x4
#define DBG_BATCH       0x8
#define DBG_EVENT       0x10
#define DBG_OPEN        0x20
#define DBG_ALL         (DBG_BITMAP|DBG_DVI|DBG_PK|DBG_EVENT|DBG_OPEN)

EXTERN  Boolean list_fonts      NTINIT(False);

#ifndef BDPI
#define BDPI    300
#endif

EXTERN  int     pixels_per_inch NTINIT(BDPI);
EXTERN  int     offset_x, offset_y;
EXTERN  int     unshrunk_paper_w, unshrunk_paper_h;
EXTERN  int     unshrunk_page_w, unshrunk_page_h;
EXTERN  int     density         NTINIT(40);
EXTERN  double  specialConv;

EXTERN  char    *dvi_name       INIT(NULL);
EXTERN  FILE    *dvi_file;                              /* user's file */
EXTERN  _Xconst char    *alt_font       NTINIT(ALTFONT);
EXTERN  char    *prog;

struct  WindowRec {
       Window  win;
       int     shrinkfactor;
       int     base_x, base_y;
       int     width, height;
       int     min_x, max_x, min_y, max_y;     /* for pending expose events */
};

extern  struct WindowRec mane, alt, currwin;

#define WINDOW(wr)      ((Window) (wr).win)
#define shrink_factor   currwin.shrinkfactor

EXTERN  jmp_buf dvi_env;        /* mechanism to communicate dvi file errors */

#ifdef  GREY
#ifndef X10
EXTERN  Display *DISP;
EXTERN  Screen  *SCRN;
EXTERN  unsigned long   palette[17];
EXTERN  unsigned long   *pixeltbl;
EXTERN  Boolean use_grey        NTINIT(True);
#else   /* Sorry - GREY works only with X11 */
#undef  GREY
#endif  /* X10 */
#endif  /* GREY */

/********************************
*         Procedures           *
*******************************/

_XFUNCPROTOBEGIN
#if     NeedFunctionPrototypes

extern  void    line_btw(int, int, int, int);
extern  void    dot_at(int, int);
extern  void    do_attribute_path(int, int, int, int);
extern  void    put_bitmap(struct bitmap *, int, int);
#ifdef  GREY
extern  void    put_image(XImage *, int, int);
#endif
extern  void    put_rectangle(int, int, int, int, WIDEARG(Boolean, int));
extern  void    redraw_page(void);
#if     NeedVarargsPrototypes
extern  NORETURN void   oops(_Xconst char *, ...);
#else
extern  NORETURN void   oops();
#endif
extern  char    *xmalloc(unsigned, _Xconst char *);
extern  void    alloc_bitmap(struct bitmap *);
extern  FILE    *xfopen(_Xconst char *);
extern  unsigned long   num(FILE *, int);
extern  long    snum(FILE *, int);
extern  void    reset_fonts(void);
extern  void    realloc_font(struct font *, WIDEARG(ubyte, int));
extern  void    realloc_virtual_font(struct font *, WIDEARG(ubyte, int));
extern  void    load_font(struct font *);
extern  void    define_font(FILE *, WIDEARG(ubyte, unsigned int), struct font *,
                       struct tn **);
extern  void    init_page(void);
extern  void    open_dvi_file(void);
extern  Boolean check_dvi_file(void);
#ifndef TEXXET
extern  long    set_char(WIDEARG(ubyte, int));
extern  long    set_vf_char(WIDEARG(ubyte, int));
#else
extern  void    set_char(WIDEARG(ubyte, int), WIDEARG(ubyte, int));
extern  void    set_vf_char(WIDEARG(ubyte, int), WIDEARG(ubyte, int));
#endif
extern  void    draw_page(void);
extern  void    init_font_open(void);
extern  FILE    *font_open(_Xconst char *, char **,
                       WIDEARG(float, double), int *, int, char **);
extern  void    applicationDoSpecial(char *);
extern  void    read_PK_index(struct font *);
extern  void    read_GF_index(struct font *);
extern  void    read_PXL_index(struct font *);
extern  void    read_VF_index(struct font *);

#else   /* ! NeedFunctionPrototypes */

extern  void    line_btw();
extern  void    dot_at();
extern  void    do_attribute_path();
extern  void    put_bitmap();
#ifdef  GREY
extern  void    put_image();
#endif
extern  void    put_rectangle();
extern  void    redraw_page();
extern  NORETURN void   oops();
extern  char    *xmalloc();
extern  void    alloc_bitmap();
extern  FILE    *xfopen();
extern  unsigned long   num();
extern  long    snum();
extern  void    reset_fonts();
extern  void    realloc_font();
extern  void    realloc_virtual_font();
extern  void    load_font();
extern  void    define_font();
extern  void    init_page();
extern  void    open_dvi_file();
extern  Boolean check_dvi_file();
#ifndef TEXXET
extern  long    set_char();
extern  long    set_vf_char();
#else
extern  void    set_char();
extern  void    set_vf_char();
#endif
extern  void    draw_page();
extern  void    init_font_open();
extern  FILE    *font_open();
extern  void    applicationDoSpecial();
extern  void    read_PK_index();
extern  void    read_GF_index();
extern  void    read_PXL_index();
extern  void    read_VF_index();

#endif  /* NeedFunctionPrototypes */

#define one(fp)         ((unsigned char) getc(fp))
#define sone(fp)        ((long) one(fp))
#define two(fp)         num (fp, 2)
#define stwo(fp)        snum(fp, 2)
#define four(fp)        num (fp, 4)
#define sfour(fp)       snum(fp, 4)

_XFUNCPROTOEND