#ifdef BUILTIN

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

/**********************************************************************/
/*************************  External Definitions  *********************/
/**********************************************************************/
#include <stdio.h>
#include <strings.h>
#include "site.h"
#include "struct.h"
#include "defs.h"

#define PS_FID (FILE *)-3
#define INFTY  99999

extern float ActualFactor();
extern void Warning(), Fatal();
extern char *malloc(), *sprintf();

extern FILE *outfp;
extern char *tfmdirs[];
extern int   ntfmdirs;
extern int   mag, num, den, hconv;
extern int   G_temporary, G_permanent;
#ifdef BUDGET
extern int budget;
#endif BUDGET


/**********************************************************************/
/**************************  Forward Definitions  *********************/
/**********************************************************************/
struct BuiltIn *IsBuiltIn();
void  LoadBuiltIn();
char *PSname();
void  ReadBuiltIn();
void  ReadPSMap();
void  InitPSFont();
char *PSFname();
void  SetPSFont();
int   FirstChar();
int   MoreChar();

struct BuiltIn *BuiltIns;	/* Names of the LaserWriter built-in fonts  */
int    curpsf;			/* what number is the current ps packed font */
char   buf[256];
int    packpsfont = MINPACKPSFONT-1;
int    packpschar = NPACKPSCHARS-1;

/**********************************************************************/
/*******************************  IsBuiltIn  **************************/
/**********************************************************************/
struct BuiltIn *
IsBuiltIn(a)
char *a;
{
    struct BuiltIn *c;

    for (c = BuiltIns; c; c = c->next) {
	if (strcmp(c->TeXname, a) == 0)
	    return(c);
	else if (c->prefix == TRUE && c->defined == INFTY
	  && strncmp(c->TeXname, a, c->length) == 0)
	    return(c);
    }
    return((struct BuiltIn *)0);
}


/**********************************************************************/
/******************************  LoadBuiltIn  *************************/
/***********************************************************************
	Font Size  =  ActualFactor(mag) * s/d * Normal Size 

	Normal Size is	     d		(DVI UNITS) 
			   * num/den	(10^-7 metres) 
			   / 10^-5	(centimetres) 
			   / 2.54	(inches)
			   * 300	DOTS
************************************************************************/
void
LoadBuiltIn(fp)
font_entry *fp;
{
    register int i;
    struct BuiltIn *bi;
    float  psfontsize;

    if (fp->font_type != PSTYPE)  return;
    if (fp->defined == G_permanent)  return;
/* if this font has a special init string (like a small caps font), output that
 * string.  Then zero the init so we only do it once per font type (otherwise
 * we'll try to do it once per size).
 */
    if ((bi = IsBuiltIn(fp->n)) && bi->Init[0] && bi->defined < G_permanent) {
	EMIT(outfp, "/%s %s\n", bi->Postscript, bi->Init);
	bi->defined = G_permanent;
    }

    psfontsize = ActualFactor(mag) * fp->s * num / den / 2540.0 * 3.0;
    if (bi->defined == INFTY)
	EMIT(outfp, "/%s /%s %f @texmakefont\n", fp->psname, PSname(fp->n), 
	   psfontsize);
    else
	EMIT(outfp, "/%s %f /%s /%s @ps2texfont\n", fp->psname, psfontsize,
	   PSname(fp->n), fp->n);

    for (i = FIRSTFNTCHAR; i <= LASTFNTCHAR; i++)
	fp->ch[i].where.isloaded = G_permanent;
    fp->ncdl++;
    fp->defined = G_permanent;
#ifdef BUDGET
    budget -= fontcost(fp);
#endif BUDGET
    return;
}


/**********************************************************************/
/*****************************  PSname  *******************************/
/**********************************************************************/
char *
PSname(a)
char *a;
{
    struct BuiltIn *c;

    for (c = BuiltIns; c; c = c->next) {
	if (strcmp(c->TeXname, a) == 0)
	    return (c->Postscript);
	else if (c->prefix == TRUE
	  && strncmp(c->TeXname, a, c->length) == 0)
	    return(a);
    }
    return ("<NULLFONT>");
}


/**********************************************************************/
/******************************  ReadBuiltIn  *************************/
/**********************************************************************/
void
ReadBuiltIn(fp)
font_entry *fp;
{
    struct BuiltIn *bi;
    char  tfmname[STRSIZE];
    FILE *tfmfl = NULL;
    register int i;
    int   lh;			/* header length */
    int   bc;			/* smallest character code */
    int   ec;			/* largest character code */
    int   nw;			/* number of words in width table */
    int   tfmwidth[NFNTCHARS];
    int   v;
    double z = (double) fp->s / (double) 1048576.;
    double tw;

    (void) sprintf(fp->psname, "%s.%d", fp->n, fp->font_mag);
    fp->font_file_id = PS_FID;

    if ((bi = IsBuiltIn(fp->n)) && bi->onewidth == TRUE) {
	for (i = bi->predef.firstchar; i < bi->predef.lastchar; ++i)
	    fp->ch[i].tfmw = bi->predef.tfmw;
	fp->font_type = PSTYPE;
	return;
    }

/*** Read in TFM widths from TFM file (not PXL file) ***/
    for (i = 0; i < ntfmdirs && tfmfl == NULL; ++i) {
	(void) strcpy(tfmname, tfmdirs[i]);
	(void) strcat(tfmname, "/");
	(void) strcat(tfmname, fp->n);
	(void) strcat(tfmname, ".tfm");
	tfmfl = fopen(tfmname, "r");
    }
    if (tfmfl == NULL) {
	fp->font_file_id = NO_FILE;
	Warning("Can't find LaserWriter TFM file %s\n", tfmname);
	return;
    }

    (void) fseek(tfmfl, 2L, 0);		/* ignore total file length */
    lh = NoSignExtend(tfmfl, 2);
    bc = NoSignExtend(tfmfl, 2);
    ec = NoSignExtend(tfmfl, 2);
    nw = NoSignExtend(tfmfl, 2);
    (void) fseek(tfmfl, (long) (24 + (lh + ec - bc + 1) * 4), 0);
				/* skip to beginning of width table */
    for (i = 0; i < nw; i++) {
	tw = (double) SignExtend(tfmfl, 4);
	tfmwidth[i] = (int) (tw * z);
    }
    (void) fseek(tfmfl, (long) lh * 4 + 24, 0);	/* skip to character info */
    for (i = bc; i <= ec; i++) {
	v = tfmwidth[NoSignExtend(tfmfl, 1)];
	fp->ch[i].tfmw = v;
	fp->ch[i].dx = PixRound(v, hconv);
	(void) getc(tfmfl);	/* ignore height, depth, italic, tag */
	(void) getc(tfmfl);	/* should this be changed for asian fonts? */
	(void) getc(tfmfl);
    }
    (void) fclose(tfmfl);
    fp->font_type = PSTYPE;
    return;
}


/**********************************************************************/
/***************************  ReadPSMap  ******************************/
/**********************************************************************/
void
ReadPSMap()
{
    FILE *map;
    char  first[STRSIZE], second[STRSIZE], third[STRSIZE], init[STRSIZE];
    char  c, *sp;
    struct BuiltIn *p = 0, *q;
    int   line, status;

    if ((map = fopen(FONTMAP, "r")) == NULL) {
	Warning("Can't open TeX->PostScript font map %s\n", FONTMAP);
	BuiltIns = (struct BuiltIn *) 0;
	return;
    }
    line = 1;
    while ((status = fscanf(map, "%s %s", first, second)) == 2) {
	sp = third;
	while ((c=getc(map)) != '\n' && sp-third < STRSIZE)
	    *sp++ = c;
	(void) ungetc(c, map);
	*sp = '\0';
	sp = third;
	while (*sp == ' ' || *sp == '\t' || *sp == '\n') ++sp;
	q = NEW(struct BuiltIn);
	q->next = (struct BuiltIn *) 0;
	q->prefix = FALSE;
	q->defined = FALSE;
	q->onewidth = FALSE;
	q->Init[0] ='\0';
	(void) strcpy(q->TeXname, first);
	if (strncmp(second, "prefix", 6) == 0) {
	    q->prefix = TRUE;
	    q->length = strlen(first);
	    if (strncmp(sp, "downloaded", 10) == 0) {
		q->defined = INFTY;
		sp += 10;
		if (*sp) {
		    while (*sp == ' ' || *sp == '\t' || *sp == '\n') ++sp;
		    if (strncmp(sp, "onewidth", 8) == 0) {
			q->onewidth = TRUE;
			status = sscanf(sp+9, "%hd %hd %d",
			    &(q->predef.firstchar), &(q->predef.lastchar),
			    &(q->predef.tfmw));
			if (status != 3) break;
		    } else break;
		}
	    } else if (strncmp(sp, "onewidth", 8) == 0) {
		q->onewidth = TRUE;
		status = sscanf(sp+9, "%hd %hd %d",
		    &(q->predef.firstchar), &(q->predef.lastchar),
		    &(q->predef.tfmw));
		if (status != 3) break;
	    } else if (*sp) break;
	} else {
	    (void) strcpy(q->Postscript, second);
	    if (third[0]) {
		status = sscanf(third, " \"%[^\n\"']\"", init);
		if (status == 1) (void) strcpy(q->Init, init);
		else break;
	    } else
		q->Init[0] = 0;
	}
	if (p) p->next = q;
	else BuiltIns = q;
	p = q;
	line++;
    }
    if (status != EOF)
	Fatal("Syntax error in %s, line %d\n", FONTMAP, line);
    (void) fclose(map);
    return;
}


void
InitPSFont()
{
    curpsf = 0;
    return;
}


char *
PSFname(psf)
int psf;
{
    if(psf >= MINPACKPSFONT)
	(void) sprintf(buf, "F%d", psf-MINPACKPSFONT);
    else
	(void) sprintf(buf, "f%d", psf);
    return(buf);
}

void
SetPSFont(fep, c)
font_entry *fep;
int c;
{
    char_entry *ce;
    int psf;

    ce = &(fep->ch[c]);
    if (ce->pschar == NONCHAR) {
	if(++packpschar >= NPACKPSCHARS) {
	    packpsfont++;
	    packpschar = 0;
	}
	if(packpschar == 0) {
#ifdef BUDGET
	    budget -= fontcost(fep);
#endif BUDGET
	    EMIT(outfp, "1.0 /%s @newfont\n", PSFname(packpsfont));
	}
	ce->psfont = packpsfont;
	ce->pschar = packpschar;
	if (fep->defined < G_permanent)
	    fep->defined = G_permanent;
    }
    if(curpsf != (psf = ce->psfont)) {
	EMIT(outfp, "%s @sf\n", PSFname(psf));
	curpsf = psf;
    }
}


int
FirstChar(fep, c)
font_entry *fep;
int c;
{
    char_entry *cep;

    cep = &(fep->ch[c]);
    SetPSFont(fep, c);
    return(cep->psfont);
}

int
MoreChar(fep,c)
font_entry *fep;
int c;
{
    char_entry *cep;

    cep = &(fep->ch[c]);
    if (cep->psfont == NONFONT && ++packpschar >= NPACKPSCHARS)
	return(0);
    else if (cep->pschar == NONCHAR) {
	cep->psfont = curpsf;
	cep->pschar = packpschar;
    }
    return(cep->psfont); 
}
#endif BUILTIN
