/* * 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 extern FILE *fontsubfile; extern char *subfont (FILE *,char *); #endif #endif /*--------------------------- Msdos ---------------------------------------*/ #include "xdvi.h" #include #ifndef X_NOT_STDC_ENV #include /* has getenv() */ #include /* 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 #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. */ /* was included by xdvi.h. */ #include static int is_dir (); #if defined(SYSV) || defined(_POSIX_SOURCE) #include typedef struct dirent *directory_entry_type; #else #include 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 /* 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; }