/* findfile.c */
/* Copyright 1985 Massachusetts Institute of Technology */
/* modified by Peter Damron 1987 University of Washington */
/*---------------------------------------------------------------------*/
#ifndef lint
static char rcsid[] = "$Header: findfile.c,v 2.0 88/06/07 15:02:38 peterd Rel2 $";
#endif lint
/*---------------------------------------------------------------------*/

#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/dir.h>
#include "findfile.h"

#ifndef TRUE
#define TRUE -1
#define FALSE 0
#endif TRUE

/* normally defined in <sys/dir.h>, but just to make sure */
#ifndef MAXNAMLEN
#define MAXNAMLEN 255
#endif MAXNAMLEN

/*---------------------------------------------------------------------*/
/* find a font file in a single directory */
/* true if it found the font file, false otherwise */
/* s is the return filename string, if found (e.g. area/stylepoint.maggf */
/* area is directory to look in */
/* style is the font style (e.g. cmr) */
/* point is the design point size of the font */
/* mag is the magnification - adjusted for this dpi and font format */

int
FindFileInDir(area, style, point, mag, s)
    char *area,*style,*s;
    int point,mag;
{
    FILE *f;
    char buf[MAXNAMLEN];
    int found = 0;

    /* presence of file "SUBDIR" means subdirectory per font style */
    sprintf(s,"%s/SUBDIR",area);

#ifdef USEPXL
    if (!access(s,F_OK)) {
	sprintf(s,"%s/%s/%s%d.%dpxl",area,style,style,point,mag);
    } else {
	sprintf(s,"%s/%s%d.%dpxl",area,style,point,mag);
    }
#else not USEPXL
    if (!access(s,F_OK)) {
	sprintf(s,"%s/%s/%s%d.%dgf",area,style,style,point,mag);
    } else {
	sprintf(s,"%s/%s%d.%dgf",area,style,point,mag);
    }
#endif USEPXL

    if (!access(s,R_OK)) {
	/* font file is there and we can read it */
	return(TRUE);
    }

    /* font file is not there */
    /* try to write out a message to "NEEDED" file */
    sprintf(buf,"%s/NEEDED",area);
    if (!access(buf,W_OK)) {
#ifdef USEPXL
	sprintf(s,"%s%d.%dpxl\n",style,point,mag);
#else not USEPXL
	sprintf(s,"%s%d.%dgf\n",style,point,mag);
#endif USEPXL
	f = fopen(buf,"r+");
	while (fgets(buf,sizeof(buf),f)) {
	    if (!strcmp(buf,s)) {
		found++;
	    }
	}
	if (!found) fputs(s,f);
	fclose(f);
    }
    return(FALSE);
}

/*---------------------------------------------------------------------*/
/* find a font file in a directory vector (path) */
/* true if it found a font file, false otherwise */
/* s is the return filename string, if found (e.g. area/stylepoint.maggf */
/* dirvec is a vector of directory strings */
/* dirveclen is the length of dirvec vector */
/* area is the first directory to search */
/* name is the font style and font design size concatenated */
/* mag is the magnification spec - modified for dpi and font format */
/* s is the return filename string */
/* nname is the return name if a substitution is made */
/* nmag is the return magnification if a substitution is made */

int FindFontFile(dirvec,dirveclen,name, mag, s, nname, nmag)
    char *dirvec[],*name,*s,*nname;
    int dirveclen,mag,*nmag;
{
    int i,point;
    char style[MAXNAMLEN];

    /* default is to use the input name and mag as the output name and mag */
    strcpy(nname,name);
    *nmag = mag;

    /* break the font name into style and design point size */
    point = -1;
    (void) sscanf(name,"%[^0123456789.]%d",style,&point);

#ifdef NOTDEF
    /* should check these values here */
    Warning("internal - find font %s style %s point %d mag %d\n",
		name,style,point,mag);
#endif NOTDEF

    /* First check dir area given in DVI file */
    /* Then check along dirvec */
    for (i = 0; i < dirveclen; i++)  {
	if (FindFileInDir(dirvec[i], style, point, mag, s)) {
	    return(TRUE);
	}
    }

    /* next check for closest magnification along dirvec */
    /* note: no check in area here */
    return(FindAnyFile(dirvec,dirveclen,style,point,mag,name,s,nname,nmag));
}

/*---------------------------------------------------------------------*/
/* find out how similar two strings are */
/* used to compare font style names */
/* rather an arbitrary measure */
/* e.g. may not have anything to do with how similar two fonts are */

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);
}

/*---------------------------------------------------------------------*/
/* scan a single directory for the best font file */

ScanDir(dir,
	 style,point,mag,
	 beststyle,bestname,bestpoint,bestmag,
	 min_ds,min_dpm,min_dp)
    char *dir,*style,*beststyle,*bestname;
    int point,mag,*bestpoint,*bestmag,*min_ds,*min_dpm,*min_dp;
{
    DIR *dirstream;		/* stream of file records in this dir */
    register struct direct *dirrecord;	/* pointer to a file record */
    char qstyle[MAXNAMLEN];	/* style name of current file */
    int qpoint;			/* point size of current file */
    int qmag;			/* mag size of current file */
    register int ds;			/* local delta in style */
    register int dpm;			/* local delta in point*mag */
    register int dp;			/* local delta in point */

    /* go through the files in this directory */
    if (dirstream = opendir(dir)) {
	while (dirrecord = readdir(dirstream)) {
#ifdef USEPXL
	    /* only use *pxl files */
	    if (!strcmp(dirrecord->d_name+dirrecord->d_namlen-3,"pxl")) {
#else not USEPXL
	    /* only use *gf files */
	    if (!strcmp(dirrecord->d_name+dirrecord->d_namlen-2,"gf")) {
#endif USEPXL
		/* parse the filename into style, point, mag */
		qpoint = -1; qmag = -1;
		(void) sscanf(dirrecord->d_name,"%[^0123456789.]%d.%d",
			      qstyle,&qpoint,&qmag);
		/* compute differences */
		ds = StrDiff(style,qstyle);
		dpm = abs((point*mag) - (qpoint*qmag));
		dp = abs(point - qpoint);
#ifdef NOTDEF
		dm = abs(mag - qmag);
#endif NOTDEF
		/* check for a better font than before */
		if ((ds < *min_ds)
		    || (ds == *min_ds && dpm <= *min_dpm)
		    || (ds == *min_ds && dpm == *min_dpm && dp <= *min_dp)) {
			sprintf(bestname,"%s/%s",dir,dirrecord->d_name);
			strcpy(beststyle,qstyle);
			*bestpoint = qpoint;
			*bestmag = qmag;
			*min_ds = ds;
			*min_dpm = dpm;
			*min_dp = dp;
		}
	    }
	}
	closedir(dirstream);
    }
}

/*---------------------------------------------------------------------*/
/* scan a font sub-directory tree for the best font file */

ScanTree(dir,name,
	style,point,mag,
	beststyle,bestname,bestpoint,bestmag,
	min_ds,min_dpm,min_dp)
    char *dir,*name,*style,*beststyle,*bestname;
    int point,mag,*bestpoint,*bestmag,*min_ds,*min_dpm,*min_dp;
{
    DIR *dirstream;
    struct direct *dirrecord;
    int ds;
    char pdir[MAXNAMLEN];

    if (dirstream = opendir(dir)) {
	while (dirrecord = readdir(dirstream)) {
	    if (dirrecord->d_name[0] != '.') {
		ds = StrDiff(name,dirrecord->d_name);
		if (ds <= *min_ds) {
		    sprintf(pdir,"%s/%s",dir,dirrecord->d_name);
		    /* try this sub-directory */
		    ScanDir(pdir,
			    style,point,mag,
			    beststyle,bestname,bestpoint,bestmag,
			    min_ds,min_dpm,min_dp);
		    /* we should update min_ds at this point */
		    /* but we rely on ScanDir to do that */
		}
	    }
	}
	closedir(dirstream);
    }
}

/*---------------------------------------------------------------------*/
/* finds the best match to the desired font */
/* searches through directory vector (path) */
/* best in what sense ??? */

int FindAnyFile(dirvec,dirveclen,style,point,mag,name,s,nname,nmag)
    char *dirvec[],*style,*name,*s,*nname;
    int dirveclen,point,mag,*nmag;
{
    char foo[MAXNAMLEN];	/* temp file name string */
    char bestname[MAXNAMLEN];	/* best font file name string */
    char beststyle[MAXNAMLEN];	/* best font style name string */
    int i;		/* temp index into directory vector */
    int bestpoint;	/* best font point size */
    int bestmag;	/* best font magnification size */
    int min_ds;		/* minimum delta found in font sytle name string */
    int min_dpm;	/* minimum delta found in font point*mag */
    int min_dp;		/* minimum delta found in font point */
	
    bestname[0] = '\0'; 
    min_ds = min_dpm = min_dp = 9999999;
    for (i = 0; i < dirveclen; i++) {
	/* check for font sub-directory tree (not flat) */
	sprintf(foo,"%s/SUBDIR",dirvec[i]);
	if (!access(foo,F_OK)) {
	    ScanTree(dirvec[i],name,
		    style,point,mag,
		    beststyle,bestname,&bestpoint,&bestmag,
		    &min_ds,&min_dpm,&min_dp);
	} else {
	    ScanDir(dirvec[i],
		    style,point,mag,
		    beststyle,bestname,&bestpoint,&bestmag,
		    &min_ds,&min_dpm,&min_dp);
	}
    }
    if (bestname[0]) {
	/* well we found something that looks ok */
	/* get return values: s, nname, nmag */
	if (bestpoint > 0) {
	    sprintf(nname,"%s%d",beststyle,bestpoint);
	} else {
	    /* does this ever get used? this looks bad */
	    strcpy(nname,beststyle);
	}
	*nmag = bestmag;
	strcpy(s,bestname);
	/* issue a warning if we are doing a substitution */
	if ((strcmp(beststyle,style)
	    || bestpoint != point || abs(bestmag - mag) > 2)) {
#ifdef NOTDEF
		Warning("Substituted font %s at mag %d for %s at mag %d\n",
		      nname,(bestmag * 4 + 3) / 6,
		      name,(mag * 4 + 3) / 6);
		      /* is this message very useful? */
		      /* why the magic numbers? */
		/* this message could be better */
		Warning("Substituted font %s at mag %d for %s at mag %d\n",
		      nname,bestmag,name,mag);
#endif NOTDEF
#ifdef USEPXL
		Warning("Substituted font %s%d.%dpxl -> %s\n",style,point,mag,s);
#else not USEPXL
		Warning("Substituted font %s%d.%dgf -> %s\n",style,point,mag,s);
#endif USEPXL
	}
	return(TRUE);
    }
    return(FALSE);
}

/*---------------------------------------------------------------------*/

