/*
*      font_open.c(font, font_ret, mag, mag_ret, magstepval, name)
*      Find and open gf, pk, or pxl files in the given path, having the given
*      name and magnification.  It tries gf files first, followed by pk and pxl
*      files.  The path variable should be of the form path1:path2:...:pathn,
*      and each of the paths will be tried successively.  Strings in pathi of
*      the form %f, %p, and %d will be replaced by the font name, "gf" or "pk"
*      or "pxl", and the magnification, respectively.  If no %f appears in a
*      path specifier, then the string "/%f.%d%p" is added on the end.  This
*      procedure is repeated for each of the possible magnifications allowed,
*      and if it fails then the procedure will try changing the point size
*      as well.  If all of the above fails, then alt_font will be tried.
*
*      If the variable SEARCH_SUBDIRECTORIES is set, then the environment
*      variable TEXFONTS_SUBDIR and the #define variable DEFAULT_SUBDIR_PATH
*      will be enabled, as well as ``*'' and ``**'' specifiers.  The
*      SUBDIR_PATH things will be appended to the end of the usual path, with
*      a `*' at the end of each component.  The `*' means that subdirectories
*      will be searched up to one level; `**' means that subdirectories
*      will be recursively searched to any level.  Neither specifier may be
*      preceded by a `%' specifier (after the most recent colon).
*
*      If the file is found, then a file pointer is returned, and the following
*      values are set:
*              *font_ret  a pointer to a string containing the font name (if
*                      different from the font requested).
*              *mag_ret  the actual magnification found.
*              *name   a pointer to a string containing the file name
*
*      If the file is not found, then the return value is NULL.
*
*      Often there are so many fonts that we need to manage the number of
*      simultaneously open files.  For that reason, these routines call
*      xfopen() instead of fopen(), which should manage the number of open
*      font files.
*
*/

/*--------------------------- Msdos ---------------------------------------*/
/* ericho */
#ifdef __MSDOS__

#define DEFAULT_FONT_PATH   "/tex/fonts"
#define DEFAULT_VF_PATH     "/tex/fonts/vf"
#define DEFAULT_FONT_SIZES  "300:328.6:360:432:518.4:622:746.4"

#ifdef FONTSUB
#include <stdio.h>
extern FILE *fontsubfile;
extern char *subfont (FILE *,char *);
#endif

#endif
/*--------------------------- Msdos ---------------------------------------*/

#include "xdvi.h"
#include <errno.h>

#ifndef X_NOT_STDC_ENV
#include <stdlib.h>     /* has getenv() */
#include <math.h>       /* has atof() */
#else
extern  char    *getenv();
#ifndef atof
double  atof();
#endif
#endif

/*
*      If you think you have to change DEFAULT_TAIL, then you haven't read the
*      documentation closely enough.
*/
#ifndef VMS
#define PATH_SEP        ':'

#ifndef __MSDOS__     /* eric ho */
#define DEFAULT_TAIL  "/%f.%d%p"
#else
#define DEFAULT_TAIL "/%d/%f.%p"
#endif

#define DEFAULT_VF_TAIL "/%f.vf"
#else   /* VMS */
#define PATH_SEP        '/'
#define DEFAULT_TAIL  ":%f.%d%p"
#define DEFAULT_VF_TAIL ":%f.vf"
#endif  /* VMS */

static  _Xconst char    *font_path;
static  _Xconst char    *default_font_path      = DEFAULT_FONT_PATH;
static  _Xconst char    *vf_path;
static  _Xconst char    *default_vf_path        = DEFAULT_VF_PATH;
#ifdef  SEARCH_SUBDIRECTORIES
static  char    default_subdir_path[]   = DEFAULT_SUBDIR_PATH;
#endif
static  int     *sizes, *sizend;
static  char    default_size_list[]     = DEFAULT_FONT_SIZES;

#ifdef  _POSIX_SOURCE
#include <limits.h>
#ifdef  PATH_MAX
#define FILENAMESIZE    PATH_MAX
#endif
#endif

#ifndef FILENAMESIZE
#define FILENAMESIZE 512
#endif

#ifdef  sun
char    *sprintf();
#endif

#ifdef  SEARCH_SUBDIRECTORIES
/* We will need some system include files to deal with directories.  */
/* <sys/types.h> was included by xdvi.h.  */

#include <sys/stat.h>

static  int     is_dir ();

#if     defined(SYSV) || defined(_POSIX_SOURCE)
#include <dirent.h>
typedef struct dirent   *directory_entry_type;
#else
#include <sys/dir.h>
typedef struct direct   *directory_entry_type;
#endif

/* Declare the routine to get the current working directory.  */

#ifdef  HAVE_GETWD
extern  char    *getwd ();
#define GETCWD(b, len)  ((b) ? getwd (b) : getwd (xmalloc (len, "getwd")))
#else
/* POSIX says getcwd result is undefined if the pointer is NULL; at least
  on a Convex, the result is a coredump.  Hence the GETCWD macro
  below is defined, as it works regardless of what getcwd() does
  with a NULL pointer  */
#define GETCWD(b, len)  ((b) ? getcwd (b,len) \
                       : getcwd (xmalloc (len, "getcwd"),len))
#ifdef  _POSIX_SOURCE
#include <unistd.h>     /* getcwd prototype */
#else
#if     NeedFunctionPrototypes
extern  char    *getcwd (char *, int);
#else
extern  char    *getcwd ();
#endif  /* not NeedFunctionPrototypes */
#endif  /* not _POSIX_SOURCE */
#endif  /* not HAVE_GETWD */

static  char    *cwd;

/* The following is a data structure containing the precomputed names of
  subdirectories to be recursively searched. */

static  struct subdir_entry {
       char    *name;          /* partial string */
       _Xconst char    *index; /* reference point in {,default_}font_path */
       struct subdir_entry *next;      /* link in list */
}
       *subdir_head    = NULL,
       *next_subdir;

#ifndef S_ISDIR
#define S_ISDIR(m)      ((m & S_IFMT) == S_IFDIR)
#endif



/* Return true if FN is a directory or a symlink to a directory,
  false if not. */

static  int
is_dir (fn)
       char    *fn;
{
       struct stat     stats;

       return stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode);
}

/*
*      Compute extra length of subdirectory entries, including a star for each.
*/

static  int
extra_len(str1, str2)
       char    *str1, *str2;
{
       int     bias    = 0;
       char    *p      = str1;
       char    *q;

       do {
           q = index(p, PATH_SEP);
           if (q == NULL) q = p + strlen(p);
           if (q == p) {
               if (str2 != NULL) {
                   bias += extra_len(str2, (char *) NULL);
                   str2 = NULL;
               }
           }
           else ++bias;        /* don't forget the star */
           p = q + 1;
       }
       while (p[-1] != '\0');
       return bias + p - str1;
}

/*
*      Add the specifiers (and double stars) for the given strings (user
*      string, plus default string) to the destination string.
*/

static  void
add_subdir_paths(dst, dst_first, src, src_default)
       char    *dst, *dst_first, *src, *src_default;
{
       char    *q;

       do {
           q = index(src, PATH_SEP);
           if (q == NULL) q = src + strlen(src);
           if (q == src) {
               if (src_default != NULL) {
                   add_subdir_paths(dst, dst_first, src_default, (char *)NULL);
                   dst += strlen(dst);
                   src_default = NULL;
               }
           }
           else {
               if (dst != dst_first) *dst++ = PATH_SEP;
               bcopy(src, dst, q - src);
               dst += q - src;
               *dst++ = '*';
           }
           src = q + 1;
       }
       while (src[-1] != '\0');
       *dst = '\0';
}

/*
*      Make a subdirectory entry.
*/

static  struct subdir_entry *
make_subdir_entry(index, name)
       _Xconst char    *index;
       char            *name;
{
       struct subdir_entry             *new_entry;
       static  struct subdir_entry     **subdir_tail = &subdir_head;

       *subdir_tail = new_entry = (struct subdir_entry *)
           xmalloc(sizeof(struct subdir_entry), "subdirectory list entry");
       subdir_tail = &(new_entry->next);
       new_entry->name = strcpy(xmalloc(strlen(name) + 1,
           "subdirectory entry string"), name);
       new_entry->index = index;
       new_entry->next = NULL;
       return new_entry;
}

/*
*      Create the subdirectory linked list for the given initial string
*/

static  void
add_subdirs(str, len, recurs)
       _Xconst char    *str;
       int     len;
       Boolean recurs;
{
       int     len1 = len;
       char    temp[FILENAMESIZE];
       struct subdir_entry *next_subdir;
       DIR     *dir;
       directory_entry_type    e;

       bcopy(str, temp, len);
       if (len > 0 && temp[len - 1] != '/') temp[len1++] = '/';
       temp[len1] = '\0';
       next_subdir = make_subdir_entry(str, temp + len);
       do {
           /* By changing directories, we save a bunch of string
              concatenations (and make the pathnames the kernel looks up
              shorter).  */
           Strcpy(temp + len, next_subdir->name);
           if (chdir (temp) != 0) continue;

           dir = opendir (".");
           if (dir == NULL) continue;

           len1 = strlen(temp);
           if (len1 == 0 || temp[len1 - 1] != '/') temp[len1++] = '/';
           while ((e = readdir (dir)) != NULL) {
               if (is_dir (e->d_name) && strcmp (e->d_name, ".") != 0
                       && strcmp (e->d_name, "..") != 0) {
                   Strcpy(temp + len1, e->d_name);
                   (void) make_subdir_entry(str, temp + len);
               }
           }
           (void) closedir (dir);


           /* Change back to the current directory, in case the path
              contains relative directory names.  */
           if (chdir (cwd) != 0) {
               perror (cwd);
               exit (errno);
           }
       }
       while (recurs && (next_subdir = next_subdir->next) != NULL);
}

/*
*      Recursively figure out the subdirectory tree and precompute the
*      list of subdirectories to search.
*/

static  void
compute_subdir_paths(fp, fp_default)
       _Xconst char    *fp;
       _Xconst char    *fp_default;
{
       _Xconst char    *star_loc = NULL;
       _Xconst char    *endp;

       do {
           if (star_loc == NULL) {
               star_loc = index(fp, '*');
               if (star_loc == NULL) star_loc = fp + strlen(fp);
           }
           endp = index(fp, PATH_SEP);
           if (endp == NULL) endp = fp + strlen(fp);
           if (endp == fp) {
               if (fp_default != NULL) {
                   compute_subdir_paths(fp_default, (char *) NULL);
                   fp_default = NULL;
               }
           }
           else if (star_loc < endp) {
               add_subdirs(fp, star_loc - fp, star_loc[1] == '*');
               star_loc = NULL;
           }
           fp = endp + 1;
       }
       while (fp[-1] != '\0');
}
#endif  /* SEARCH_SUBDIRECTORIES */

static  void
get_sizes(size_list, spp)
       char    *size_list;
       int     **spp;
{
       if (*size_list == PATH_SEP) ++size_list;
       for (;;) {
           *(*spp)++ = atof(size_list) * 5 + 0.5;
           size_list = index(size_list, PATH_SEP);
           if (size_list == NULL) return;
           ++size_list;
       }
}

void
init_font_open()
{
       char    *size_list;
       int     *sp, *sp1, *sp2;
       unsigned int n;
       char    *p;
#ifdef  SEARCH_SUBDIRECTORIES
       char    *q;
#endif

       if ((font_path = getenv("XDVIFONTS")) == NULL
#ifndef XDVIFONTS_ONLY
               && (font_path = getenv("PKFONTS")) == NULL
               && (font_path = getenv("TEXFONTS")) == NULL
#endif
               ) {
           font_path = default_font_path;
           default_font_path = NULL;
       }

#ifdef  SEARCH_SUBDIRECTORIES
       p = getenv ("TEXFONTS_SUBDIR");
       if (p == NULL) p = "";
       q = xmalloc((unsigned) strlen(font_path)
           + extra_len(p, default_subdir_path) + 1,
           "initializing font searching");
       Strcpy(q, font_path);
       add_subdir_paths(q + strlen(q), q, p, default_subdir_path);
       font_path = q;

       /* Unfortunately, we can't look in the environment for the current
          directory, because if we are running under a program (let's say
          Emacs), the PWD variable might have been set by Emacs' parent
          to the current directory at the time Emacs was invoked.  This
          is not necessarily the same directory the user expects to be
          in.  So, we must always call getcwd(3) or getwd(3), even though
          they are slow and prone to hang in networked installations.  */
       cwd = GETCWD ((char *) NULL, FILENAMESIZE + 2);
       if (cwd == NULL) {
           perror ("getcwd");
           exit (errno);
       }
       compute_subdir_paths(font_path, default_font_path);
#endif

       if ((vf_path = getenv("XDVIVFS")) == NULL
#ifndef XDVIFONTS_ONLY
               && (vf_path = getenv("VFFONTS")) == NULL
#endif
               ) {
           vf_path = default_vf_path;
           default_vf_path = NULL;
       }

       size_list = getenv("XDVISIZES");
       n = 1;  /* count number of sizes */
       if (size_list == NULL || *size_list == PATH_SEP)
           for (p = default_size_list; (p = index(p, PATH_SEP)) != NULL; ++p)
               ++n;
       if (size_list != NULL)
           for (p = size_list; (p = index(p, PATH_SEP)) != NULL; ++p) ++n;
       sizes = (int *) xmalloc(n * sizeof(int), "size list");
       sizend = sizes + n;
       sp = sizes;     /* get the actual sizes */
       if (size_list == NULL || *size_list == PATH_SEP)
           get_sizes(default_size_list, &sp);
       if (size_list != NULL) get_sizes(size_list, &sp);

       /* bubble sort the sizes */
       sp1 = sizend - 1;       /* extent of this pass */
       do {
           sp2 = NULL;
           for (sp = sizes; sp < sp1; ++sp)
               if (*sp > sp[1]) {
                   int i = *sp;
                   *sp = sp[1];
                   sp[1] = i;
                   sp2 = sp;
               }
       }
       while ((sp1 = sp2) != NULL);
}

/* eric */
static  FILE *
formatted_open(path, font, gforpk, mag, name, first_try, tail)
       _Xconst char    *path;
       _Xconst char    *font;
       _Xconst char    *gforpk;
       int     mag;
       char    **name;
       Boolean first_try;
       _Xconst char    *tail;
{
       _Xconst char    *p = path;
       char    nm[FILENAMESIZE];
       char    *n = nm;
       char    c;
       Boolean f_used = False;
       Boolean p_used = False;
       FILE    *f;


#ifdef  SEARCH_SUBDIRECTORIES
       if (next_subdir != NULL && next_subdir->index == p) {
           int len = index(p, '*') - p;

           bcopy(p, n, len);
           p += len;
           n += len;
           Strcpy(n, next_subdir->name);
           n += strlen(n);
           ++p;
           if (*p == '*') ++p;
           if (*p != '/') *n++ = '/';
       }
#endif
       for (;;) {
           c = *p++;
           if (c==PATH_SEP || c=='\0') {
               if (f_used) break;
               p = tail;
               continue;
           }
           if (c=='%') {
               c = *p++;
               switch (c) {
                   case 'f':
                       f_used = True;
                       Strcpy(n, font);
                       break;
                   case 'p':
                       p_used = True;
                       Strcpy(n, gforpk);
                       break;
                   case 'd':
                       Sprintf(n, "%d", mag);
                       break;
                   default:
                       *n++ = c;
                       *n = '\0';
               }
               n += strlen(n);
           }
           else *n++ = c;
       }
 if (!p_used && !first_try) return NULL;
       *n = '\0';
       if (debug & DBG_OPEN) Printf("Trying font file %s\n", nm);


       f = xfopen(nm);
       if (f != NULL) {
           *name = xmalloc((unsigned) (n - nm + 1), "font file name");
           Strcpy(*name, nm);
       }
       return f;
}

/*
*      Try a given size
*/

static  FILE *
try_size(font, pxlmag, name, x_font_path, x_default_font_path)
       _Xconst char    *font;
       int     pxlmag;
       char    **name;
       _Xconst char    *x_font_path;
       _Xconst char    *x_default_font_path;
{
       _Xconst char    *p      = x_font_path;
       FILE    *f;
       int     pkmag   = (pxlmag + 2) / 5;

#ifdef __MSDOS__
 char *sfont, *dotptr;
#endif

       /*
        * loop over paths
        */
#ifdef  SEARCH_SUBDIRECTORIES
       next_subdir = subdir_head;
#endif
       for (;;) {
           if (*p == PATH_SEP || *p == '\0') {
               if (x_default_font_path != NULL &&
                       (f = try_size(font, pxlmag, name, x_default_font_path,
                       (_Xconst char *) NULL)) != NULL)
                   return f;
               if (*p == '\0') break;
           }
           else {



#define FIRST_TRY True
#ifdef  USE_PK
/* ---------------------------- MSDOS (Eric Ho) ----------------------------*/

#if defined(__MSDOS__) && !defined(FONTSUB)

 /* I prefer this method because it'll execute a lot */
 /* faster than looking up the font substitute file  */

 /* simply convert all the amXXXX font to cmXXXX     */
 dotptr = strchr (font,'a');
 if (dotptr != (char *)NULL) {
   *dotptr = 'c';
 }
#endif

/* ---------------------------- MSDOS (Eric Ho) ----------------------------*/

   if ((f = formatted_open(p, font, "pk", pkmag, name, FIRST_TRY,DEFAULT_TAIL)) != NULL)
     return f;

/* ---------------------------- MSDOS (Eric Ho) ----------------------------*/

#if defined(__MSDOS__) && defined(FONTSUB)
 /* look for the substitute font from file */
 if (fontsubfile != (FILE *) NULL) {
   if ((sfont = (char *)subfont((FILE *)fontsubfile,(char *)font)) != (char *)NULL) {

     /* try open font file again */
     if ((f = formatted_open(p, (_Xconst char *)sfont, "pk", pkmag, name, FIRST_TRY,DEFAULT_TAIL)) != NULL)
       return f;
   }
 }
#endif

/* ---------------------------- MSDOS (Eric Ho) ----------------------------*/

#undef  FIRST_TRY
#define FIRST_TRY False
#endif


#ifdef  USE_GF
   if ((f = formatted_open(p, font, "gf", pkmag, name, FIRST_TRY,DEFAULT_TAIL)) != NULL)
                   return f;

/* ---------------------------- MSDOS (Eric Ho) ----------------------------*/

#if defined( __MSDOS__) && defined(FONTSUB)

 if (fontsubfile != (FILE *) NULL) {
   /* look for the substitute font from file */
   if ((sfont = (char *)subfont((FILE *)fontsubfile,font)) != (char *)NULL) {

     /* try open font file again */
     if ((f = formatted_open(p, sfont, "gf", pkmag, name, FIRST_TRY,DEFAULT_TAIL)) != NULL)
       return f;
   }
 }
#endif

/* ---------------------------- MSDOS (Eric Ho) ----------------------------*/


#undef  FIRST_TRY
#define FIRST_TRY False
#endif
#ifdef  USE_PXL
   if ((f = formatted_open(p, font, "pxl", pxlmag, name, FIRST_TRY,DEFAULT_TAIL)) != NULL)
                   return f;

/* ---------------------------- MSDOS (Eric Ho) ----------------------------*/

#if defined( __MSDOS__) && defined(FONTSUB)

 if (fontsubfile != (FILE *) NULL) {
   /* look for the substitute font from file */
   if ((sfont = (char *)subfont((FILE *)fontsubfile,font)) != (char *)NULL) {
     /* try open font file again */
     if ((f = formatted_open(p, sfont, "pxl", pkmag, name, FIRST_TRY,DEFAULT_TAIL)) != NULL)
       return f;
   }
 }
#endif

/* ---------------------------- MSDOS (Eric Ho) ----------------------------*/
#endif

#ifdef  SEARCH_SUBDIRECTORIES
               if (next_subdir != NULL && next_subdir->index == p) {
                   next_subdir = next_subdir->next;
                   if (next_subdir != NULL && next_subdir->index == p)
                       continue;
               }
#endif
               p = index(p, PATH_SEP);
               if (p == NULL) break;
           }
           ++p;
       }
       return NULL;
}

/*
*      Try a virtual font
*/

static  FILE *
try_vf(font, name, x_vf_path, x_default_vf_path)
       _Xconst char    *font;
       char    **name;
       _Xconst char    *x_vf_path;
       _Xconst char    *x_default_vf_path;
{
       _Xconst char    *p      = x_vf_path;
       FILE    *f;

       /*
        * loop over paths
        */
       for (;;) {
           if (*p == PATH_SEP || *p == '\0') {
               if (x_default_vf_path != NULL &&
                       (f = try_vf(font, name, x_default_vf_path,
                       (_Xconst char *) NULL)) != NULL)
                   return f;
               if (*p == '\0') break;
           }
           else {
               if ((f = formatted_open(p, font, "vf", 0, name, True,
                       DEFAULT_VF_TAIL)) != NULL)
                   return f;
               p = index(p, PATH_SEP);
               if (p == NULL) break;
           }
           ++p;
       }
       return NULL;
}

#ifdef  MAKEPKCMD
#undef  MAKEPK
#define MAKEPK
#endif

#ifdef  MAKEPK
#ifndef MAKEPKCMD
#define MAKEPKCMD       "MakeTeXPK"
#endif

#define NOBUILD 29999
#endif

/*
*      Try a given font name
*/

#ifndef MAKEPK
#define PRE_FONT_OPEN(font, fmag, mag_ret, name, ignore) \
               pre_font_open(font, fmag, mag_ret, name)
#else
#define PRE_FONT_OPEN   pre_font_open
#endif

static  FILE *
PRE_FONT_OPEN(font, fmag, mag_ret, name, magstepval)
       _Xconst char    *font;
       float   fmag;
       int     *mag_ret;
       char    **name;
#ifdef  MAKEPK
       int     magstepval;
#endif
{
       FILE    *f;
       int     *p1, *p2;
       int     mag     = 5 * fmag + 0.5;
       int     tmag;
#ifndef VMS
       _Xconst char    *path_to_use;
       _Xconst char    *vf_path_to_use;
#endif
#ifdef  MAKEPK
       char    mkpk[80];
#endif

       /*
        * Loop over sizes.  Try actual size first, then closest sizes.
          If the pathname is absolutely or explicitly relative, don't
          use the usual paths to search for it; just look for it in the
          directory specified.
        */

#ifndef VMS
       path_to_use = (_Xconst char *) NULL;
       if (*font == '/') path_to_use = "/";
       else if (*font == '.' && (*(font + 1) == '/'
               || (*(font + 1) == '.' && *(font + 2) == '/')))
           path_to_use = ".";
       vf_path_to_use = path_to_use;
       if (path_to_use == NULL) {
           path_to_use = font_path;
           vf_path_to_use = vf_path;
       }
#else   /* VMS */
#define path_to_use     font_path
#define vf_path_to_use  vf_path
#endif  /* VMS */

       if ((f = try_size(font, *mag_ret = mag, name, path_to_use,
               default_font_path)) != NULL)
           return f;

       /* Try at one away from the size we just tried, to account
          for rounding error.  */
       tmag = mag + (mag < 5 * fmag ? 1 : -1);
       if ((f = try_size(font, tmag, name, path_to_use, default_font_path))
               != NULL) {
           *mag_ret = tmag;
           return f;
       }

       /* Try a virtual font. */
       if ((f = try_vf(font, name, vf_path_to_use, default_vf_path)) != NULL)
           return f;

#ifdef  MAKEPK
       /* Try to create the font. */
       if (magstepval != NOBUILD) {
           char str[24];
           int dpi     = (mag + 2) / 5;

           if (magstepval == NOMAGSTP)
               Sprintf(str, "%d+%d/%d", dpi / pixels_per_inch,
                   dpi % pixels_per_inch, pixels_per_inch);
           else if (magstepval < 0)
               Sprintf(str, "magstep\\(-%d%s\\)", (-magstepval) / 2,
                   magstepval % 2 ? ".5" :"");
           else
               Sprintf(str, "magstep\\(%d%s\\)", magstepval / 2,
                   magstepval % 2 ? ".5" :"");

           Sprintf(mkpk, "%s %s %d %d %s", MAKEPKCMD, font, dpi,
               pixels_per_inch, str);
           Printf("- %s\n", mkpk);
           if (system(mkpk) == 0
               && (f = try_size(font, mag, name, path_to_use,
                       default_font_path))
                   != NULL)
               return f;
       }
#endif

       /* Now try at all the sizes. */
       for (p2 = sizes; p2 < sizend; ++p2) if (*p2 >= mag) break;
       p1 = p2;
       for (;;) {
               /* find another magnification */
           if (p1 <= sizes)
               if (p2 >= sizend) return NULL;
               else tmag = *p2++;
           else if (p2 >= sizend || (long) mag * mag <= (long) p1[-1] * *p2)
                   tmag = *--p1;
               else tmag = *p2++;
           if ((f = try_size(font, *mag_ret = tmag, name, path_to_use,
                   default_font_path)) != NULL)
               return f;
       }
}

/* ARGSUSED */
FILE *
font_open(font, font_ret, mag, mag_ret, magstepval, name)
       _Xconst char    *font;
       char    **font_ret;
       WIDEARG(float, double) mag;
       int     *mag_ret;
       int     magstepval;
       char    **name;
{
       FILE    *f;
       int     actual_pt, low_pt, high_pt, trial_pt;
       char    fn[50], *fnend;

       f = PRE_FONT_OPEN(font, mag, mag_ret, name, magstepval);
       if (f != NULL) {
           *font_ret = NULL;
           return f;
       }
       Strcpy(fn, font);
       fnend = fn + strlen(fn);
       while (fnend > fn && fnend[-1] >= '0' && fnend[-1] <= '9') --fnend;
       actual_pt = low_pt = high_pt = atoi(fnend);
       if (actual_pt) {
           low_pt = actual_pt - 1;
           high_pt = actual_pt + 1;
           for (;;) {
               if (2 * low_pt >= actual_pt &&
                   (low_pt * high_pt > actual_pt * actual_pt ||
                   high_pt > actual_pt + 5))
                       trial_pt = low_pt--;
               else if (high_pt > actual_pt + 5) break;
               else trial_pt = high_pt++;
               Sprintf(fnend, "%d", trial_pt);
               f = PRE_FONT_OPEN(fn, mag * actual_pt / trial_pt, mag_ret,
                   name, NOBUILD);
               if (f != NULL) {
                   *font_ret = strcpy(xmalloc((unsigned) strlen(fn) + 1,
                       "name of font used"), fn);
                   return f;
               }
           }
       }
       if (alt_font != NULL) {
           f = PRE_FONT_OPEN(alt_font, mag, mag_ret, name, NOBUILD);
           if (f != NULL)
               *font_ret = strcpy(xmalloc((unsigned) strlen(alt_font) + 1,
                   "name of font used"), alt_font);
       }
       return f;
}