/* findfile.c Copyright 1985 Massachusetts Institute of Technology Modified by
 * Kevin R. Coombes	 */

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

#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <dirent.h>
#include "struct.h"
#include "defs.h"

extern char *sprintf();
extern void Warning();

/**********************************************************************/
/**************************** FndFileInDir ****************************/
/**********************************************************************/
/* find a file in a single directory. Returns true if it found the file,
 * false otherwise. */
int
FndFileInDir(area, name, fp)
char *area;		/* directory to look in */
char *name;		/* e.g., cmr10 */
font_entry *fp;		/* font structure of e.g., cmr10.300 */
{
    char  s[BUFSIZ], buf[BUFSIZ];
    int   mag;

    mag = fp->font_mag;		/* for PK or GF fonts */
    (void) sprintf(s, "%s/SUBDIR", area);
    if (!access(s, 0))
	(void) sprintf(s, "%s/%s/%s", area, name, name);
    else
	(void) sprintf(s, "%s/%s", area, name);
#ifndef NO_PK
    (void) sprintf(buf, "%s.%dpk", s, mag);
    if (!access(buf, 4)) {
	(void) strcpy(fp->name, buf);
	fp->font_type = PKTYPE;
	return (-1);
    }
#endif NO_PK
#ifdef USEGF
    (void) sprintf(buf, "%s.%dgf", s, mag);
    if (!access(buf, 4)) {
	(void) strcpy(fp->name, buf);
	fp->font_type = GFTYPE;
	return (-1);
    }
#endif USEGF
#ifdef USEPXL
    mag = 5 * mag;		/* for PXL fonts */
    (void) sprintf(buf, "%s.%dpxl", s, mag);
    if (!access(buf, 4)) {
	(void) strcpy(fp->name, buf);
	fp->font_type = PXLTYPE;
	fp->font_mag = mag;
	return (-1);
    }
#endif USEPXL
    return (0);
}


/**********************************************************************/
/****************************** FindFile ******************************/
/**********************************************************************/
/* find a font file in a directory vector (path) */
/* true if it found a file, false otherwise */
int
FindFile(dirvec, dirveclen, area, name, fp)
char *dirvec[];		/* vector of directories to search */
int   dirveclen;	/* number of directories to search */
char *area;		/* absolute path name of first directory (optional) */
char *name;		/* font style and design size, e.g. cmr10 */
font_entry *fp;		/* font structure for e.g. cmr10.300 */
{
    int   i, point;
    char  family[STRSIZE];

    fp->ps_scale = 1.0;
    point = -1;
    (void) sscanf(name, "%[^0123456789.]%d", family, &point);

/* First check dir area given in DVI file */
    if (*area && FndFileInDir(area, name, fp))
	return (1);

/* Then check along dirvec */
    for (i = 0; i < dirveclen; i++)
	if (FndFileInDir(dirvec[i], name, fp))
	    return (1);

/* next check for closest magnification along dirvec */
    return (FindAnyFile(dirvec, dirveclen, family, point, name, fp));
}


/**********************************************************************/
/******************************* StrDiff ******************************/
/**********************************************************************/
/* measure difference in two strings representing font style names */
/* rather arbitrary */
int
StrDiff(s1, s2)
char *s1, *s2;
{
    register int diff = 0;

    while (*s1 && *s2)
	diff += abs(*s1++ - *s2++);
    while (*s1)
	diff += *s1++;
    while (*s2)
	diff += *s2++;
    return (diff);
}


/**********************************************************************/
/****************************** ScanDir ******************************/
/**********************************************************************/
/* scan a single directory for the best font file */
ScanDir(dir, family, point, mag,
  bestfamily, bestname, bestpoint, bestmag, besttype,
  min_df, min_dp, min_dm)
char *dir, *family, *bestfamily, *bestname;
int   point, mag, *bestpoint, *bestmag, *besttype, *min_df, *min_dp, *min_dm;
{
    DIR  *dirstream;
    struct dirent *dirrecord;
    char  qfamily[STRSIZE];
    int   qpoint, qmag, df, dp, dm, type, tmpmag;

    type = NONEXISTENT;
    tmpmag = mag;
    if (dirstream = opendir(dir)) {
	while (dirrecord = readdir(dirstream)) {
#ifndef NO_PK
	    if (!strcmp(dirrecord->d_name + dirrecord->d_namlen - 2, "pk"))
		type = PKTYPE;
#endif NO_PK
#ifdef USEGF
	    if (!strcmp(dirrecord->d_name + dirrecord->d_namlen - 2, "gf"))
		type = GFTYPE;
#endif USEGF
#ifdef USEPXL
	    if (!strcmp(dirrecord->d_name + dirrecord->d_namlen - 3, "pxl")) {
		type = PXLTYPE;
		tmpmag = 5 * mag;
	    }
#endif USEPXL
	    if (type != NONEXISTENT) {
		qpoint = -1;
		qmag = -1;
		(void) sscanf(dirrecord->d_name, "%[^0123456789.]%d.%d",
		  qfamily, &qpoint, &qmag);
		df = StrDiff(family, qfamily);
		dp = abs(point - qpoint);
		if (type != PXLTYPE)
		    dm = abs(mag - qmag);
		else
		    dm = (int) (abs(tmpmag - qmag) / 5);
		if ((df < *min_df)
		  || (df == *min_df && dp < *min_dp)
		  || (df == *min_df && dp == *min_dp && dm < *min_dm)) {
		    (void) sprintf(bestname, "%s/%s", dir, dirrecord->d_name);
		    (void) strcpy(bestfamily, qfamily);
		    *besttype = type;
		    *bestpoint = qpoint;
		    *bestmag = qmag;
		    *min_df = df;
		    *min_dp = dp;
		    *min_dm = dm;
		}
	    }
	}
	(void) closedir(dirstream);
    }
}


/**********************************************************************/
/****************************** ScanTree ******************************/
/**********************************************************************/
/* scan a font sub-directory tree for the best font file */
void
ScanTree(dir, name, family, point, mag,
  bestfamily, bestname, bestpoint, bestmag, besttype,
  min_df, min_dp, min_dm)
char *dir, *name, *family, *bestfamily, *bestname;
int   point, mag, *bestpoint, *bestmag, *besttype, *min_df, *min_dp, *min_dm;
{
    DIR  *dirstream;
    struct dirent *dirrecord;
    int   df;
    char  pdir[MAXNAMLEN];

    if (dirstream = opendir(dir)) {
	while (dirrecord = readdir(dirstream)) {
	    if (dirrecord->d_name[0] != '.') {
		df = StrDiff(name, dirrecord->d_name);
		if (df <= *min_df) {
		    (void) sprintf(pdir, "%s/%s", dir, dirrecord->d_name);
		    ScanDir(pdir, family, point, mag,
		      bestfamily, bestname, bestpoint, bestmag,
		      besttype, min_df, min_dp, min_dm);
		}
	    }
	}
	(void) closedir(dirstream);
    }
}


/**********************************************************************/
/***************************** FindAnyFile ****************************/
/**********************************************************************/
/* finds the best (in some vague sense) match to the desired font */
int
FindAnyFile(dirvec, dirveclen, family, point, name, fp)
font_entry *fp;
char *dirvec[], *family, *name;
int   dirveclen, point;
{
    char  foo[MAXNAMLEN], bestname[MAXNAMLEN], bestfamily[STRSIZE];
    int   min_df, min_dp, min_dm, i, bestpoint, bestmag, besttype, magwish;

    bestname[0] = '\0';
    min_df = min_dp = min_dm = 9999999;
    magwish = fp->font_mag;
    for (i = 0; i < dirveclen; i++) {
	(void) sprintf(foo, "%s/SUBDIR", dirvec[i]);
	if (!access(foo, 0))
	    ScanTree(dirvec[i], name, family, point, magwish,
	      bestfamily, bestname, &bestpoint, &bestmag, &besttype,
	      &min_df, &min_dp, &min_dm);
	else
	    ScanDir(dirvec[i], family, point, magwish,
	      bestfamily, bestname, &bestpoint, &bestmag, &besttype,
	      &min_df, &min_dp, &min_dm);
    }
    if (bestname[0]) {
	fp->ps_scale = (float) fp->font_mag / bestmag;
	(void) sprintf(foo, "%s%d", bestfamily, bestpoint);
	fp->font_mag = bestmag;
	fp->font_type = besttype;
	(void) strcpy(fp->name, bestname);
	if ((strcmp(bestfamily, family)
	    || bestpoint != point || abs(bestmag - magwish) > 2)) {
	    Warning("Substituted font %s at mag %d for %s at mag %d.\n",
	      foo, bestmag, name, magwish);
	    Warning("Scaled %f.\n", fp->ps_scale);
	}
	return (-1);
    }
    return (0);
}
