#include	"defs.h"
#include	"commands.h"
#include	"dconv.h"
#include	"global.h"
#ifdef KPATHSEA
#include	<kpathsea/progname.h>
#include	<kpathsea/variable.h>
#include	<kpathsea/proginit.h>
#include	<kpathsea/tex-file.h>
#include	<kpathsea/tex-glyph.h>
#endif

#define	DVI2PATHENV	"DVI2DVIPATH"
#define	DVI2PATH	"."

#define	DVI2LIBENV	"DVI2DVILIB"
#define	DVI2LIB		"c:/usr/local/share/texmf/dvi2dvi"

#define	FONTDESCENV	"FONTDESCDVI"
#define	FONTDESC	"fontdesc"

/* used as drift */
#ifndef	RESOLUTION
#define	RESOLUTION	5
#endif
#ifndef PAGEREVERSE
#define	PAGEREVERSE	FALSE
#endif
#ifdef KPATHSEA
#define	KPSENAME	"k"
#else
#define	KPSENAME	""
#endif

void ReadPreAmble();
void ReadPostAmble();
void FindPostAmblePtr();
void GetFontDef();

/**********************************************************************/
/*************************  Global Variables  *************************/
/**********************************************************************/

int   FirstPage = -1000000;	/* first page to print (uses count0)	*/
int   LastPage = 1000000;	/* last page to print			*/

int   den;			/* denominator specified in preamble	*/
int   mag;			/* magnification specified in preamble	*/
int   num;			/* numerator specified in preamble	*/
int   usermag = 0;              /* user specified magnification		*/

char *dvi2path;			/* fontdesc library directories path	*/
char *dvi2lib;			/* fontdesc library directory		*/
char *fontdescfile;		/* default fontdesc file name		*/

int resolution = 0;

long  postambleptr;		/* pointer to the postamble		*/
long  fpagep;			/* pointer to the final page		*/

char dvifilename[PATHLEN];	/* DVI file name			*/
char dvidirpath[PATHLEN];	/* DVI file directory			*/
char rootname[PATHLEN];		/* DVI filename without extension	*/
FILE *dvifp  = NULL;		/* DVI file pointer			*/
FILE *outfp = NULL;		/* output file				*/

int   ncopies = 1;              /* number of copies to print		*/
int   ndone = 0;                /* number of pages converted		*/

#ifdef DEBUG
int debug = DEBUGoff;
#endif
int   PreLoad = TRUE;		/* preload the font descriptions?          */
int   Reverse = PAGEREVERSE;	/* process DVI pages in reverse order ?    */
int   G_errenc = FALSE;		/* has an error been encountered?          */
char *G_progname;		/* program name                            */
int   G_quiet = FALSE;		/* for quiet operation                     */
int   G_nowarn = FALSE;		/* don't print out warnings                */
int   G_removecomments = FALSE;	/* remove comments from included PS files  */
#ifdef MSDOS
int   G_longfontname = FALSE;	/* truncate file name to 8 characters      */
#endif
int SpecialSize;
char *SpecialStr;		/* "\special" strings	*/
#ifdef STATS
int   Stats = FALSE;		/* are we reporting stats ?                */
int   Snbpxl = 0;		/* # of bytes of pixel data                */
int   Sonbpx = 0;		/* "optimal" number of bytes of pixel data */
int   Sndc = 0;			/* # of different characters typeset       */
int   Stnc = 0;			/* total # of chars typeset                */
int   Snbpx0, Sndc0, Stnc0;	/* used for printing incremental changes per dvi page */
#endif


/**********************************************************************/
/*******************************  main  *******************************/
/**********************************************************************/

main(argc, argv)
int argc;
char *argv[];
{
    struct font_index *hdfontidx;
    struct font_entry *fe;
    int i;

#ifdef WIN32
    getlongname(argv[0]);
#endif
    G_progname = argv[0];
#ifdef KPATHSEA
    kpse_set_progname(G_progname);
#endif

#ifdef KPATHSEA
    if ((dvi2path = kpse_var_value(DVI2PATHENV)) == NULL)
#else
    if ((dvi2path = getenv(DVI2PATHENV)) == NULL)
#endif
      {
	fprintf(stderr, "Please define %s in texmf.cnf\n", DVI2PATHENV);
	dvi2path = DVI2PATH;
      }
#ifdef KPATHSEA
    if ((dvi2lib = kpse_var_value(DVI2LIBENV)) == NULL)
#else
    if ((dvi2lib = getenv(DVI2LIBENV)) == NULL)
#endif
      {
	fprintf(stderr, "Please define %s in texmf.cnf\n", DVI2LIBENV);
	dvi2lib = DVI2LIB;
      }
#ifdef KPATHSEA
    if ((fontdescfile = kpse_var_value(FONTDESCENV)) == NULL)
#else
    if ((fontdescfile = getenv(FONTDESCENV)) == NULL)
#endif
      {
	fprintf(stderr, "Please define %s in texmf.cnf\n", FONTDESCENV);
	fontdescfile = FONTDESC;
      }
    init_settings(argc, argv, fontdescfile);
    fix_default(RESOLUTION);
#ifdef KPATHSEA
    kpse_init_prog(G_progname, resolution, NULL, NULL);
    kpse_format_info[kpse_pk_format].program_enabled_p = false;
    kpse_format_info[kpse_gf_format].program_enabled_p = false;
    kpse_format_info[kpse_tfm_format].program_enabled_p = false;
#endif
    if (!G_quiet) {
	(void)fprintf(stderr, "%s\n", version);
	(void)fflush(stderr);
    }

    if ((i = getuint(dvifp, 1)) != PRE)
	Fatal("PRE doesn't occur first--are you sure this is a DVI file?");
    if ((i = getint(dvifp, 1)) != DVIFORMAT)
	Fatal("DVI format = %d, can only process DVI format %d files",
	      i, DVIFORMAT);
    SpecialSize = STRSIZE;
    if ((SpecialStr = malloc((unsigned)SpecialSize)) == NULL)
	Fatal("can't malloc space for special");

    dev_init();
    dfd_dconv_templ.dc_file = dvifp;
    dir = HOR;
    setcurdconv(&dfd_dconv_templ);
    if (Reverse || PreLoad) {
	ReadPostAmble(PreLoad, &hdfontidx);
	(void)fseek(dvifp, 14L, SEEK_SET);
    } else
	ReadPreAmble();
    skipbytes(dvifp, getuint(dvifp, 1));

    dev_setup();
    if (!G_quiet) {
#ifdef DEBUG
	if (Debuguser)
	    (void)fprintf(stderr, "\nPrescanning:\n");
	else
#endif
	    (void)fprintf(stderr, "\nPrescanning ");
	(void)fflush(stderr);
    }
    setcurfont(NULL);
    scanfont(PreLoad, &hdfontidx);

    if (!G_quiet) {
#ifdef DEBUG
	if (Debuguser)
	    (void)fprintf(stderr, "\nReading font info:\n");
	else
#endif
	    (void)fprintf(stderr, "\nReading font info ");
	(void)fflush(stderr);
    }
    for (fe = hdfontent; fe != NULL; fe = fe->next) {
	read_fontinfo(fe);
	if (fe->vert_use == VU_USED)
	    read_fontinfo(fe->vert_fe);
	if (!G_quiet) {
#ifdef DEBUG
	    if (Debuguser) {
	    } else {
#endif
		(void)putc('.', stderr);
		(void)fflush(stderr);
#ifdef DEBUG
	    }
#endif
	}
    }
    if (!G_quiet) {
#ifdef DEBUG
	if (Debuguser)
	    (void)fprintf(stderr, "\nGenerating output:\n");
	else
#endif
	    (void)fprintf(stderr, "\nGenerating output ");
	(void)fflush(stderr);
    }
    dev_endsetup();

    if (Reverse)
	(void)fseek(dvifp, fpagep, SEEK_SET);
    else {
	(void)fseek(dvifp, 14L, SEEK_SET);
	skipbytes(dvifp, getuint(dvifp, 1));
    }
    setcurfont(NULL);
    initdir();
    dviconv(hdfontidx);

    AllDone();
    /*NOTREACHED*/
}

default_def()
{
#ifdef KPATHSEA
    add_def0("TEXMF", kpse_var_value("TEXMF"));
#endif
    init_default(KPSENAME);
}

void
ReadPreAmble()
{
    num = getuint(dvifp, 4);
    den = getuint(dvifp, 4);
    mag = getuint(dvifp, 4);
#ifdef USEGLOBALMAG
    if (usermag > 0 && usermag != mag)
	(void)fprintf(stderr,
		"DVI magnification of %d over-ridden by user mag of %d\n",
		mag, usermag);
#endif
    if (usermag > 0)
	mag = usermag;
#ifndef USEGLOBALMAG
    if (mag != 1000)
	(void)fprintf(stderr, "Magnification of %d ignored.\n", mag);
#endif
}

void
ReadPostAmble(load, hdfip)
int load;
struct font_index **hdfip;
/***********************************************************************
    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.
***********************************************************************/
{
    FindPostAmblePtr(&postambleptr);
    if (getuint(dvifp, 1) != POST)
	Fatal("POST missing at head of postamble");
#ifdef DEBUG
    if (Debug)
	(void)fprintf(stderr, "got POST command\n");
#endif
    fpagep = getuint(dvifp, 4);
    num = getuint(dvifp, 4);
    den = getuint(dvifp, 4);
    mag = getuint(dvifp, 4);
#ifdef USEGLOBALMAG
    if (usermag > 0 && usermag != mag)
	(void)fprintf(stderr,
		"DVI magnification of %d over-ridden by user mag of %d\n",
		mag, usermag);
#endif
    if (usermag > 0)
	mag = usermag;
#ifndef USEGLOBALMAG
    if (mag != 1000)
	(void)fprintf(stderr, "Magnification of %d ignored.\n", mag);
#endif

    skipbytes(dvifp, 4);	/* height-plus-depth of tallest page */
    skipbytes(dvifp, 4);	/* width of widest page */
    if (getuint(dvifp, 2) >= STACKSIZE)
	Fatal("Stack size is too small");
    skipbytes(dvifp, 2);	/* number of pages in the DVI file */
#ifdef DEBUG
    if (Debug)
	(void)fprintf(stderr, "now reading font defs\n");
#endif
    if (load)
	GetFontDef(hdfip);
}

void
FindPostAmblePtr(postambleptr)
long *postambleptr;
/* this routine will move to the end of the file and find the start
    of the postamble */
{
    int i;

    (void)fseek(dvifp, 0L, SEEK_END);	/* goto end of file */
    *postambleptr = ftell(dvifp) - 4;
    (void)fseek(dvifp, *postambleptr, SEEK_SET);

    while (TRUE) {
	(void)fseek(dvifp, --(*postambleptr), SEEK_SET);
	if (((i = getuint(dvifp, 1)) != 223) &&
	    (i != DVIFORMAT) && (i != EXTDVIFORMAT))
	    Fatal("Bad end of DVI file");
	if (i == DVIFORMAT || i == EXTDVIFORMAT)
	    break;
    }
    (void)fseek(dvifp, (*postambleptr) - 4, SEEK_SET);
    (*postambleptr) = getuint(dvifp, 4);
    (void)fseek(dvifp, *postambleptr, SEEK_SET);
}


/*-->GetFontDef*/
/**********************************************************************/
/**************************** GetFontDef  *****************************/
/**********************************************************************/

void
GetFontDef(hdfip)
struct font_index **hdfip;
/***********************************************************************
   Read the font  definitions as they  are in the  postamble of the  DVI
   file.
***********************************************************************/
{
    int cmd;

    for (;;) {
	cmd = getuint(dvifp, 1);
	if (FNT_DEF1 <= cmd && cmd <= FNT_DEF4)
	    ReadFontDef(getuint(dvifp, cmd-FNT_DEF1+1), hdfip);
	else if (cmd == NOP)
	    ;
	else if (cmd == POST_POST)
	    return;
	else
	    Fatal("POST_POST missing after fontdefs");
    }
}
