#ifndef lint
static char sccsid[] = "@(#)prelim.c	3.1\t11/16/89";
#endif lint
#define VERSION "3.1"

/**********************************************************************/
/***********************  external definitions  ***********************/
/**********************************************************************/
#include <stdio.h>
#include <strings.h>
#include "site.h"
#include "struct.h"
#include "defs.h"
#include "commands.h"

extern int  NoSignExtend(), SignExtend();
extern void Fatal(), Progress(), Warning();
extern void CopyFile(), GetBytes(), ReadFontDef();

extern FILE *dvifp;
extern FILE *outfp;
extern char  G_progname[];
extern char  G_outfname[];
extern char  filename[];
extern char  rootname[];
extern bool  C_create;
extern bool  C_header;
extern int   C_copies;
extern int   C_fontdensity;
extern char *G_headerfile;
extern char *PScmd[];
extern int   nps;
extern char *Ifile[];
extern int   nif;
extern bool  C_preload;
extern bool  C_reverse;
extern int   C_usermag;
extern long  ppagep;
extern char  n[];
extern int num, den, mag, hconv, vconv, hconvResolution, vconvResolution;
#ifdef DEBUG
extern bool C_debug;
#endif DEBUG

/**********************************************************************/
/************************  Forward Definitions  ***********************/
/**********************************************************************/
int     ChkOpt();
int     DoConv();
void	FindPostAmblePtr();
void	GetFontDef();
void    Preliminaries();
void	ReadPostAmble();

#ifdef CREOPT
FILE*   OpenOutput();
#endif CREOPT
#ifdef NOTDEF
void    PreScanGlobals();
#endif NOTDEF


long  postambleptr;		/* Pointer to the postamble		*/


/*********************************************************************/
/****************************** ChkOpt *******************************/
/*********************************************************************/
/* check a user supplied option for validity */

#define ISOPT(s) if( EQ(str,s) ) return( TRUE )

int
ChkOpt( str )
char    *str;
{
	ISOPT("note");	  /* its a shame to build this into the program */
	ISOPT("letter");
	ISOPT("legal");
	ISOPT("a4");
	ISOPT("landscape");
	ISOPT("draft");
	ISOPT("twoup");
	ISOPT("duplex");
	ISOPT("manualfeed");
	return( FALSE );
}


/*********************************************************************/
/********************************  DoConv  ***************************/
/*********************************************************************/
int
DoConv(convResolution)
{
    register float conv;

    conv = ((float)num/(float)den) *
#ifdef USEGLOBALMAG
	((float) mag/1000.0) *
#endif USEGLOBALMAG
	((float)convResolution/254000.0);
    return((int) (1.0 / conv + 0.5));
}


/**********************************************************************/
/************************  FindPostAmblePtr  **************************/
/**********************************************************************/
/* Move to the end of the file and find the start of the postamble */
void
FindPostAmblePtr()
{
    register int i;

    (void) fseek (dvifp, (long) 0, 2);
    postambleptr = ftell (dvifp) - 4;		/* Why not seek 4 from end? */
    (void) fseek (dvifp, postambleptr, 0);

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


/**********************************************************************/
/**************************** GetFontDef  *****************************/
/**********************************************************************/
/* Read the font definitions as they are in the postamble */
void
GetFontDef()
{
    unsigned char byte;

    while (((byte = NoSignExtend(dvifp, 1)) >= FNT_DEF1) && (byte <= FNT_DEF4))
	ReadFontDef (NoSignExtend(dvifp, (int)byte-FNT_DEF1+1));
    if (byte != POST_POST)
	Fatal ("POST_POST missing after fontdefs");
}


#ifdef CREOPT
/**********************************************************************/
/*************************** OpenOutput *******************************/
/**********************************************************************/
/* generate a unique file name and open it */

FILE*
OpenOutput()
{
	FILE*   fp;
#ifdef apollo
	long t;
	int  n = 0;
	char *p, *pp, b[256];
	int nd;

	time( &t );
	t = t % 100000;
	(void) strcpy( G_outfname, SPOOLFILE );
	(void) sprintf( b, "%s.%s.%x", logname(), rootname, t );
	if( (nd=strlen(b)-MAXFLEN) > 0 ) {
	       for(pp=(p=rindex(b,'.')); p && *p != '\0'; *(pp-nd) = *p++, pp++) ;
	       *(pp-nd) = '\0';
	       }
	(void) strcat( G_outfname, b );

	while( access(G_outfname,0) == 0 ) {
		n += 1;
		if (n > 10)
			Fatal( "Unable to create a unique output file name: %s\n", G_outfname );
		(void) strcpy( G_outfname, SPOOLFILE );
		(void) sprintf( b, "%s.%s.%x.%d", logname(), rootname, t, n );
		if( (nd=strlen(b)-MAXFLEN) > 0 ) {
			for(pp=(p=rindex(b,'.')); p && *p != '\0'; *(pp-nd) = *p++, pp++) ;
			*(pp-nd) = '\0';
			}
		(void) strcat( G_outfname, b );
		}
#else
	(void) strcpy (G_outfname, rootname);
	(void) strcat (G_outfname, ".ps");
#endif apollo
	if( (fp=fopen(G_outfname,"w")) == NULL )
		Fatal("Unable to create output file: %s\n", G_outfname);
	return( fp );
}
#endif CREOPT


/**********************************************************************/
/**************************  Preliminaries  ***************************/
/**********************************************************************/
void
Preliminaries()
{
    int k;

    Progress("This is dvi2ps, version %s\n", VERSION);

#ifdef apollo
    set_sbrk_size(2048*1024);
#endif apollo

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

#ifdef CREOPT
    if (C_create) outfp = OpenOutput();
    else
#endif CREOPT
	outfp = stdout;

/* it is important that these be the very first things output !!! */

    if (C_header) CopyFile(G_headerfile);
    for (k = 0; k < nif; k++)      /* copy all included files */
	CopyFile(Ifile[k]);

    EMIT(outfp, "%%%%Title: %s\n", filename);
    EMIT(outfp, "%%%%Creator: %s %s\n", G_progname, VERSION);
    EMITS("%%EndProlog\n");
    EMITS("TeXDict begin @start\n");

#ifdef NOTDEF
    PreScanGlobals();
#endif NOTDEF

    for (k = 0; k < nps; k++)  /* prefix valid PostScript options with "@" */
	if( ChkOpt(PScmd[k]) )
	    EMIT(outfp, "@%s\n", PScmd[k]);
	else
	    Fatal("%s is an invalid PostScript option\n", PScmd[k]);

    if( C_copies > 1 ) EMIT(outfp, "%d @copies\n", C_copies);

/* Send the resolution to the PostScript file */
    EMIT(outfp, "%d @startdoc\n", C_fontdensity);

    if (C_reverse) {
	ReadPostAmble(C_preload);
	(void) fseek(dvifp, ppagep, 0);
    } else {
	if (C_preload) {
	    ReadPostAmble(TRUE);
	    (void) fseek(dvifp, (long) 14, 0);
        } else {
    	    num = NoSignExtend(dvifp, 4);
    	    den = NoSignExtend(dvifp, 4);
    	    mag = NoSignExtend(dvifp, 4);
#ifdef USEGLOBALMAG
	    if( C_usermag > 0 && C_usermag != mag )
		Warning("DVI mag of %d over-ridden by user mag of %d\n",
			mag, C_usermag );
#endif USEGLOBALMAG
	    if( C_usermag > 0 ) mag = C_usermag;
#ifndef USEGLOBALMAG
	    if( mag != 1000 ) Warning("Magnification of %d ignored.\n", mag);
#endif USEGLOBALMAG
    	    hconv = DoConv(hconvResolution);
    	    vconv = DoConv(vconvResolution);
	    }
	k = NoSignExtend(dvifp, 1);
	GetBytes(dvifp, n, k);		/* Skip over DVI comment */
	}
}

#ifdef NOTDEF
/**********************************************************************/
/**************************  PreScanGlobals  **************************/
/**********************************************************************/
void
PreScanGlobals()
{
    (void) fseek(dvifp, (long) 14, 0);
    realpage = FALSE;
    do {
	switch(command = NoSignExtend(dvifp, 1)) {
	case XXX1: case XXX2: case XXX3: case XXX4:
	    k = NoSignExtend(dvifp, command-XXX1+1);
	    GetBytes(dvifp, SpecialStr, k);
	    DoGlobal(SpecialStr, k);
	    break;
	case SET1: case SET2: case SET3: case SET4:
	case PUT1: case PUT2: case PUT3: case PUT4:
	case SET_RULE:
	case PUT_RULE:
	case FNT1: case FNT2: case FNT3: case FNT4:
	case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4:
	    realpage = TRUE;
	case PRE:
	    Fatal("PRE occurs within file");
	case POST:
	    Fatal("POST occurs before any EOP");
	    break;
	case POST_POST:
 	    Fatal("POST_POST with no preceding POST");
	    break;
	default:
	    break;
	}
    } while(command != EOP)
}
#endif NOTDEF


/**********************************************************************/
/**************************  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. */
void
ReadPostAmble(load)
int load;
{
    FindPostAmblePtr();
    if (NoSignExtend(dvifp, 1) != POST)
	Fatal("POST missing at head of postamble");
#ifdef DEBUG
    if (C_debug) (void) fprintf (stderr, "got POST command\n");
#endif DEBUG
    ppagep = NoSignExtend(dvifp, 4);
    num = NoSignExtend(dvifp, 4);
    den = NoSignExtend(dvifp, 4);
    mag = NoSignExtend(dvifp, 4);
#ifdef USEGLOBALMAG
    if (C_usermag > 0 && C_usermag != mag)
	Warning("DVI magnification of %d over-ridden by user mag of %d\n",
		mag, C_usermag);
#endif USEGLOBALMAG

    if (C_usermag > 0) mag = C_usermag;

#ifndef USEGLOBALMAG
    if (mag != 1000) Warning("Magnification of %d ignored.\n", mag);
#endif USEGLOBALMAG

    hconv = DoConv(hconvResolution);
    vconv = DoConv(vconvResolution);

    (void) NoSignExtend(dvifp, 4);	/* height-plus-depth of tallest page */
    (void) NoSignExtend(dvifp, 4);	/* width of widest page */
/* Should these be used to give BB information to PS file? */
    if (NoSignExtend(dvifp, 2) >= MAXPUSHES)
	Fatal ("Stack size is too small");
    (void) NoSignExtend(dvifp, 2);	/* read number of pages in DVI file */
#ifdef DEBUG
    if (C_debug) (void) fprintf(stderr, "now reading font defs");
#endif DEBUG
    if (load) GetFontDef();
}


