/* hacked for dvibj */

#ifndef lint
static char rcsid[] = "$Header: /ful/chris/ctex_dist/lib/RCS/pxl.c,v 1.7 85/04/14 02:56:03 chris Exp $";
#endif

/* Routines for manipulating PXL files---Vax version */

#ifndef TEXBIN
#error Please define TEXBIN giving the path to MakeTeXPK, e.g. "/usr/local/bin"
#endif

#ifndef PKPATH
#error Please define PKPATH giving the search path for fonts, e.g. ".:/tmp"
#endif

/* The functions DMagFactor, GenPXLFileName, and ReadPXLFile could go in
   separate files, but it's likely that any program that uses any one
   function uses all three. */

#include "pxl.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <math.h>

extern int errno;
extern char *sys_errlist[];

char *malloc (), *getenv ();
long  lseek ();

struct pxltail *ReadFontFile ();
struct pxltail *not_loaded ();
char errstr[128];

/*
 *  From DVIIMP:
 *
 *  A minor problem in specifying the sizes of scaled fonts arises
 *  because of the fact that magstep definitions are in terms of the
 *  rounded values based on the magnification times 1000.  For
 *  example, one willget different values for 1) a magnification of
 *  1200 as applied to a font scaled magstep4, and for 2) a
 *  magnification of 1000 as applied to a font scaled magstep5.  The
 *  following function provides the mechanism for resolving these
 *  differences by identifying the nearest match in terms of the
 *  overall actual magnification.
 *
 *  This is used in conjunction with the FONT_SLOP stuff to try to get
 *  the file names right .
 */

double reconcile_scale (double scale)
{
  double lg, nlg;
  double z = 0.0;

  if (scale <= 0) return scale;

  /* something below doesn't work for 1.0!?  I don't even care */
  if (scale == 1) return 1;

  lg = log (scale) / log (1.2);
  nlg = 0.5 * ((int) (2 * lg + 10000.5) - 10000);
  if (fabs (lg - nlg) < 0.01)
    return pow (1.2, nlg);
  else
    return scale;
}

/* Generate the name of a PXL font file, given the partial name 'nm',
   at the magnification 'magfactor', with design size 'designsize',
   a global mag factor of 'globalmag' (default 1000), and a fontname
   path of 'path' (default PKPATH).  Paths are defined as colon-
   separated strings (eg, "/usr/foo:/usr/bar") */

struct pxltail *read_font (nm, scale, dpi, path)
char *nm;			/* raw name, eg "cmr10" */
double scale;			/* 1.0 for true size, 1.2 for magstep1, etc */
int dpi;			/* device resolution, dots per inch */
char *path;			/* colon-separated search path */
{
    register char  *s,
		   *p;
    register int    pxmag,pkmag,/* expected magnification */
                    slop;	/* current slop index */
    char   *slash;		/* path name separator */
    char    pbuf[256];		/* expansion area for path components */
    static char pkfmt[] = "%s%s%s.%dpk";
    static char rv[256];
    int twice;

    scale = reconcile_scale (scale);
    pxmag = (int) (0.5 + dpi * scale * 5);
    pkmag = (int) (0.5 + dpi * scale);

    /* we may return here after running metafont to create a missing font */

    twice = 0;
  again:

 /* For some reason I used to look for slashes in 'nm', and suppress path
    expansion if there were any.  This seems awfully bogus, so I've changed
    it to suppress path expansion iff the font name starts with '/'.  Also,
    we no longer choke on font names with percent signs in them. */
    if (*nm == '/')
	slash = s = "";
    else {
	s = path;
	if (s == 0 || *s == 0)
	    s = PKPATH;
	slash = "/";
    }

 /* Tread the path in s, trying for the file, and testing "nearby" names */

    while (s) {
	p = pbuf;
	while (*s) {
	    if ((*p = *s++) == ':')
		break;
	    p++;
	}
	*p = 0;
	if (*s == 0)
	    s = 0;
	for (slop = 0; slop < FONT_SLOP; slop++) {
	    (void) sprintf (rv, pkfmt, pbuf, slash, nm, pkmag + slop);
	    if (access (rv, 4) == 0) return ReadFontFile (rv, PKFMT);
	    if (slop) {
		(void) sprintf (rv, pkfmt, pbuf, slash, nm, pkmag - slop);
		if (access (rv, 4) == 0) return ReadFontFile (rv, PKFMT);
	      }}}

    /* run metafont to make the desired font */

    if (! twice) {
      twice = 1;
      if (run_metafont (nm, pkmag, dpi))
	goto again; }
    
    return ReadFontFile (fontname (nm, scale), NOFMT);
}

run_metafont (const char *nm, int dpi, int bdpi)
{
  char buf[256];
  char cmd[256];
  int retval;

  sprintf (buf, TEXBIN "MakeTeXPK %s %d %d %.7g",
	   nm, dpi, bdpi, reconcile_scale ((double) dpi / bdpi));
#if 0
  fprintf (stderr, " \n[%s", buf);
  fflush (stderr);
#endif
  
  sprintf (cmd, "exec %s </dev/null >/dev/null", buf);
  retval = system (cmd);

#if 0
  fprintf (stderr, "]\n");
  fflush (stderr);
#endif

  return retval == 0;
}


char *fontname (name, scale)
    char *name;
    double scale;
{
   static char retval[128];
    int s = (int) (0.5 + 1000 * reconcile_scale (scale));
    if (s == 1000)
	strcpy (retval, name);
    else
	sprintf (retval, "%s scaled %d", name, s);
    return retval;
}

/* Read in a PK, [not]PXL, or [not]TFM font file.
   Return a pointer to a struct pxltail. */

struct pxltail *ReadFontFile (nm, fmt)
    char *nm;
    FONT_FORMAT fmt;
{
    register struct pxltail *px;
    register char  *p;
    register int fd;
    struct stat stat;

    /* read in the whole file */

    px = (struct pxltail *) malloc ((unsigned) sizeof (struct pxltail));
    if (px == 0) {
	error (1, errno, "can't read %s", nm); }
    bzero (px, sizeof (struct pxltail));

    p = (char *) malloc (1 + strlen (nm));
    if (p == 0) {
	error (1, errno, "can't read %s", nm); }
    strcpy (px->px_filename = p, nm);

    px->px_fmt = BADFMT;
    if (fmt == NOFMT) {
	strcpy (errstr, "not found");
	return px; }

    if ((fd = open (nm, 0)) < 0) return not_loaded (px);
    if (fstat (fd, &stat) < 0) return not_loaded (px);
    if ((stat.st_size & 3) != 0) {
	strcpy (errstr, "not loaded: file length bad");
	return px; }
    if ((p = malloc (stat.st_size)) == 0) return not_loaded (px);
    if (read (fd, p, stat.st_size) != stat.st_size) {
	free (p); return not_loaded (px); }
    (void) close (fd);

    switch (fmt) {
    case PKFMT:
	if (font_is_pk (px, p, stat.st_size)) return px;
	else break;
#if 0
    case PXLFMT:
	if (font_is_pxl (px, (long *) p, stat.st_size / 4)) return px;
	else break;
    case TFMFMT:
	if (font_is_tfm (px, (long *) p, stat.st_size / 4)) return px;
	else break;
#endif
    }

    free (p);
    strcpy (errstr, "not loaded: format is bad");
    return px;
}

struct pxltail *not_loaded (px) 
    struct pxltail *px;
{
    sprintf (errstr, "not loaded: %s", sys_errlist[errno]);
    return px;
}

#if 0
font_is_pxl (px, p, sz)
    struct pxltail *px;		/* pxltail to record info in */
    long *p;			/* hypothetical PXL file */
    int sz;			/* size in words */
{
    if (sz < 6 || p[0] != PXLID || p[sz-1] != PXLID)
	return 0;		/* not a PXL file */
    else {
	struct pxltail *ptail = (struct pxltail *) &p [sz - 5];
	struct chinfo *pch = (struct chinfo *) &p[ptail->px_dirpointer];
	struct chinfo *pxch = px->px_info;
	px->px_checksum = ptail->px_checksum;
	px->px_magnification = ptail->px_magnification;
	px->px_designsize = ptail->px_designsize;

	/* copy font directory -- up to 256 chars */

	if (&pch[256] < (struct chinfo *) ptail) {
	    ptail = (struct pxltail *) &pch[256]; }

	for (--pch; ++pch < (struct chinfo *) ptail; ++pxch) {
	    *pxch = *pch;	/* copy width, height, xoff, yoff, etc. */
	    if (pch->ch_rastoff != 0) {
		pxch->ch_raster = &p[pch->ch_rastoff]; }}

	px->px_fmt = PXLFMT; return 1; }
}
#endif
