changeset 1268:76a0c05089d4

[project @ 1995-04-20 19:15:51 by jwe] Initial revision
author jwe
date Thu, 20 Apr 1995 19:15:51 +0000
parents 69501f98669d
children abaf21f34109
files kpathsea/absolute.c kpathsea/basename.c kpathsea/cnf.c kpathsea/concat.c kpathsea/concat3.c kpathsea/concatn.c kpathsea/db.c kpathsea/debug.c kpathsea/dir.c kpathsea/elt-dirs.c kpathsea/expand.c kpathsea/extend-fname.c kpathsea/file-p.c kpathsea/find-suffix.c kpathsea/fn.c kpathsea/fontmap.c kpathsea/getopt.c kpathsea/getopt1.c kpathsea/hash.c kpathsea/itoa.c kpathsea/kdefault.c kpathsea/kpsewhich.c kpathsea/kpsexpand.c kpathsea/line.c kpathsea/magstep.c kpathsea/make-suffix.c kpathsea/path-elt.c kpathsea/pathsearch.c kpathsea/proginit.c kpathsea/progname.c kpathsea/putenv.c kpathsea/readable.c kpathsea/rm-suffix.c kpathsea/str-list.c kpathsea/str-llist.c kpathsea/tex-file.c kpathsea/tex-glyph.c kpathsea/tex-make.c kpathsea/tilde.c kpathsea/truncate.c kpathsea/uppercasify.c kpathsea/variable.c kpathsea/version.c kpathsea/xcalloc.c kpathsea/xfopen.c kpathsea/xmalloc.c kpathsea/xopendir.c kpathsea/xputenv.c kpathsea/xrealloc.c kpathsea/xstat.c kpathsea/xstrdup.c
diffstat 51 files changed, 6280 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/absolute.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,51 @@
+/* absolute.c: Test if a filename is absolute or explicitly relative.
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/absolute.h>
+#include <kpathsea/c-pathch.h>
+
+#ifdef DOS
+#include <kpathsea/c-ctype.h> /* For ISALPHA */
+#endif /* DOS */
+
+
+/* Sorry this is such a system-dependent mess, but I can't see any way
+   to usefully generalize.  */
+
+boolean
+kpse_absolute_p P2C(const_string, filename,  boolean, relative_ok)
+{
+#ifdef VMS
+#include <string.h>
+  return strcspn (filename, "]>:") != strlen (filename);
+#else /* not VMS */
+  boolean absolute = IS_DIR_SEP (*filename)
+#ifdef DOS
+                      || ISALPHA (*filename) && filename[1] == ':'
+#endif /* DOS */
+		      ;
+  boolean explicit_relative
+    = relative_ok && (*filename == '.'
+       && (IS_DIR_SEP (filename[1])
+           || (filename[1] == '.' && IS_DIR_SEP (filename[2]))));
+
+  return absolute || explicit_relative;
+#endif /* not VMS */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/basename.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,51 @@
+/* basename.c: return the last element in a path.
+
+Copyright (C) 1992, 94, 95 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Have to include this first to get c-auto.h.  */
+#include <kpathsea/config.h>
+
+#ifndef HAVE_BASENAME /* rest of file */
+
+#include <kpathsea/c-pathch.h>
+
+/* Return NAME with any leading path stripped off.  This returns a
+   pointer into NAME.  For example, `basename ("/foo/bar.baz")'
+   returns "bar.baz".  */
+
+const_string
+basename P1C(const_string, name)
+{
+  const_string base = NULL;
+  unsigned len = strlen (name);
+  
+  for (len = strlen (name); len > 0; len--)
+    {
+      if (IS_DIR_SEP (name[len - 1]))
+        {
+          base = name + len;
+          break;
+        }
+    }
+
+  if (!base)
+    base = name;
+  
+  return base;
+}
+
+#endif /* not HAVE_BASENAME */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/cnf.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,190 @@
+/* cnf.c: read config files.
+
+Copyright (C) 1994 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-fopen.h>
+#include <kpathsea/c-ctype.h>
+#include <kpathsea/cnf.h>
+#include <kpathsea/db.h>
+#include <kpathsea/hash.h>
+#include <kpathsea/line.h>
+#include <kpathsea/paths.h>
+#include <kpathsea/pathsearch.h>
+#include <kpathsea/tex-file.h>
+#include <kpathsea/variable.h>
+
+
+/* By using our own hash table, instead of the environment, we
+   complicate variable expansion (because now we have to look in two
+   places), but we don't bang so heavily on the system.  DOS and System
+   V have very limited environment space.  Also, this way
+   `kpse_init_format' can distinguish between values originating from
+   the cnf file and ones from environment variables, which can be useful
+   for users trying to figure out what's going on.  */
+#ifndef CNF_HASH_SIZE
+#define CNF_HASH_SIZE 751
+#endif
+static hash_table_type cnf_hash;
+
+/* Do a single line in a cnf file: if it's blank or a comment, skip it.
+   Otherwise, parse <variable>[.<program>] [=] <value>.  Do
+   this even if the <variable> is already set in the environment, since
+   the envvalue might contain a trailing :, in which case we'll be
+   looking for the cnf value.  */
+
+static void
+do_line P1C(string, line)
+{
+  unsigned len;
+  string start;
+  string value, var;
+  
+  /* Skip leading whitespace.  */
+  while (ISSPACE (*line))
+    line++;
+  
+  /* More to do only if we have non-comment material left.  */
+  if (*line == 0 || *line == '%' || *line == '#')
+    return;
+  
+  /* The variable name is everything up to the next space or = or `.'.  */
+  start = line;
+  while (!ISSPACE (*line) && *line != '=' && *line != '.')
+    line++;
+
+  /* `line' is now one character past the end of the variable name.  */
+  len = line - start;
+  var = xmalloc (len + 1);
+  strncpy (var, start, len);
+  var[len] = 0;
+  
+  /* If the variable is qualified with a program name, we might be
+     ignoring it.  */
+  while (ISSPACE (*line))
+    line++;
+  if (*line == '.') 
+    { /* Skip spaces, then everything up to the next space or =.  */
+      string prog;
+      extern string program_invocation_short_name; /* must be set by main */
+      
+      line++;
+      while (ISSPACE (*line))
+        line++;
+      start = line;
+      while (!ISSPACE (*line) && *line != '=')
+        line++;
+      
+      /* It's annoying to repeat all this, but making a tokenizing
+         subroutine would be just as long and annoying.  */
+      len = line - start;
+      prog = xmalloc (len + 1);
+      strncpy (prog, start, len);
+      prog[len] = 0;
+      
+      /* If we are running `prog', fine; otherwise, we're done.  */
+      assert (program_invocation_short_name);
+      if (!STREQ (prog, program_invocation_short_name))
+        {
+          free (var);
+          free (prog);
+          return;
+        }
+    }
+
+  /* Skip whitespace, an optional =, more whitespace.  */
+  while (ISSPACE (*line))
+    line++;
+  if (*line == '=')
+    {
+      line++;
+      while (ISSPACE (*line))
+        line++;
+    }
+  
+  /* Everything up to the next whitespace or eol is the value. */
+  start = line;
+  while (*line && !ISSPACE (*line))
+    line++;
+  len = line - start;
+  
+  value = xmalloc (len + 1);
+  strncpy (value, start, len);
+  value[len] = 0;
+  
+  /* For cnf files, multiple values for a single variable make no sense,
+     but instead of removing them, we'll just take the most recent in
+     `kpse_cnf_get'.  Thus, we are assuming here that `hash_insert' puts
+     the most recent entries in first.  */
+  hash_insert (&cnf_hash, var, value);
+  
+  /* We could check that anything remaining is preceded by a comment
+     character, but let's not bother.  */
+}
+
+/* Read all the configuration files in the path.  */
+
+static void
+read_files P1H(void)
+{
+  string *cnf_files;
+  const_string cnf_path = kpse_init_format (kpse_cnf_format);
+
+  cnf_hash = hash_create (CNF_HASH_SIZE);
+
+  for (cnf_files = kpse_all_path_search (cnf_path,
+                                    kpse_format_info[kpse_cnf_format].program);
+       cnf_files && *cnf_files; cnf_files++)
+    {
+      string line;
+      string cnf_filename = *cnf_files;
+      FILE *cnf_file = xfopen (cnf_filename, FOPEN_R_MODE);
+      
+      while ((line = read_line (cnf_file)) != NULL)
+        {
+          do_line (line);
+          free (line);
+        }
+
+      xfclose (cnf_file, cnf_filename);
+    }
+  
+  /* After (*after*) reading the cnf files, expand the db directory, for
+     use by `elt_in_db' in pathsearch.c.  The default value of $TEXMF
+     has to be able to get TEXMF from a cnf file, therefore in the
+     `kpse_all_path_search' call above, we do not have DB_DIR.  */
+  kpse_db_dir = kpse_var_expand (KPSE_DB_DIR);
+  if (! *kpse_db_dir)
+    kpse_db_dir = kpse_var_expand (DEFAULT_TEXMF);
+}
+
+/* Read the cnf files on the first call.  Return the first value in the
+   returned list -- this will be from the last-read cnf file.  */
+
+string
+kpse_cnf_get P1C(const_string, name)
+{
+  string *ret_list;
+  
+  if (cnf_hash.size == 0)
+    read_files ();
+  
+  ret_list = hash_lookup (cnf_hash, name);
+  
+  return ret_list ? *ret_list : NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/concat.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,33 @@
+/* concat.c: dynamic string concatenation.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+
+/* Return the concatenation of S1 and S2.  See `concatn.c' for a
+   `concatn', which takes a variable number of arguments.  */
+
+string
+concat P2C(const_string, s1,  const_string, s2)
+{
+  string answer = (string) xmalloc (strlen (s1) + strlen (s2) + 1);
+  strcpy (answer, s1);
+  strcat (answer, s2);
+
+  return answer;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/concat3.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,32 @@
+/* concat3.c: concatenate three strings.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+
+string
+concat3 P3C(const_string, s1,  const_string, s2,  const_string, s3)
+{
+  string answer
+    = (string) xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1);
+  strcpy (answer, s1);
+  strcat (answer, s2);
+  strcat (answer, s3);
+
+  return answer;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/concatn.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,68 @@
+/* concatn.c: Concatenate an arbitrary number of strings.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/concatn.h>
+
+
+/* OK, it would be epsilon more efficient to compute the total length
+   and then do the copying ourselves, but I doubt it matters in reality.  */
+
+string
+concatn PVAR1C(const_string, str1,  ap)
+{
+  string arg;
+  string ret;
+
+  if (!str1)
+    return NULL;
+  
+  ret = xstrdup (str1);
+  
+  while ((arg = va_arg (ap, string)) != NULL)
+    {
+      ret = concat (ret, arg);
+    }
+  va_end (ap);
+  
+  return ret;
+}}
+
+#ifdef TEST
+int
+main ()
+{
+  printf ("null = \"%s\"\n", concatn (NULL));
+  printf ("\"a\" = \"%s\"\n", concatn ("a", NULL));
+  printf ("\"ab\" = \"%s\"\n", concatn ("a", "b", NULL));
+  printf ("\"abc\" = \"%s\"\n", concatn ("a", "b", "c", NULL));
+  printf ("\"abcd\" = \"%s\"\n", concatn ("ab", "cd", NULL));
+  printf ("\"abcde\" = \"%s\"\n", concatn ("ab", "c", "de", NULL));
+  printf ("\"abcdef\" = \"%s\"\n", concatn ("", "a", "", "bcd", "ef", NULL));
+  return 0;
+}
+
+#endif /* TEST */
+
+
+/*
+Local variables:
+standalone-compile-command: "gcc -posix -g -I. -I.. -DTEST concatn.c kpathsea.a"
+End:
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/db.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,269 @@
+/* db.c: an external database to avoid filesystem lookups.
+
+Copyright (C) 1994 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-fopen.h>
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/db.h>
+#include <kpathsea/hash.h>
+#include <kpathsea/line.h>
+#include <kpathsea/readable.h>
+#include <kpathsea/str-list.h>
+#include <kpathsea/variable.h>
+
+/* See comments in `read_files' in cnf.c.  */
+string kpse_db_dir = NULL;
+
+/* The hash table for ls-R.  */
+static hash_table_type db;
+
+
+/* If no DB_FILE, return false (maybe they aren't using this feature).
+   Otherwise, build the db and return true.  */
+
+static boolean
+db_build P1C(hash_table_type *, table)
+{
+  string line;
+  unsigned dir_count = 0, file_count = 0; /* for debugging */
+  string cur_dir = NULL; /* First thing in ls-R might be a filename.  */
+  string db_filename = concat3 (kpse_db_dir, DIR_SEP_STRING, KPSE_DB_NAME);
+  FILE *db_file = fopen (db_filename, FOPEN_R_MODE);
+  
+  if (db_file)
+    {
+      while ((line = read_line (db_file)) != NULL)
+        {
+          unsigned len = strlen (line);
+          /* A line like `/foo:' = new dir foo */
+          if (IS_DIR_SEP (line[0]) && line[len - 1] == ':')
+            {
+              cur_dir = xstrdup (line);
+              cur_dir[len - 1] = DIR_SEP;
+              dir_count++;
+            }
+          else if (line[0] != 0 && cur_dir) /* other nonblank line */
+            { /* New hash table entry with a key of `line' and a data of
+                 `cur_dir'.  Already-existing identical keys are ok, since
+                 a file named `foo' can be in more than one directory.
+                 Since it doesn't hurt, share the directory name string
+                 among all the files in the directory. */
+              hash_insert (table, xstrdup (line), cur_dir);
+              file_count++;
+            }
+          /* else ignore blank lines */
+
+          free (line);
+        }
+      xfclose (db_file, db_filename);
+      
+      if (file_count == 0)
+        {
+          fprintf (stderr, "kpathsea: no usable entries in %s; see the\n", 
+                   db_filename);
+          fprintf (stderr, "kpathsea: manual for how to generate ls-R.\n");
+        }
+
+#ifdef DEBUG
+      if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
+        {
+          /* Don't make this a debugging bit, since the output is so
+             voluminous, and being able to specify -1 is too useful.
+             Instead, let people who want it run the program under
+             a debugger and change the variable that way.  */
+          boolean print_hash_table = false;
+
+          DEBUGF3 ("%u entries (in %d directories) read from %s.\n",
+                   file_count, dir_count, db_filename);
+          if (print_hash_table)
+            {
+              DEBUGF ("Hash table built from ls-R:");
+              hash_print (*table);
+            }
+          fflush (stderr);
+        }
+#endif
+    }
+
+  free (db_filename);
+  return db_file != NULL;
+}
+
+
+/* Insert FNAME into the hash table.  This is for files that get built
+   during a run.  We wouldn't want to reread all of ls-R, even if it got
+   rebuilt.  */
+
+void
+db_insert P1C(const_string, passed_fname)
+{
+  /* We should always have called `kpse_db_search' before this.  */
+  assert (db.size > 0);
+  
+  /* But we might not have found ls-R; in that case, we'll have cleared
+     the buckets (but left the size).  */
+  if (db.buckets)
+    {
+      const_string dir_part;
+      string fname = xstrdup (passed_fname);
+      string baseptr = (string) basename (fname);
+      const_string file_part = xstrdup (baseptr);
+      
+      *baseptr = '\0';  /* Chop off the filename.  */
+      dir_part = fname; /* That leaves the dir, with the trailing /.  */
+
+      hash_insert (&db, file_part, dir_part);
+    }
+}
+
+/* Return true if FILENAME could be in PATH_ELT, i.e., if the directory
+   part of FILENAME matches PATH_ELT.  Have to consider // wildcards, but
+   $ and ~ expansion have already been done.  */
+     
+static boolean
+match P2C(const_string, filename,  const_string, path_elt)
+{
+  const_string original_filename = filename;
+  boolean matched = false;
+  boolean done = false;
+  
+  for (; !done && *filename && *path_elt; filename++, path_elt++)
+    {
+      if (*filename == *path_elt) /* normal character match */
+        ;
+
+      else if (IS_DIR_SEP (*path_elt)  /* at // */
+               && original_filename < filename && IS_DIR_SEP (path_elt[-1]))
+        {
+          path_elt++; /* get past second / */
+          if (*path_elt == 0)
+            { /* Have a trailing //, which matches anything. We
+                 could make this part of the other case, but it seems
+                 pointless to do the extra work.  */
+              matched = true;
+              done = true;
+            }
+          else
+            { /* intermediate //, have to match rest of PATH_ELT */
+              for (; !matched && *filename; filename++)
+                { /* Try matching at each possible character.  */
+                  if (*filename == *path_elt)
+                    matched = match (filename, path_elt);
+                }
+            }
+        }
+      
+      else /* normal character nonmatch, quit */
+        done = true;
+    }
+  
+  /* If we've reached the end of PATH_ELT, and we're at the last
+     component of FILENAME, we've matched.  */
+  if (!matched && *path_elt == 0 && IS_DIR_SEP (*filename))
+    {
+      filename++;
+      while (*filename && !IS_DIR_SEP (*filename))
+        filename++;
+      matched = *filename == 0;
+    }
+
+  return matched;
+}
+
+/* Don't bother implementing a search path for the database itself.  We
+   get multiple databases, sort of, with the $TEXMF value for DB_DIR.  */
+
+str_list_type *
+kpse_db_search P3C(const_string, name,  const_string, orig_path_elt,
+                   boolean, all)
+{
+  string *db_dirs, *orig_dirs;
+  const_string last_slash;
+  string path_elt;
+  boolean done;
+  str_list_type *ret;
+  
+  /* Hash up the database if this is the first call.  */
+  if (db.size == 0)
+    {
+      db = hash_create (7603); /* What the heck, sparse is ok.  */
+      if (!db_build (&db))
+        { /* If db can't be built, leave `size' nonzero (so we don't
+             rebuild it), but clear `buckets' (so we don't look in it).  */
+          free (db.buckets);
+          db.buckets = NULL;
+        }
+    }
+  
+  /* If we failed to build the database, quit.  */
+  if (db.buckets == NULL)
+    return NULL;
+  
+  /* When tex-glyph.c calls us looking for, e.g., dpi600/cmr10.pk, we
+     won't find it unless we change NAME to just `cmr10.pk' and append
+     `/dpi600' to PATH_ELT.  We are justified in using a literal `/'
+     here, since that's what tex-glyph.c unconditionally uses in
+     DPI_BITMAP_SPEC.  But don't do anything if the / begins NAME; that
+     should never happen.  */
+  last_slash = strrchr (name, '/');
+  if (last_slash && last_slash != name)
+    {
+      unsigned len = last_slash - name + 1;
+      string dir_part = xmalloc (len);
+      strncpy (dir_part, name, len - 1);
+      dir_part[len - 1] = 0;
+      path_elt = concat3 (orig_path_elt, "/", dir_part);
+      name = last_slash + 1;
+    }
+  else
+    path_elt = (string) orig_path_elt;
+
+  /* We have a db.  Look up NAME.  */
+  orig_dirs = db_dirs = hash_lookup (db, name);
+
+  done = false;
+  ret = XTALLOC1 (str_list_type);
+  *ret = str_list_init ();
+  
+  /* For each filename found, see if it matches the path element.  For
+     example, if we have ../cx/cmr10.300pk and .../ricoh/cmr10.300pk,
+     and the path looks like .../cx, we don't want the ricoh file.  */
+  while (!done && db_dirs && *db_dirs)
+    {
+      string db_file = concat (*db_dirs, name);
+      
+      if (match (db_file, path_elt) && kpse_readable_file (db_file))
+        {
+          str_list_add (ret, db_file);
+          if (!all) done = true;
+        }
+      else
+        free (db_file);
+      
+      /* On to the next directory, if any.  */
+      db_dirs++;
+    }
+
+  /* This is just the space for the pointers, not the strings.  */
+  if (orig_dirs && *orig_dirs) free (orig_dirs);
+  
+  /* If we had to break up NAME, free the temporary PATH_ELT.  */
+  if (path_elt != orig_path_elt) free (path_elt);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/debug.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,52 @@
+/* debug.c: Help the user discover what's going on.
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#ifdef DEBUG
+
+unsigned kpathsea_debug = 0;
+
+/* If the real definitions of fopen or fclose are macros, we lose -- the
+   #undef won't restore them. */
+
+FILE *
+fopen P2C(const_string, filename,  const_string, mode)
+{
+#undef fopen
+  FILE *ret = fopen (filename, mode);
+
+  if (KPSE_DEBUG_P (KPSE_DEBUG_FOPEN))
+    DEBUGF3 ("fopen(%s, %s) => 0x%lx\n", filename, mode, (unsigned long) ret);
+
+  return ret;
+}
+
+int
+fclose P1C(FILE *, f)
+{
+#undef fclose
+  int ret = fclose (f);
+  
+  if (KPSE_DEBUG_P (KPSE_DEBUG_FOPEN))
+    DEBUGF2 ("fclose(0x%lx) => %d\n", (unsigned long) f, ret);
+
+  return ret;
+}
+
+#endif /* DEBUG */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/dir.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,85 @@
+/* dir.c: directory operations.
+
+Copyright (C) 1992, 93, 94 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-dir.h>
+#include <kpathsea/c-stat.h>
+#include <kpathsea/hash.h>
+
+
+/* Return true if FN is a directory or a symlink to a directory,
+   false if not. */
+
+boolean
+dir_p P1C(const_string, fn)
+{
+  struct stat stats;
+  return stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode);
+}
+
+
+/* Return -1 if FN isn't a directory, else its number of links.
+   Duplicate the call to stat; no need to incur overhead of a function
+   call for that little bit of cleanliness. */
+
+int
+dir_links P1C(const_string, fn)
+{
+  static hash_table_type link_table;
+  string *hash_ret;
+  long ret;
+  
+  if (link_table.size == 0)
+    link_table = hash_create (457);
+
+#ifdef DEBUG
+  /* This is annoying, but since we're storing integers as pointers, we
+     can't print them as strings.  */
+  if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
+    kpse_debug_hash_lookup_int = true;
+#endif
+
+  hash_ret = hash_lookup (link_table, fn);
+  
+#ifdef DEBUG
+  if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
+    kpse_debug_hash_lookup_int = false;
+#endif
+
+  /* Have to cast the int we need to/from the const_string that the hash
+     table stores for values. Let's hope an int fits in a pointer.  */
+  if (hash_ret)
+    ret = (long) *hash_ret;
+  else
+    {
+      struct stat stats;
+      ret = stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode)
+            ? stats.st_nlink : -1;
+
+      /* It's up to us to copy the value.  */
+      hash_insert (&link_table, xstrdup (fn), (const_string) ret);
+      
+#ifdef DEBUG
+      if (KPSE_DEBUG_P (KPSE_DEBUG_STAT))
+        DEBUGF2 ("dir_links(%s) => %ld\n", fn, ret);
+#endif
+    }
+
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/elt-dirs.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,367 @@
+/* elt-dirs.c: Translate a path element to its corresponding director{y,ies}.
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/expand.h>
+#include <kpathsea/fn.h>
+#include <kpathsea/pathsearch.h>
+#include <kpathsea/xopendir.h>
+
+/* To avoid giving prototypes for all the routines and then their real
+   definitions, we give all the subroutines first.  The entry point is
+   the last routine in the file.  */
+
+/* Make a copy of DIR (unless it's null) and save it in L.  Ensure that
+   DIR ends with a DIR_SEP for the benefit of later searches.  */
+
+static void
+dir_list_add P2C(str_llist_type *, l,  const_string, dir)
+{
+  string saved_dir
+    = IS_DIR_SEP (dir[strlen (dir) - 1])
+      ? xstrdup (dir)
+      : concat (dir, DIR_SEP_STRING);
+  
+  str_llist_add (l, saved_dir);
+}
+
+
+/* If DIR is a directory, add it to the list L.  */
+
+static void
+checked_dir_list_add P2C(str_llist_type *, l,  const_string, dir)
+{
+  if (dir_p (dir))
+    dir_list_add (l, dir);
+}
+
+/* The cache.  Typically, several paths have the same element; for
+   example, /usr/local/lib/texmf/fonts//.  We don't want to compute the
+   expansion of such a thing more than once.  Even though we also cache
+   the dir_links call, that's not enough -- without this path element
+   caching as well, the execution time doubles.  */
+
+typedef struct
+{
+  const_string key;
+  str_llist_type *value;
+} cache_entry;
+
+static cache_entry *the_cache = NULL;
+static unsigned cache_length = 0;
+
+
+/* Associate KEY with VALUE.  We implement the cache as a simple linear
+   list, since it's unlikely to ever be more than a dozen or so elements
+   long.  We don't bother to check here if PATH has already been saved;
+   we always add it to our list.  We copy KEY but not VALUE; not sure
+   that's right, but it seems to be all that's needed.  */
+
+static void
+cache P2C(const_string, key,  str_llist_type *, value)
+{
+  cache_length++;
+  XRETALLOC (the_cache, cache_length, cache_entry);
+  the_cache[cache_length - 1].key = xstrdup (key);
+  the_cache[cache_length - 1].value = value;
+}
+
+
+/* To retrieve, just check the list in order.  */
+
+static str_llist_type *
+cached P1C(const_string, key)
+{
+  unsigned p;
+  
+  for (p = 0; p < cache_length; p++)
+    {
+      if (STREQ (the_cache[p].key, key))
+        return the_cache[p].value;
+    }
+  
+  return NULL;
+}
+
+/* Handle the magic path constructs.  */
+
+/* Declare recursively called routine.  */
+static void expand_elt P3H(str_llist_type *, const_string, unsigned);
+
+
+/* POST is a pointer into the original element (which may no longer be
+   ELT) to just after the doubled DIR_SEP, perhaps to the null.  Append
+   subdirectories of ELT (up to ELT_LENGTH, which must be a /) to
+   STR_LIST_PTR.  */
+
+static void
+do_subdir P4C(str_llist_type *, str_list_ptr,  const_string, elt,
+              unsigned, elt_length,  const_string, post)
+{
+  DIR *dir;
+  struct dirent *e;
+  fn_type name;
+  
+  /* Some old compilers don't allow aggregate initialization.  */
+  name = fn_copy0 (elt, elt_length);
+  
+  assert (IS_DIR_SEP (elt[elt_length - 1]));
+  
+  /* If we can't open it, quit.  */
+  dir = opendir (FN_STRING (name));
+  if (dir == NULL)
+    {
+      fn_free (&name);
+      return;
+    }
+  
+  /* Include top level before subdirectories, if nothing to match.  */
+  if (*post == 0)
+    dir_list_add (str_list_ptr, FN_STRING (name));
+  else
+    { /* If we do have something to match, see if it exists.  For
+         example, POST might be `pk/ljfour', and they might have a
+         directory `$TEXMF/fonts/pk/ljfour' that we should find.  */
+      fn_str_grow (&name, post);
+      if (dir_p (FN_STRING (name)))
+        dir_list_add (str_list_ptr, FN_STRING (name));
+      fn_shrink_to (&name, elt_length);
+    }
+
+  while ((e = readdir (dir)) != NULL)
+    { /* If it begins with a `.', never mind.  (This allows ``hidden''
+         directories that the algorithm won't find.)  */
+      if (e->d_name[0] != '.')
+        {
+          int links;
+          
+          /* Construct the potential subdirectory name.  */
+          fn_str_grow (&name, e->d_name);
+          
+          /* If we can't stat it, or if it isn't a directory, continue.  */
+          links = dir_links (FN_STRING (name));
+
+          if (links >= 0)
+            { 
+              unsigned potential_len = FN_LENGTH (name);
+              
+              /* It's a directory, so append the separator.  */
+              fn_str_grow (&name, DIR_SEP_STRING);
+              
+              if (*post != 0)
+                { 
+                  fn_str_grow (&name, post);
+                  /* Unfortunately we can't check if the new element is
+                     a leaf directory, because we don't have a directory
+                     name here, we just have a path spec. This means we
+                     may descend into a leaf directory cm/pk, if the
+                     spec is ...fonts//pk//.  */
+                  expand_elt (str_list_ptr, FN_STRING (name), potential_len);
+                  fn_shrink_to (&name, potential_len);
+                }
+              
+              /* Should we recurse?  To see if the subdirectory is a
+                 leaf, check if it has two links (one for . and one for
+                 ..).  This means that symbolic links to directories do
+                 not affect the leaf-ness.  This is arguably wrong, but
+                 the only alternative I know of is to stat every entry
+                 in the directory, and that is unacceptably slow.
+                 
+                 The #ifdef here makes all this configurable at
+                 compile-time, so that if we're using VMS directories or
+                 some such, we can still find subdirectories, even if it
+                 is much slower.  */
+#ifdef UNIX_ST_NLINK
+              if (links > 2)
+#endif
+                /* All criteria are met; find subdirectories.  */
+                do_subdir (str_list_ptr, FN_STRING (name),
+                           potential_len, post);
+#ifdef UNIX_ST_NLINK
+              else if (*post == 0)
+                /* Nothing to match, no recursive subdirectories to
+                   look for: we're done with this branch.  Add it.  */
+                dir_list_add (str_list_ptr, FN_STRING (name));
+#endif
+            }
+
+          /* Remove the directory entry we just checked from `name'.  */
+          fn_shrink_to (&name, elt_length);
+        }
+    }
+  
+  fn_free (&name);
+  xclosedir (dir);
+}
+
+
+/* Assume ELT is non-empty and non-NULL.  Return list of corresponding
+   directories (with no terminating NULL entry) in STR_LIST_PTR.  Start
+   looking for magic constructs at START.  */
+
+static void
+expand_elt P3C(str_llist_type *, str_list_ptr,  const_string, elt,
+               unsigned, start)
+{
+  boolean found_special = false;
+  const_string dir = elt + start;
+  
+  while (*dir != 0)
+    {
+      if (IS_DIR_SEP (*dir))
+        {
+          /* If two consecutive directory separators, find subdirectories.  */
+          if (IS_DIR_SEP (dir[1]))
+            {
+              do_subdir (str_list_ptr, elt, dir - elt + 1, dir + 2);
+              found_special = true;
+            }
+#if 0
+/* Maybe eventually I'll implement this, but probably not.  */
+          /* If /?, make following component optional.  */
+          else if (dir[1] == '?')
+            do_optional (str_list_ptr, elt, dir - elt + 1, dir + 2);
+#endif
+          /* No special stuff at this slash.  Keep going.  */
+        }
+      
+      dir++;
+    }
+  
+  if (!found_special)
+    /* When we reach the end of ELT, it will be a normal filename.  */
+    checked_dir_list_add (str_list_ptr, elt);
+}
+
+/* Here is the entry point.  Returns directory list for ELT.  */
+
+str_llist_type *
+kpse_element_dirs P1C(const_string, elt)
+{
+  str_llist_type *ret;
+
+  /* If given nothing, return nothing.  */
+  if (!elt)
+    return NULL;
+
+  /* If we've already cached the answer for ELT, return it.  */
+  ret = cached (elt);
+  if (ret)
+    return ret;
+
+  /* We're going to have a real directory list to return.  */
+  ret = XTALLOC1 (str_llist_type);
+  *ret = NULL;
+  
+  /* If ELT is the empty string, just return cwd.  */
+  if (*elt == 0)
+    { /* Some old compilers do not support aggregate initialization.  */
+      char cwd[3];
+      cwd[0] = '.';
+      cwd[1] = DIR_SEP;
+      cwd[2] = 0;
+      
+      checked_dir_list_add (ret, cwd);
+    }
+
+  /* OK, so much for the trivial cases.  We handle the hard case in
+     a subroutine.  */
+  else
+    expand_elt (ret, elt, 0);
+
+  /* Remember the directory list we just found, in case future calls are
+     made with the same ELT.  */
+  cache (elt, ret);
+
+#ifdef DEBUG
+  if (KPSE_DEBUG_P (KPSE_DEBUG_EXPAND))
+    {
+      DEBUGF1 ("path element %s =>", elt);
+      if (ret)
+        {
+          str_llist_elt_type *e;
+          for (e = *ret; e; e = STR_LLIST_NEXT (*e))
+            fprintf (stderr, " %s", STR_LLIST (*e));
+        }
+      putc ('\n', stderr);
+      fflush (stderr);
+    }
+#endif
+
+  return ret;
+}
+
+#ifdef TEST
+
+void
+print_element_dirs (const_string elt)
+{
+  str_llist_type *dirs;
+  
+  printf ("Directories of %s:\t", elt ? elt : "(null)");
+  fflush (stdout);
+  
+  dirs = kpse_element_dirs (elt);
+  
+  if (!dirs)
+    printf ("(null)");
+  else
+    {
+      str_llist_elt_type *dir;
+      for (dir = *dirs; dir; dir = STR_LLIST_NEXT (*dir))
+        {
+          string d = STR_LLIST (*dir);
+          printf ("%s ", *d ? d : "`'");
+        }
+    }
+  
+  putchar ('\n');
+}
+
+int
+main ()
+{
+  /* DEBUG_SET (DEBUG_STAT); */
+
+  /* All lists end with NULL.  */
+  print_element_dirs (NULL);	/* */
+  print_element_dirs ("");	/* ./ */
+  print_element_dirs ("/k");	/* */
+  print_element_dirs (".//");	/* ./ ./archive/ */
+  print_element_dirs (".//archive");	/* ./ ./archive/ */
+  print_element_dirs ("/tmp/fonts//");	/* no need to stat anything */
+  print_element_dirs ("/usr/local/lib/tex/fonts//");      /* lots */
+  print_element_dirs ("/usr/local/lib/tex/fonts//times"); /* just one */
+  print_element_dirs ("/usr/local/lib/tex/fonts//"); /* lots again [cache] */
+  print_element_dirs ("~karl");		/* tilde expansion */
+  print_element_dirs ("$karl");		/* variable expansion */  
+  print_element_dirs ("~${LOGNAME}");	/* both */  
+  
+  return 0;
+}
+
+#endif /* TEST */
+
+
+/*
+Local variables:
+test-compile-command: "gcc -g -I. -I.. -DTEST elt-dirs.c kpathsea.a"
+End:
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/expand.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,69 @@
+/* expand.c: general expansion.
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/expand.h>
+#include <kpathsea/pathsearch.h>
+#include <kpathsea/tilde.h>
+#include <kpathsea/variable.h>
+
+
+/* Do variable expansion so ~${USER} will work.  (Besides, it's what the
+   shells do.)  */
+
+string
+kpse_expand P1C(const_string, s)
+{
+  string var_expansion = kpse_var_expand (s);
+  string tilde_expansion = kpse_tilde_expand (var_expansion);
+  
+  /* `kpse_var_expand' always gives us new memory; `kpse_tilde_expand'
+     doesn't, necessarily.  So be careful that we don't free what we are
+     about to return.  */
+  if (tilde_expansion != var_expansion)
+    free (var_expansion);
+  
+  return tilde_expansion;
+}
+
+
+/* Be careful to not waste all the memory we allocate for each element.  */
+
+string
+kpse_path_expand P1C(const_string, path)
+{
+  string elt;
+  string ret = xmalloc (1); /* so we can free it */
+  *ret = 0;
+  
+  for (elt = kpse_path_element (path); elt; elt = kpse_path_element (NULL))
+    {
+      string save_ret = ret;
+      string elt_exp = kpse_expand (elt);
+      ret = concat3 (ret, elt_exp, ENV_SEP_STRING);
+      free (elt_exp);
+      free (save_ret);
+    }
+    
+  /* Waste the last byte.  */
+  ret[strlen (ret) - 1] = 0;
+  
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/extend-fname.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,34 @@
+/* extend-fname.c: give a filename a suffix, if necessary.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+
+/* We may or may not return NAME.  It's up to the caller not to assume
+   the return value is modifiable.  */
+
+string 
+extend_filename P2C(const_string, name, const_string, default_suffix)
+{
+  string new_s;
+  const_string suffix = find_suffix (name);
+
+  new_s = suffix == NULL ? concat3 (name, ".", default_suffix)
+                         : (string) name;
+  return new_s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/file-p.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,37 @@
+/* file-p.c: file predicates.
+
+Copyright (C) 1992, 93, 94 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/xstat.h>
+
+
+/* Test whether FILENAME1 and FILENAME2 are actually the same file.  If
+   stat fails on either of the names, we return false, without error.  */
+
+boolean
+same_file_p P2C(const_string, filename1,  const_string, filename2)
+{
+    struct stat sb1, sb2;
+    /* These are put in variables only so the results can be inspected
+       under gdb.  */
+    int r1 = stat (filename1, &sb1);
+    int r2 = stat (filename2, &sb2);
+
+    return r1 == 0 && r2 == 0 ? SAME_FILE_P (sb1, sb2) : false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/find-suffix.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,43 @@
+/* find-suffix.c: return the stuff after a dot.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-pathch.h>
+
+
+/* Return pointer to first character after `.' in last directory element
+   of NAME.  If the name is `foo' or `/foo.bar/baz', we have no extension.  */
+
+string
+find_suffix P1C(const_string, name)
+{
+  const_string slash_pos;
+  string dot_pos = strrchr (name, '.');
+  
+  if (dot_pos == NULL)
+    return NULL;
+  
+  for (slash_pos = name + strlen (name) + 1;
+       slash_pos > dot_pos && !IS_DIR_SEP (*slash_pos);
+       slash_pos--)
+    ;
+  
+  return slash_pos > dot_pos ? NULL : dot_pos + 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/fn.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,119 @@
+/* fn.c: arbitrarily long filenames (or just strings).
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/fn.h>
+
+
+/* /usr/local/lib/texmf/fonts/public/cm/pk/ljfour/cmr10.300pk is 58
+   chars, so ASCII `K' seems a good choice. */
+#define CHUNK_SIZE 75
+
+
+fn_type
+fn_init P1H(void)
+{
+  fn_type ret;
+  
+  FN_ALLOCATED (ret) = FN_LENGTH (ret) = 0;
+  FN_STRING (ret) = NULL;
+  
+  return ret;
+}
+
+
+fn_type
+fn_copy0 P2C(const_string, s,  unsigned, len)
+{
+  fn_type ret;
+  
+  FN_ALLOCATED (ret) = CHUNK_SIZE > len ? CHUNK_SIZE : len + 1;
+  FN_STRING (ret) = xmalloc (FN_ALLOCATED (ret));
+  
+  strncpy (FN_STRING (ret), s, len);
+  FN_STRING (ret)[len] = 0;
+  FN_LENGTH (ret) = len + 1;
+  
+  return ret;
+}
+
+/* Don't think we ever try to free something that might usefully be
+   empty, so give fatal error if nothing allocated.  */
+
+void
+fn_free P1C(fn_type *, f)
+{
+  assert (FN_STRING (*f) != NULL);
+  free (FN_STRING (*f));
+  FN_STRING (*f) = NULL;
+  FN_ALLOCATED (*f) = 0;
+  FN_LENGTH (*f) = 0;
+}
+
+/* An arithmetic increase seems more reasonable than geometric.  We
+   don't increase the length member since it may be more convenient for
+   the caller to add than subtract when appending the stuff that will
+   presumably follow.  */
+
+static void
+grow P2C(fn_type *, f,  unsigned, len)
+{
+  while (FN_LENGTH (*f) + len > FN_ALLOCATED (*f))
+    {
+      FN_ALLOCATED (*f) += CHUNK_SIZE;
+      XRETALLOC (FN_STRING (*f), FN_ALLOCATED (*f), char);
+    }
+}
+
+
+void
+fn_1grow P2C(fn_type *, f,  char, c)
+{
+  grow (f, 1);
+  FN_STRING (*f)[FN_LENGTH (*f)] = c;
+  FN_LENGTH (*f)++;
+}
+
+
+void
+fn_grow P3C(fn_type *, f,  address, source,  unsigned, len)
+{
+  grow (f, len);
+  strncpy (FN_STRING (*f) + FN_LENGTH (*f), source, len);
+  FN_LENGTH (*f) += len;
+}
+
+
+void
+fn_str_grow P2C(fn_type *, f,  const_string, s)
+{
+  unsigned more_len = strlen (s);
+  grow (f, more_len);
+  strcat (FN_STRING (*f), s);
+  FN_LENGTH (*f) += more_len;
+}
+
+
+void
+fn_shrink_to P2C(fn_type *, f,  unsigned, loc)
+{
+  assert (FN_LENGTH (*f) > loc);
+  FN_STRING (*f)[loc] = 0;
+  FN_LENGTH (*f) = loc + 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/fontmap.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,133 @@
+/* fontmap.c: read a file for additional font names.
+
+Copyright (C) 1993, 94 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-fopen.h>
+#include <kpathsea/fontmap.h>
+#include <kpathsea/hash.h>
+#include <kpathsea/line.h>
+#include <kpathsea/pathsearch.h>
+#include <kpathsea/str-list.h>
+
+
+/* Look up KEY in MAP; if it's not found, remove any suffix from KEY and
+   try again.  */
+
+string *
+map_lookup P2C(hash_table_type, map,  const_string, key)
+{
+  string suffix = find_suffix (key);
+  string *ret = hash_lookup (map, key);
+  
+  if (!ret)
+    {
+      /* OK, the original KEY didn't work.  Let's check for the KEY without
+         an extension -- perhaps they gave foobar.tfm, but the mapping only
+         defines `foobar'.  */
+      if (suffix)
+        {
+          string base_key = remove_suffix (key);
+          
+          ret = hash_lookup (map, base_key);
+
+          free (base_key);
+        }
+    }
+
+  /* Append the original suffix, if we had one.  */
+  if (ret && suffix)
+    while (*ret)
+      {
+       *ret = extend_filename (*ret, suffix);
+       ret++;
+      }
+
+  return ret;
+}
+
+/* Open and read the mapping file MAP_FILENAME, putting its entries into
+   MAP. Comments begin with % and continue to the end of the line.  Each
+   line of the file defines an entry: the first word is the real
+   filename (e.g., `ptmr'), the second word is the alias (e.g.,
+   `Times-Roman'), and any subsequent words are ignored.  .tfm is added
+   if either the filename or the alias have no extension.  This is the
+   same order as in Dvips' psfonts.map; unfortunately, we can't have TeX
+   read that same file, since most of the real filenames start with an
+   `r', because of the virtual fonts Dvips uses.  */
+
+static void
+map_file_parse P2C(hash_table_type *, map,  const_string, map_filename)
+{
+  extern FILE *xfopen ();	/* In xfopen.c.  */
+  char *l;
+  unsigned map_lineno = 0;
+  FILE *f = xfopen (map_filename, FOPEN_R_MODE);
+  
+  while ((l = read_line (f)) != NULL)
+    {
+      string filename;
+      string comment_loc = strchr (l, '%');
+      
+      map_lineno++;
+      
+      /* Ignore anything after a %.  */
+      if (comment_loc)
+        *comment_loc = 0;
+      
+      /* If we don't have any filename, that's ok, the line is blank.  */
+      filename = strtok (l, " \t");
+      if (filename)
+        {
+          string alias = strtok (NULL, " \t");
+          
+          /* But if we have a filename and no alias, something's wrong.  */
+          if (alias == NULL || *alias == 0)
+            fprintf (stderr, "%s:%u: Alias missing for filename `%s'.\n",
+                     map_filename, map_lineno, filename);
+          else
+            { /* We've got everything.  Insert the new entry.  */
+              hash_insert (map, xstrdup (alias), xstrdup (filename));
+            }
+        }
+      
+      free (l);
+    }
+  
+  xfclose (f, map_filename);
+}
+
+/* Search for all the MAP_NAME's in PATH.  */
+
+#define MAP_NAME "texfonts.map"
+
+hash_table_type
+map_create P1C(const_string, path)
+{
+  string *filenames = kpse_all_path_search (path, MAP_NAME);
+  hash_table_type map; /* some old compilers ... */
+  map = hash_create (751);
+  
+  while (*filenames)
+    {
+      map_file_parse (&map, *filenames);
+      filenames++;
+    }
+
+  return map;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/getopt.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,748 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
+   	Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#endif	/* GNU C library.  */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+static const char *
+_getopt_initialize (optstring)
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind = 1;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+  return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  optarg = NULL;
+
+  if (optind == 0)
+    optstring = _getopt_initialize (optstring);
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc
+		 && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* The special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return EOF;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return EOF;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+	/* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+	 or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	if (!strncmp (p->name, nextchar, nameend - nextchar))
+	  {
+	    if (nameend - nextchar == strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second or later nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, "%s: option `%s' is ambiguous\n",
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*nameend)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = nameend + 1;
+	      else
+		{
+		  if (opterr)
+		    {
+		      if (argv[optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+				 "%s: option `--%s' doesn't allow an argument\n",
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+			     "%s: option `%c%s' doesn't allow an argument\n",
+			     argv[0], argv[optind - 1][0], pfound->name);
+		    }
+		  nextchar += strlen (nextchar);
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr, "%s: option `%s' requires an argument\n",
+			     argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, "%s: unrecognized option `--%s'\n",
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+	    if (posixly_correct)
+	      /* 1003.2 specifies the format of this message.  */
+	      fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+	    else
+	      fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
+	  }
+	optopt = c;
+	return '?';
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = NULL;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr, "%s: option requires an argument -- %c\n",
+			     argv[0], c);
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif	/* _LIBC or not __GNU_LIBRARY__.  */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/getopt1.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,180 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
+	Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif	/* _LIBC or not __GNU_LIBRARY__.  */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+	{"add", 1, 0, 0},
+	{"append", 0, 0, 0},
+	{"delete", 1, 0, 0},
+	{"verbose", 0, 0, 0},
+	{"create", 0, 0, 0},
+	{"file", 1, 0, 0},
+	{0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+		       long_options, &option_index);
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case 0:
+	  printf ("option %s", long_options[option_index].name);
+	  if (optarg)
+	    printf (" with arg %s", optarg);
+	  printf ("\n");
+	  break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case 'd':
+	  printf ("option d with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/hash.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,171 @@
+/* hash.c: hash table operations.
+
+Copyright (C) 1994 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/hash.h>
+#include <kpathsea/str-list.h>
+
+
+/* The hash function.  We go for simplicity here.  */
+
+static unsigned
+hash P2C(hash_table_type, table,  const_string, key)
+{
+  unsigned n = 0;
+  
+  /* Our keys aren't often anagrams of each other, so no point in
+     weighting the characters.  */
+  while (*key != 0)
+    n = (n + n + *key++) % table.size;
+  
+  return n;
+}
+
+hash_table_type
+hash_create P1C(unsigned, size) 
+{
+  unsigned b;
+  hash_table_type ret;
+  ret.buckets = XTALLOC (size, hash_element_type *);
+  ret.size = size;
+  
+  /* calloc's zeroes aren't necessarily NULL, according to ANSI, so be
+     safe.  (Not that I know of any exceptions in reality.)  */
+  for (b = 0; b <ret.size; b++)
+    ret.buckets[b] = NULL;
+    
+  return ret;
+}
+
+/* Whether or not KEY is already in MAP, insert it and VALUE.  Do not
+   duplicate the strings, in case they're being purposefully shared.  */
+
+void
+hash_insert P3C(hash_table_type *, table,  const_string, key,
+                const_string, value)
+{
+  unsigned n = hash (*table, key);
+  hash_element_type *new_elt = XTALLOC1 (hash_element_type);
+
+  new_elt->key = key;
+  new_elt->value = value;
+  new_elt->next = NULL;
+  
+  /* Insert the new element at the end of the list.  */
+  if (!table->buckets[n])
+    /* first element in bucket is a special case.  */
+    table->buckets[n] = new_elt;
+  else
+    {
+      hash_element_type *loc = table->buckets[n];
+      while (loc->next)		/* Find the last element.  */
+        loc = loc->next;
+      loc->next = new_elt;	/* Insert the new one after.  */
+    }
+}
+
+/* Look up STR in MAP.  Return a (dynamically-allocated) list of the
+   corresponding strings or NULL if no match.  */ 
+
+#ifdef DEBUG
+/* Print the hash values as integers if this is nonzero.  */
+boolean kpse_debug_hash_lookup_int = false; 
+#endif
+
+string *
+hash_lookup P2C(hash_table_type, table,  const_string, key)
+{
+  hash_element_type *p;
+  str_list_type ret;
+  unsigned n = hash (table, key);
+  ret = str_list_init ();
+  
+  /* Look at everything in this bucket.  */
+  for (p = table.buckets[n]; p != NULL; p = p->next)
+    if (STREQ (key, p->key))
+      /* Cast because the general str_list_type shouldn't force const data.  */
+      str_list_add (&ret, (string) p->value);
+  
+  /* If we found anything, mark end of list with null.  */
+  if (STR_LIST (ret))
+    str_list_add (&ret, NULL);
+
+#ifdef DEBUG
+  if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
+    {
+      DEBUGF1 ("hash_lookup(%s) =>", key);
+      if (!STR_LIST (ret))
+        fputs (" (null)\n", stderr);
+      else
+        {
+          string *r;
+          for (r = STR_LIST (ret); *r; r++)
+            {
+              putc (' ', stderr);
+              if (kpse_debug_hash_lookup_int)
+                fprintf (stderr, "%ld", (long) *r);
+              else
+                fputs (*r, stderr);
+            }
+          putc ('\n', stderr);
+        }
+      fflush (stderr);
+    }
+#endif
+
+  return STR_LIST (ret);
+}
+
+/* We only print nonempty buckets, to decrease output volume.  */
+
+void
+hash_print P1C(hash_table_type, table)
+{
+  unsigned b;
+  unsigned total_elements = 0, total_buckets = 0;
+  
+  for (b = 0; b < table.size; b++)
+    {
+      hash_element_type *bucket = table.buckets[b];
+      
+      if (bucket)
+        {
+          unsigned len = 1;
+          hash_element_type *tb;
+          
+          total_buckets++;
+          printf ("%4d ", b);
+          
+          for (tb = bucket->next; tb != NULL; tb = tb->next)
+            len++;
+          printf (":%-5d", len);
+          total_elements += len;
+          
+          for (tb = bucket; tb != NULL; tb = tb->next)
+            printf (" %s=>%s", tb->key, tb->value);
+          
+          putchar ('\n');
+        }
+    }
+  
+  printf ("%u buckets, %u nonempty (%u%%); %u entries, average chain %.1f.\n",
+          table.size, total_buckets, 100 * total_buckets / table.size,
+          total_elements,
+          total_buckets ? total_elements / (double) total_buckets : 0.0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/itoa.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,29 @@
+/* itoa.c: convert an int to a string.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+
+string
+itoa P1C(int, i)
+{
+  char a[MAX_INT_LENGTH];
+  
+  sprintf (a, "%d", i);
+  return xstrdup (a);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/kdefault.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,120 @@
+/* kdefault.c: Expand extra colons.
+   (This is not named default.c because then the OSF/1 make tries to
+   make a program `default' from it, since we have a target `default';
+   and OSF/1 make doesn't understand .PHONY.)
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/default.h>
+
+
+/* Check for leading colon first, then trailing, then doubled, since
+   that is fastest.  Usually it will be leading or trailing.  */
+
+string 
+kpse_expand_default P2C(const_string, path,  const_string, fallback)
+{
+  unsigned path_length;
+  string expansion;
+  
+  /* The default path better not be null.  */
+  assert (fallback);
+  
+  if (path == NULL)
+    expansion = (string) fallback;
+
+  /* Solitary or leading :?  */
+  else if (IS_ENV_SEP (*path))
+    {
+      expansion = path[1] == 0 ? (string) fallback : concat (fallback, path);
+    }
+
+  /* Sorry about the assignment in the middle of the expression, but
+     conventions were made to be flouted and all that.  I don't see the
+     point of calling strlen twice or complicating the logic just to
+     avoid the assignment (especially now that I've pointed it out at
+     such great length).  */
+  else if (path[(path_length = strlen (path)) - 1] == ENV_SEP)
+    expansion = concat (path, fallback);
+
+  /* OK, not leading or trailing.  Check for doubled.  */
+  else
+    {
+      const_string loc;
+
+      /* What we'll return if we find none.  */
+      expansion = (string) path;
+
+      for (loc = path; *loc && expansion == path; loc++)
+        {
+          if (IS_ENV_SEP (loc[0]) && IS_ENV_SEP (loc[1]))
+            { /* We have a doubled colon.  */
+              expansion = xmalloc (path_length + strlen (fallback) + 1);
+              
+              /* Copy stuff up to and including the first colon.  */
+              strncpy (expansion, path, loc - path + 1);
+              expansion[loc - path + 1] = 0;
+              
+              /* Copy in FALLBACK, and then the rest of PATH.  */
+              strcat (expansion, fallback);
+              strcat (expansion, loc + 1);
+            }
+        }
+    }
+  
+  return expansion;
+}
+
+#ifdef TEST
+
+void
+test_expand_default (const_string path, const_string def)
+{
+  string answer;
+  
+  printf ("Expansion of `%s':\t", path ? path : "(null)");
+  answer = kpse_expand_default (path, def);
+  puts (answer);
+}
+
+int
+main ()
+{
+  string default_path = "default";
+
+  test_expand_default (NULL, default_path);
+  test_expand_default ("", default_path);
+  test_expand_default ("none", default_path);
+  test_expand_default (":", default_path);
+  test_expand_default (":first", default_path);
+  test_expand_default ("last:", default_path);
+  test_expand_default ("middle::elddim", default_path);
+  
+  return 0;
+}
+
+#endif /* TEST */
+
+
+/*
+Local variables:
+standalone-compile-command: "gcc -g -I. -I.. -DTEST default.c kpathsea.a"
+End:
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/kpsewhich.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,258 @@
+/* kpsewhich -- standalone path lookup and variable expansion for Kpathsea.
+   Ideas from Tom Esser and Pierre MacKay.
+
+Copyright (C) 1995 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+#include <kpathsea/getopt.h>
+#include <kpathsea/line.h>
+#include <kpathsea/proginit.h>
+#include <kpathsea/progname.h>
+#include <kpathsea/tex-file.h>
+#include <kpathsea/tex-glyph.h>
+#include <kpathsea/variable.h>
+
+
+/* Base resolution. (-D, -dpi) */
+unsigned dpi = 300;
+
+/* A construct to do variable expansion on.  (-expand) */
+string expand = NULL;
+
+/* The file type for lookups.  (-format) */
+kpse_file_format_type format = kpse_last_format;
+
+/* Ask interactively?  (-interactive) */
+boolean interactive = false;
+
+/* The device name, for $MAKETEX_MODE.  (-mode) */
+string mode = NULL;
+
+/* The program name, for `.program' in texmf.cnf.  (-program) */
+string progname = NULL;
+
+/* Return the <number> substring in `<name>.<number><stuff>', if S has
+   that form.  If it doesn't, return 0.  */
+
+static unsigned
+find_dpi P1C(string, s)
+{
+  unsigned dpi_number = 0;
+  string extension = find_suffix (s);
+  
+  if (extension != NULL)
+    sscanf (extension, "%u", &dpi_number);
+
+  return dpi_number;
+}
+
+/* Use the -format if specified, else guess dynamically from NAME.  */
+
+/* We could partially initialize this array from `kpse_format_info',
+   but it doesn't seem worth the trouble.  */
+static const_string suffix[]
+  = { "gf", "pk", "", ".base", ".bib", ".bst", ".cnf", ".fmt", ".mf",
+      ".pool", ".eps", ".tex", ".pool", ".tfm", ".vf", ".ps", ".pfa" };
+
+static kpse_file_format_type
+find_format P1C(string, name)
+{
+  kpse_file_format_type ret;
+  
+  if (format != kpse_last_format)
+    ret = format;
+  else
+    {
+      unsigned name_len = strlen (name);
+      for (ret = 0; ret < kpse_last_format; ret++)
+        {
+          const_string suffix_try = suffix[ret];
+          unsigned try_len = strlen (suffix_try);
+          if (try_len && try_len < name_len
+              && STREQ (suffix_try, name + name_len - try_len))
+            break;
+        }
+      if (ret == kpse_last_format)
+        {
+          fprintf (stderr,
+                   "kpsewhich: Can't guess format for %s, using tex.\n", name);
+          ret = kpse_tex_format;
+        }
+    }
+  
+  return ret;
+}
+
+/* Look up a single filename NAME.  Return 0 if success, 1 if failure.  */
+
+static unsigned
+lookup P1C(string, name)
+{
+  string ret;
+  unsigned local_dpi;
+  kpse_glyph_file_type glyph_ret;
+  kpse_file_format_type fmt = find_format (name);
+  
+  switch (fmt)
+    {
+    case kpse_pk_format:
+    case kpse_gf_format:
+    case kpse_any_glyph_format:
+      /* Try to extract the resolution from the name.  */
+      local_dpi = find_dpi (name);
+      if (!local_dpi)
+        local_dpi = dpi;
+      ret = kpse_find_glyph (remove_suffix (name), local_dpi, fmt, &glyph_ret);
+      break;
+    default:
+      ret = kpse_find_file (name, fmt, false);
+    }
+  
+  if (ret)
+    puts (ret);
+  
+  return ret == NULL;
+}
+
+/* Reading the options.  */
+
+#define USAGE "Options:\n\
+  You can use `--' or `-' to start an option.\n\
+  You can use any unambiguous abbreviation for an option name.\n\
+  You can separate option names and values with `=' or ` '.\n\
+debug <integer>: set debugging flags.\n\
+D, dpi <unsigned>: use a base resolution of <unsigned>; default 300.\n\
+expand <string>: do variable expansion on <string>.\n\
+help: print this message and exit.\n\
+interactive: ask for additional filenames to look up.\n\
+mode <string>: set device name for $MAKETEX_MODE to <string>; no default.\n\
+version: print version number and exit.\n\
+"
+
+/* Test whether getopt found an option ``A''.
+   Assumes the option index is in the variable `option_index', and the
+   option table in a variable `long_options'.  */
+#define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
+
+/* SunOS cc can't initialize automatic structs.  */
+static struct option long_options[]
+  = { { "debug",		1, 0, 0 },
+      { "dpi",			1, 0, 0 },
+      { "D",			1, 0, 0 },
+      { "expand",		1, 0, 0 },
+      { "format",		1, 0, 0 },
+      { "help",                 0, 0, 0 },
+      { "interactive",		0, (int *) &interactive, 1 },
+      { "mode",			1, 0, 0 },
+      { "program",		1, 0, 0 },
+      { "version",              0, 0, 0 },
+      { 0, 0, 0, 0 } };
+
+
+/* We return the name of the font to process.  */
+
+static void
+read_command_line P2C(int, argc,  string *, argv)
+{
+  int g;   /* `getopt' return code.  */
+  int option_index;
+
+  while (true)
+    {
+      g = getopt_long_only (argc, argv, "", long_options, &option_index);
+      
+      if (g == EOF)
+        break;
+
+      if (g == '?')
+        exit (1);  /* Unknown option.  */
+  
+      assert (g == 0); /* We have no short option names.  */
+      
+      if (ARGUMENT_IS ("debug"))
+        kpathsea_debug |= atoi (optarg);
+
+      else if (ARGUMENT_IS ("dpi") || ARGUMENT_IS ("D"))
+        dpi = atoi (optarg);
+
+      else if (ARGUMENT_IS ("expand"))
+        expand = optarg;
+
+      else if (ARGUMENT_IS ("format"))
+        format = atoi (optarg);
+
+      else if (ARGUMENT_IS ("help"))
+        {
+          printf ("Usage: %s [options] [filenames].\n", argv[0]);
+          fputs (USAGE, stdout);
+          exit (0);
+        }
+
+      else if (ARGUMENT_IS ("mode"))
+        mode = optarg;
+
+      else if (ARGUMENT_IS ("program"))
+        progname = optarg;
+
+      else if (ARGUMENT_IS ("version"))
+        {
+          extern char *kpathsea_version_string; /* from version.c */
+          printf ("%s.\n", kpathsea_version_string);
+          exit (0);
+        }
+      
+      /* Else it was just a flag; getopt has already done the assignment.  */
+    }
+}
+
+int
+main P2C(int, argc,  string *, argv)
+{
+  unsigned unfound = 0;
+  
+  read_command_line (argc, argv);
+  
+  if (!progname)
+    progname = (string) "";
+
+  kpse_set_progname (progname);
+  
+  /* false for no MakeTeXPK, NULL for no fallback font.  */
+  kpse_init_prog (uppercasify (progname), dpi, mode, false, NULL);
+  
+  /* No extra frills on expansion output, to make it easy to use.  */
+  if (expand)
+    puts (kpse_var_expand (expand));
+
+  for (; optind < argc; optind++)
+    {
+      unfound += lookup (argv[optind]);
+    }
+
+  if (interactive)
+    {
+      for (;;)
+        {
+          string name = read_line (stdin);
+          if (!name || STREQ (name, "q") || STREQ (name, "quit")) break;
+          unfound += lookup (name);
+          free (name);
+        }
+    }
+  
+  exit (unfound);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/kpsexpand.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,44 @@
+/* kpsexpand -- do Kpathsea variable expansion, pretending to be a given
+   program.  For example,
+     prompt$ kpsexpand latex2e '$TEXINPUTS'
+   expands $TEXINPUTS for latex2e.
+
+   Based on code from te@informatik.uni-hannover.de.  */
+
+/* Not worth chance of collisions to #include anything but this.  */
+#include <stdio.h> /* for stderr */
+
+#include "tex-file.h"
+extern char *kpse_var_expand ();
+extern void kpse_set_progname ();
+extern char *kpathsea_version_string;
+
+int
+main (argc, argv)
+    int argc;
+    char *argv[];
+{
+  if (argc < 3)
+    {
+      fprintf (stderr, "Usage: %s progname string [filename]\n", argv[0]);
+      fprintf (stderr, "%s\n", kpathsea_version_string);
+      fputs ("Sets the program name to `progname',\n", stderr);
+      fputs ("then prints the variable expansion of `string'.\n", stderr);
+      fputs ("If `filename' is present, does lookups of several types.\n",
+             stderr);
+      fputs ("Example: kpsexpand latex2e '$TEXFINPUTS'.\n", stderr);
+      exit (1);
+    }
+
+  kpse_set_progname (argv[1]);
+  printf ("%s\n", kpse_var_expand (argv[2]));
+
+  if (argc == 4)
+    {
+      printf ("PICT: %s\n", kpse_find_pict (argv[3]));
+      printf ("TEX: %s\n", kpse_find_tex (argv[3]));
+      printf ("TFM: %s\n", kpse_find_tfm (argv[3]));
+      printf ("VF: %s\n", kpse_find_vf (argv[3]));
+    }
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/line.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,71 @@
+/* line.c: return the next line from a file, or NULL.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Don't include config.h or all our other usual includes, since
+   it's useful to just throw this file into other programs.  */
+
+#include <stdio.h>
+extern void free ();
+
+/* From xmalloc.c and xrealloc.c.  This saves having to include config.h.  */
+extern void *xmalloc (), *xrealloc ();
+
+
+/* Allocate in increments of this size.  */
+#define BLOCK_SIZE 40
+
+char *
+read_line (f)
+    FILE *f;
+{
+  int c;
+  unsigned limit = BLOCK_SIZE;
+  unsigned loc = 0;
+  char *line = xmalloc (limit);
+  
+  while ((c = getc (f)) != EOF && c != '\n')
+    {
+      line[loc] = c;
+      loc++;
+      
+      /* By testing after the assignment, we guarantee that we'll always
+         have space for the null we append below.  We know we always
+         have room for the first char, since we start with BLOCK_SIZE.  */
+      if (loc == limit)
+        {
+          limit += BLOCK_SIZE;
+          line = xrealloc (line, limit);
+        }
+    }
+  
+  /* If we read anything, return it.  This can't represent a last
+     ``line'' which doesn't end in a newline, but so what.  */
+  if (c != EOF)
+    {
+      /* Terminate the string.  We can't represent nulls in the file,
+         either.  Again, it doesn't matter.  */
+      line[loc] = 0;
+    }
+  else /* At end of file.  */
+    {
+      free (line);
+      line = NULL;
+    }
+
+  return line;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/magstep.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,100 @@
+/* magstep.c: fix up fixed-point vs. floating-point.
+
+Copyright (C) 1994 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/magstep.h>
+
+
+/* Return true magstep N, where the lsb of N means ``half'' (see
+   magstep.h) for resolution BDPI.  From Tom Rokicki's dvips.  */
+
+static int
+magstep P2C(int, n,  int, bdpi)
+{
+   double t;
+   int step;
+   int neg = 0;
+
+   if (n < 0)
+     {
+       neg = 1;
+       n = -n;
+     }
+
+   if (n & 1)
+     {
+       n &= ~1;
+       t = 1.095445115;
+     }
+    else
+      t = 1.0;
+
+   while (n > 8)
+     {
+       n -= 8;
+       t = t * 2.0736;
+     }
+
+   while (n > 0)
+     {
+       n -= 2;
+       t = t * 1.2;
+     }
+
+   step = 0.5 + (neg ? bdpi / t : bdpi * t);
+   return step;
+}
+
+/* This is adapted from code written by Tom Rokicki for dvips.  It's
+   part of Kpathsea now so all the drivers can use it.  The idea is to
+   return the true dpi corresponding to DPI with a base resolution of
+   BDPI.  If M_RET is non-null, we also set that to the mag value.  */
+   
+/* Don't bother trying to use fabs or some other ``standard'' routine
+   which can only cause trouble; just roll our own simple-minded
+   absolute-value function that is all we need.  */
+#undef ABS /* be safe */
+#define ABS(expr) ((expr) < 0 ? -(expr) : (expr))
+
+#define MAGSTEP_MAX 40
+
+unsigned
+kpse_magstep_fix P3C(unsigned, dpi,  unsigned, bdpi,  int *, m_ret)
+{
+  int m;
+  int mdpi = -1;
+  unsigned real_dpi = 0;
+  int sign = dpi < bdpi ? -1 : 1; /* negative or positive magsteps? */
+  
+  for (m = 0; !real_dpi && m < MAGSTEP_MAX; m++) /* don't go forever */
+    {
+      mdpi = magstep (m * sign, bdpi);
+      if (ABS (mdpi - (int) dpi) <= 1) /* if this magstep matches, quit */
+        real_dpi = mdpi;
+      else if ((mdpi - (int) dpi) * sign > 0) /* if gone too far, quit */
+        real_dpi = dpi;
+    }
+  
+  /* If requested, return the encoded magstep (the loop went one too far).  */
+  if (m_ret)
+    *m_ret = real_dpi == mdpi ? (m - 1) * sign : 0;
+
+  /* Always return the true dpi found.  */
+  return real_dpi ? real_dpi : dpi;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/make-suffix.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,44 @@
+/* make_suffix.c: unconditionally add a filename suffix.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+
+/* Return a new string: S suffixed with SUFFIX, regardless of what it
+   was before. This returns a newly allocated string.  */ 
+
+string
+make_suffix P2C(const_string, s,  const_string, suffix)
+{
+  string new_s;
+  const_string dot_pos = strrchr (s, '.');
+  const_string slash_pos = strrchr (s, '/');
+
+  if (dot_pos == NULL || dot_pos < slash_pos)
+    new_s = concat3 (s, ".", suffix);
+  else
+    {
+      unsigned past_dot_index = dot_pos + 1 - s;
+      
+      new_s = (string) xmalloc (past_dot_index + strlen (suffix) + 1);
+      strncpy (new_s, s, dot_pos + 1 - s);
+      strcpy (new_s + past_dot_index, suffix);
+    }
+
+  return new_s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/path-elt.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,133 @@
+/* path-elt.c: Return the stuff between colons.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/pathsearch.h>
+
+
+/* The static (but dynamically allocated) area we return the answer in,
+   and how much we've currently allocated for it.  */
+static string elt = NULL;
+static unsigned elt_alloc = 0;
+
+/* The path we're currently working on.  */
+static const_string path = NULL;
+
+
+/* Upon entry, the static `path' is at the first (and perhaps last)
+   character of the return value, or else NULL if we're at the end (or
+   haven't been called).  I make no provision for caching the results;
+   thus, we parse the same path over and over, on every lookup.  If that
+   turns out to be a significant lose, it can be fixed, but I'm guessing
+   disk accesses overwhelm everything else.  */
+
+string
+kpse_path_element P1C(const_string, passed_path)
+{
+  const_string p;
+  string ret;
+  
+  if (passed_path)
+    path = passed_path;
+  
+  /* Check if called with NULL, and no previous path (perhaps we reached
+     the end).  */
+  else if (!path)
+    return NULL;
+  
+  /* OK, we have a non-null `path' if we get here.  */
+  assert (path);
+  p = path;
+  
+  /* Find the next colon (or the end of the path).  */
+  while (*p != 0 && !IS_ENV_SEP (*p))
+    p++;
+  
+  /* If there were no separators, return the whole thing this time, and
+     return NULL next time.  */
+  if (*p == 0)
+    {
+      ret = (string) path;
+      path = NULL;
+    }
+  
+  /* Otherwise, return the substring starting at `path'.  */
+  else
+    {
+      unsigned len = p - path;
+      
+      /* Make sure we have enough space (including the null byte).  */
+      if (len + 1 > elt_alloc)
+        {
+          elt_alloc = len + 1;
+          elt = xrealloc (elt, elt_alloc);
+        }
+
+      strncpy (elt, path, len);
+      elt[len] = 0;
+      ret = elt;
+      
+      path += len + 1;
+    }
+
+  return ret;
+}
+
+#ifdef TEST
+
+void
+print_path_elements (const_string path)
+{
+  string elt;
+  printf ("Elements of `%s':", path ? path : "(null)");
+  
+  for (elt = kpse_path_element (path); elt != NULL;
+       elt = kpse_path_element (NULL))
+    {
+      printf (" %s", *elt ? elt : "`'");
+    }
+  
+  puts (".");
+}
+
+int
+main ()
+{
+  /* All lists end with NULL.  */
+  print_path_elements (NULL);	/* */
+  print_path_elements ("");	/* "" */
+  print_path_elements ("a");	/* a */
+  print_path_elements (":");	/* "", "" */
+  print_path_elements ("::");	/* "", "", "" */
+  print_path_elements ("a:");	/* a, "" */ 
+  print_path_elements (":b");	/* "", b */ 
+  print_path_elements ("a:b");	/* a, b */ 
+  
+  return 0;
+}
+
+#endif /* TEST */
+
+
+/*
+Local variables:
+standalone-compile-command: "gcc -g -I. -I.. -DTEST path-elt.c kpathsea.a"
+End:
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/pathsearch.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,405 @@
+/* pathsearch.c: look up a filename in a path.
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-fopen.h>
+#include <kpathsea/absolute.h>
+#include <kpathsea/expand.h>
+#include <kpathsea/db.h>
+#include <kpathsea/pathsearch.h>
+#include <kpathsea/readable.h>
+#include <kpathsea/str-list.h>
+#include <kpathsea/str-llist.h>
+#include <kpathsea/variable.h>
+
+#include <time.h> /* for `time' */
+
+/* This function is called after every search to record the filename(s)
+   found in $TEXMFLOG or if debugging.  */
+
+static void
+log_search P1C(str_list_type, filenames)
+{
+  static FILE *log_file = NULL;
+  static boolean first_time = true;
+  
+  if (first_time)
+    {
+      string log_name = kpse_var_expand ("$TEXMFLOG");
+      first_time = false;
+      /* Get name from either envvar or config file.  */
+      if (log_name && *log_name)
+        {
+          log_file = fopen (log_name, FOPEN_A_MODE);
+          if (!log_file)
+            perror (log_name);
+          free (log_name);
+        }
+    }
+
+  if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH) || log_file)
+    {
+      unsigned e;
+      
+      /* FILENAMES should never be null, but safety doesn't hurt.  */
+      for (e = 0;
+           e < STR_LIST_LENGTH (filenames) && STR_LIST_ELT (filenames, e);
+           e++)
+        {
+          string filename = STR_LIST_ELT (filenames, e);
+          
+          /* Only record absolute filenames, for privacy.  */
+          if (log_file && kpse_absolute_p (filename, false))
+            fprintf (log_file, "%u %s\n", time (NULL), filename);
+
+          /* And show them online, if debugging.  We've already started
+             the debugging line in `search', where this is called, so
+             just print the filename here, don't use DEBUGF.  */
+          if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
+            fputs (filename, stderr);
+        }
+    }
+}
+
+/* Concatenate each element in DIRS with NAME (assume each ends with a
+   /, to save time).  If SEARCH_ALL is false, return the first readable
+   regular file.  Else continue to search for more.  In any case, if
+   none, return a list containing just NULL.
+
+   We keep a single buffer for the potential filenames and reallocate
+   only when necessary.  I'm not sure it's noticeably faster, but it
+   does seem cleaner.  (We do waste a bit of space in the return
+   value, though, since we don't shrink it to the final size returned.)  */
+
+#define INIT_ALLOC 75  /* Doesn't much matter what this number is.  */
+
+static str_list_type
+dir_list_search P3C(str_llist_type *, dirs,  const_string, name,
+                    boolean, search_all)
+{
+  str_llist_elt_type *elt;
+  str_list_type ret;
+  unsigned name_len = strlen (name);
+  unsigned allocated = INIT_ALLOC;
+  string potential = xmalloc (allocated);
+
+  ret = str_list_init ();
+  
+  for (elt = *dirs; elt; elt = STR_LLIST_NEXT (*elt))
+    {
+      const_string dir = STR_LLIST (*elt);
+      unsigned dir_len = strlen (dir);
+      
+      while (dir_len + name_len + 1 > allocated)
+        {
+          allocated += allocated;
+          XRETALLOC (potential, allocated, char);
+        }
+      
+      strcpy (potential, dir);
+      strcat (potential, name);
+      
+      if (kpse_readable_file (potential))
+        { 
+          str_list_add (&ret, potential);
+          
+          /* Move this element towards the top of the list.  */
+          str_llist_float (dirs, elt);
+          
+          /* If caller only wanted one file returned, no need to
+             terminate the list with NULL; the caller knows to only look
+             at the first element.  */
+          if (!search_all)
+            return ret;
+
+          /* Start new filename.  */
+          allocated = INIT_ALLOC;
+          potential = xmalloc (allocated);
+        }
+    }
+  
+  /* If we get here, either we didn't find any files, or we were finding
+     all the files.  But we're done with the last filename, anyway.  */
+  free (potential);
+  
+  return ret;
+}
+
+/* This is called when NAME is absolute or explicitly relative; if it's
+   readable, return (a list containing) it; otherwise, return NULL.  */
+
+static str_list_type
+absolute_search P1C(string, name)
+{
+  str_list_type ret_list;
+  string found = kpse_readable_file (name);
+  
+  /* Some old compilers can't initialize structs.  */
+  ret_list = str_list_init ();
+
+  /* If NAME wasn't found, free the expansion.  */
+  if (name != found)
+    free (name);
+
+  /* Add `found' to the return list even if it's null; that tells
+     the caller we didn't find anything.  */
+  str_list_add (&ret_list, found);
+  
+  return ret_list;
+}
+
+/* If DB_DIR is a prefix of PATH_ELT, return true; otherwise false.
+   That is, the question is whether to try the db for a file looked up
+   in PATH_ELT.  If PATH_ELT == ".", for example, the answer is no. If
+   PATH_ELT == "/usr/local/lib/texmf/fonts//tfm", the answer is yes.
+   
+   In practice, ls-R is only needed for lengthy subdirectory
+   comparisons, but there's no gain to checking PATH_ELT to see if it is
+   a subdir match, since the only way to do that is to do a string
+   search in it, which is all we do anyway.
+   
+   In fact, we do a simple string compare, ignoring // complications,
+   since in practice I believe //'s will always be after `kpse_db_dir',
+   i.e., we would never want to find ls-R in /usr//texmf.  */
+   
+static boolean
+elt_in_db P1C(const_string, path_elt)
+{
+  boolean found = false;
+  
+  /* If `kpse_db_dir' is not set, we're being called from `read_files'
+     for the very first time -- for cnf file initialization.  We can't
+     use ls-R for that.  */
+  if (kpse_db_dir)
+    {
+      string db_temp = kpse_db_dir;
+
+      while (!found && *db_temp++ == *path_elt++)
+        { /* If we've matched the entire db directory, it's good.  */
+          if (*db_temp == 0)
+            found = true;
+          /* If we've reached the end of PATH_ELT, but not the end of the db
+             directory, it's no good.  */
+          else if (*path_elt == 0)
+            break;
+        }
+    }
+
+  return found;
+}
+
+
+/* This is the hard case -- look for NAME in PATH.  If
+   ALL is false, just return the first file found.  Otherwise,
+   search all elements of PATH.  */
+
+static str_list_type
+path_search P4C(const_string, path,  string, name,
+                boolean, must_exist,  boolean, all)
+{
+  string elt;
+  str_list_type ret_list;
+  boolean done = false;
+  ret_list = str_list_init (); /* some compilers lack struct initialization */
+
+  for (elt = kpse_path_element (path); !done && elt;
+       elt = kpse_path_element (NULL))
+    {
+      boolean try_db;
+      boolean allow_disk_search = true;
+      str_list_type *found = NULL;
+      
+      if (*elt == '!' && *(elt + 1) == '!')
+        { /* Magic leading chars in a path element means don't search the
+             disk regardless.  And move past the magic to get to the name.  */
+          allow_disk_search = false;
+          elt += 2;
+        }
+      
+      /* Try the prebuilt db only if it's relevant to this path element. */
+      try_db = elt_in_db (elt);
+      found = try_db ? kpse_db_search (name, elt, all) : NULL;
+      
+      /* Search the filesystem if (1) the path spec allows it, and either
+         (2a) the db was irrelevant to ELT (try_db == false); or
+         (2b) no db exists (kpse_db_search returns NULL); or
+         (3) NAME was not in the db (kpse_db_search returns an empty list)
+             and MUST_EXIST.
+         In (2a) and (2b), `found' will be NULL.  */
+      if (allow_disk_search && (!found || (!STR_LIST (*found) && must_exist)))
+        {
+          str_llist_type *dirs = kpse_element_dirs (elt);
+          if (dirs && *dirs)
+            {
+              if (!found)
+                found = XTALLOC1 (str_list_type);
+              *found = dir_list_search (dirs, name, all);
+            }
+        }
+
+      /* Did we find anything anywhere?  */
+      if (found && STR_LIST (*found))
+        if (all)
+          str_list_concat (&ret_list, *found);
+        else
+          {
+            str_list_add (&ret_list, STR_LIST_ELT (*found, 0));
+            done = true;
+          }
+      
+      /* Free the list space, if any (but not the elements).  */
+      if (found)
+        free (found);
+    }
+
+  /* Free the expanded name we were passed.  It can't be in the return
+     list, since the path directories got unconditionally prepended.  */
+  free (name);
+  
+  return ret_list;
+}      
+
+/* Search PATH for ORIGINAL_NAME.  If ALL is false, or ORIGINAL_NAME is
+   absolute_p, check ORIGINAL_NAME itself.  Otherwise, look at each
+   element of PATH for the first readable ORIGINAL_NAME.
+   
+   Always return a list; if no files are found, the list will
+   contain just NULL.  If ALL is true, the list will be
+   terminated with NULL.  */
+
+static string *
+search P4C(const_string, path,  const_string, original_name,
+           boolean, must_exist,  boolean, all)
+{
+  str_list_type ret_list;
+
+  /* Make a leading ~ count as an absolute filename, and expand $FOO's.  */
+  string name = kpse_expand (original_name);
+  
+  /* If the first name is absolute or explicitly relative, no need to
+     consider PATH at all.  */
+  boolean absolute_p = kpse_absolute_p (name, true);
+  
+  if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
+    DEBUGF4 ("search(file=%s, must_exist=%d, find_all=%d, path=%s).\n",
+             name, must_exist, all, path);
+
+  /* Find the file(s). */
+  ret_list = absolute_p ? absolute_search (name)
+                        : path_search (path, name, must_exist, all);
+  
+  /* Append NULL terminator if we didn't find anything at all, or we're
+     supposed to find ALL and the list doesn't end in NULL now.  */
+  if (STR_LIST_LENGTH (ret_list) == 0
+      || (all && STR_LIST_LAST_ELT (ret_list) != NULL))
+    str_list_add (&ret_list, NULL);
+
+  /* Record the filenames we found, if desired.  And wrap them in a
+     debugging line if we're doing that.  */
+  if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
+    DEBUGF1 ("search(%s) =>", original_name);
+  log_search (ret_list);
+  if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
+    putc ('\n', stderr);
+  
+  return STR_LIST (ret_list);
+}
+
+/* Search PATH for the first NAME.  */
+
+string
+kpse_path_search P3C(const_string, path,  const_string, name,
+                     boolean, must_exist)
+{
+  string *ret_list = search (path, name, must_exist, false);
+  return *ret_list;
+}
+
+
+/* Search all elements of PATH for files named NAME.  Not sure if it's
+   right to assert `must_exist' here, but it suffices now.  */
+
+string *
+kpse_all_path_search P2C(const_string, path,  const_string, name)
+{
+  string *ret = search (path, name, true, true);
+  return ret;
+}
+
+#ifdef TEST
+
+void
+test_path_search (const_string path, const_string file)
+{
+  string answer;
+  string *answer_list;
+  
+  printf ("\nSearch %s for %s:\t", path, file);
+  answer = kpse_path_search (path, file);
+  puts (answer ? answer : "(null)");
+
+  printf ("Search %s for all %s:\t", path, file);
+  answer_list = kpse_all_path_search (path, file);
+  putchar ('\n');
+  while (*answer_list)
+    {
+      putchar ('\t');
+      puts (*answer_list);
+      answer_list++;
+    }
+}
+
+#define TEXFONTS "/usr/local/lib/tex/fonts"
+
+int
+main ()
+{
+  /* All lists end with NULL.  */
+  test_path_search (".", "nonexistent");
+  test_path_search (".", "/nonexistent");
+  test_path_search ("/k:.", "kpathsea.texi");
+  test_path_search ("/k:.", "/etc/fstab");
+  test_path_search (".:" TEXFONTS "//", "cmr10.tfm");
+  test_path_search (".:" TEXFONTS "//", "logo10.tfm");
+  test_path_search (TEXFONTS "//times:.::", "ptmr.vf");
+  test_path_search (TEXFONTS "/adobe//:"
+                    "/usr/local/src/TeX+MF/typefaces//", "plcr.pfa");
+  
+  test_path_search ("~karl", ".bashrc");
+  test_path_search ("/k", "~karl/.bashrc");
+
+  xputenv ("NONEXIST", "nonexistent");
+  test_path_search (".", "$NONEXISTENT");
+  xputenv ("KPATHSEA", "kpathsea");
+  test_path_search ("/k:.", "$KPATHSEA.texi");  
+  test_path_search ("/k:.", "${KPATHSEA}.texi");  
+  test_path_search ("$KPATHSEA:.", "README");  
+  test_path_search (".:$KPATHSEA", "README");  
+  
+  return 0;
+}
+
+#endif /* TEST */
+
+
+/*
+Local variables:
+test-compile-command: "gcc -posix -g -I. -I.. -DTEST pathsearch.c kpathsea.a"
+End:
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/proginit.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,63 @@
+/* proginit.c: useful initializations for DVI drivers.
+
+Copyright (C) 1994 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/proginit.h>
+#include <kpathsea/progname.h>
+#include <kpathsea/tex-file.h>
+
+
+/* These initializations were common to all the drivers modified for
+   kpathsea, so a single routine seemed in order.  Kind of a bollixed-up
+   mess, but still better than repeating the code.  */
+
+void
+kpse_init_prog P5C(const_string, prefix,  unsigned, dpi,  const_string, mode,
+                   boolean, make_tex_pk,  const_string, fallback)
+{
+  string makepk_var = concat (prefix, "MAKEPK");
+  string font_var = concat (prefix, "FONTS");
+  string size_var = concat (prefix, "SIZES");
+  
+  /* Do both `pk_format' and `any_glyph_format' for the sake of xdvi; in
+     general, MakeTeXPK might apply to either, and the program will ask
+     for the one it wants.  */
+     
+  /* Might have a program-specific name for MakeTeXPK itself.  */
+  kpse_format_info[kpse_pk_format].program
+    = kpse_format_info[kpse_any_glyph_format].program
+    = getenv (makepk_var);
+  
+  /* If we did, we want to enable the program, I think.  */
+  kpse_format_info[kpse_pk_format].program_enabled_p
+    = kpse_format_info[kpse_any_glyph_format].program_enabled_p
+    = getenv (makepk_var) || make_tex_pk;
+
+  kpse_font_override_path = getenv (font_var);
+  kpse_init_fallback_resolutions (size_var);
+  xputenv_int ("MAKETEX_BASE_DPI", dpi);
+  kpse_fallback_font = fallback;
+  
+  /* See comments in kpse_make_tex in kpathsea/tex-make.c.  */
+  xputenv ("MAKETEX_MODE", mode ? mode : DIR_SEP_STRING);
+  
+  free (makepk_var);
+  free (font_var);
+  free (size_var);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/progname.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,43 @@
+/* progname.c: the executable name we were invoked as; general initialization.
+
+Copyright (C) 1994 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/progname.h>
+
+
+#ifndef HAVE_PROGRAM_INVOCATION_NAME
+/* Don't redefine the variables if glibc already has.  */
+string program_invocation_name;
+string program_invocation_short_name;
+#endif
+
+
+void
+kpse_set_progname P1C(const_string, progname)
+{
+#ifndef HAVE_PROGRAM_INVOCATION_NAME
+  program_invocation_name = xstrdup (progname);
+  program_invocation_short_name = (string) basename (program_invocation_name);
+#endif
+  {
+    string s = getenv ("KPATHSEA_DEBUG");
+    if (s) 
+     kpathsea_debug |= atoi (s);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/putenv.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,118 @@
+/****************************************************************/
+/*								*/
+/*	putenv(3)						*/
+/*								*/
+/*		Change or add an environment entry		*/
+/*								*/
+/****************************************************************/
+/*   origination        1987-Oct-7               T. Holm	*/
+/* (slightly modified by karl@cs.umb.edu for kpathsea.)         */
+/****************************************************************/
+
+/* for HAVE_PUTENV and const -- need nothing else.  */
+#include <kpathsea/c-auto.h>
+
+#ifndef HAVE_PUTENV /* whole file */
+
+/*
+Path: hoptoad!pacbell!ames!ll-xn!mit-eddie!uw-beaver!ssc-vax!uvicctr!tholm
+From: tholm@uvicctr.UUCP (Terrence W. Holm)
+Newsgroups: comp.os.minix
+Subject: putenv(3)
+Message-ID: <395@uvicctr.UUCP>
+Date: 5 May 88 06:40:52 GMT
+Organization: University of Victoria, Victoria B.C. Canada
+
+EFTH Minix report #2  - May 1988 -  putenv(3)
+
+This is an implementation of putenv(3) that we
+wrote for Minix. Please consider this a public
+domain program.
+*/
+
+#define NULL 0
+#define  PSIZE  sizeof(char *)
+
+extern  char  **environ;
+
+char  *strchr();
+char  *malloc();
+
+/****************************************************************/
+/*								*/
+/*      int							*/
+/*	putenv( entry )						*/
+/*								*/
+/*		The "entry" should follow the form 		*/
+/*		"NAME=VALUE". This routine will search the 	*/
+/*		user environment for "NAME" and replace its 	*/
+/*		value with "VALUE".				*/
+/*								*/
+/*		Note that "entry" is not copied, it is used 	*/
+/*		as the environment entry. This means that it 	*/
+/*		must not be unallocated or otherwise modifed 	*/
+/*		by the caller, unless it is replaced by a 	*/
+/*		subsequent putenv().				*/
+/*								*/
+/*		If the name is not found in the environment, 	*/
+/*		then a new vector of pointers is allocated, 	*/
+/*		"entry" is put at the end and the global 	*/
+/*		variable "environ" is updated.			*/
+/*								*/
+/*		This function normally returns 0, but -1	*/
+/*		is returned if it can not allocate enough 	*/
+/*		space using malloc(3), or "entry" does not	*/
+/*		contain a '='.					*/
+/*								*/
+/****************************************************************/
+
+
+int
+putenv( entry )
+  char *entry;
+{
+  unsigned length;
+  unsigned size;
+  char     *temp;
+  char     **p;
+  char     **new_environ;
+
+  /*  Find the length of the "NAME="  */
+
+  temp = strchr(entry,'=');
+  if ( temp == 0 )
+    return( -1 );
+
+  length = (unsigned) (temp - entry + 1);
+
+
+  /*  Scan through the environment looking for "NAME="  */
+
+  for ( p=environ; *p != 0 ; p++ )
+    if ( strncmp( entry, *p, length ) == 0 )
+      {
+      *p = entry;
+      return( 0 );
+      }
+
+
+  /*  The name was not found, build a bigger environment  */
+
+  size = p - environ;
+
+  new_environ = (char **) malloc( (size+2)*PSIZE );
+
+  if ( new_environ == (char **) NULL )
+    return( -1 );
+
+  memcpy ((char *) new_environ, (const char *) environ, size*PSIZE );
+
+  new_environ[size]   = entry;
+  new_environ[size+1] = NULL;
+
+  environ = new_environ;
+
+  return(0);
+}
+
+#endif /* not HAVE_PUTENV */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/readable.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,71 @@
+/* readable.c: check if a filename is a readable regular file.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-stat.h>
+#include <kpathsea/readable.h>
+#include <kpathsea/truncate.h>
+
+
+/* If access can read FN, run stat (assigning to stat buffer ST) and
+   check that fn is a regular file.  */
+
+#define READABLE(fn, st) \
+  (access (fn, R_OK) == 0 && stat (fn, &(st)) == 0 && S_ISREG (st.st_mode))
+
+
+/* POSIX invented the brain-damage of not necessarily truncating
+   filename components; the system's behavior is defined by the value of
+   the symbol _POSIX_NO_TRUNC, but you can't change it dynamically!
+   
+   Generic const return warning.  See extend-fname.c.  */
+
+string
+kpse_readable_file P1C(const_string, name)
+{
+  struct stat st;
+  string ret;
+  
+  if (READABLE (name, st))
+    ret = (string) name;
+
+#ifdef ENAMETOOLONG
+  else if (errno == ENAMETOOLONG)
+    {
+      ret = kpse_truncate_filename (name);
+
+      /* Perhaps some other error will occur with the truncated name, so
+         let's call access again.  */
+      if (!READABLE (ret, st))
+        { /* Failed.  */
+          if (ret != name) free (ret);
+          ret = NULL;
+        }
+    }
+#endif
+
+  else /* Some other error.  */
+    { 
+      if (errno == EACCES) /* Warn them if permissions are bad.  */
+        perror (name);
+      ret = NULL;
+    }
+  
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/rm-suffix.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,42 @@
+/* rm-suffix.c: remove any suffix.
+
+Copyright (C) 1992, 93, 95 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+
+/* Generic const warning -- see extend-fname.c.  */
+
+string
+remove_suffix P1C(const_string, s)
+{
+  string ret;
+  const_string suffix = find_suffix (s);
+  
+  if (suffix)
+    {
+      /* Back up to before the dot.  */
+      suffix--;
+      ret = (string) xmalloc (suffix - s + 1);
+      strncpy (ret, s, suffix - s);
+      ret[suffix - s] = 0;
+    }
+  else
+    ret = (string) s;
+    
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/str-list.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,75 @@
+/* str-list.c: define routines for string lists.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/str-list.h>
+
+
+/* See the .h file for comments.  */
+
+
+str_list_type
+str_list_init P1H(void)
+{
+  str_list_type ret;
+  
+  STR_LIST_LENGTH (ret) = 0;
+  STR_LIST (ret) = NULL;
+  
+  return ret;
+}
+
+
+void
+str_list_add P2C(str_list_type *, l,  string, s)
+{
+  STR_LIST_LENGTH (*l)++;
+  XRETALLOC (STR_LIST (*l), STR_LIST_LENGTH (*l), string);
+  STR_LIST_LAST_ELT (*l) = s;
+}
+
+
+/* May as well save some reallocations and do everything in a chunk
+   instead of calling str_list_add on each element.  */
+   
+void
+str_list_concat P2C(str_list_type *, target,  str_list_type, more)
+{
+  unsigned e;
+  unsigned prev_len = STR_LIST_LENGTH (*target);
+
+  STR_LIST_LENGTH (*target) += STR_LIST_LENGTH (more);
+  XRETALLOC (STR_LIST (*target), STR_LIST_LENGTH (*target), string);
+  
+  for (e = 0; e < STR_LIST_LENGTH (more); e++)
+    STR_LIST_ELT (*target, prev_len + e) = STR_LIST_ELT (more, e);
+}
+
+
+/* Free the list (but not the elements within it).  */
+
+void
+str_list_free P1C(str_list_type *, l)
+{
+  if (STR_LIST (*l))
+    {
+      free (STR_LIST (*l));
+      STR_LIST (*l) = NULL;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/str-llist.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,94 @@
+/* str-llist.c: Implementation of a linked list of strings.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/str-llist.h>
+
+
+/* Add the new string STR to the end of the list L.  */
+
+void
+str_llist_add P2C(str_llist_type *, l,  string, str)
+{
+  str_llist_elt_type *e;
+  str_llist_elt_type *new_elt = XTALLOC1 (str_llist_elt_type);
+  
+  /* The new element will be at the end of the list.  */
+  STR_LLIST (*new_elt) = str;
+  STR_LLIST_MOVED (*new_elt) = false;
+  STR_LLIST_NEXT (*new_elt) = NULL;
+  
+  /* Find the current end of the list.  */
+  for (e = *l; e && STR_LLIST_NEXT (*e); e = STR_LLIST_NEXT (*e))
+    ;
+  
+  if (!e)
+    *l = new_elt;
+  else
+    STR_LLIST_NEXT (*e) = new_elt;
+}
+
+/* Move an element towards the top. The idea is that when a file is
+   found in a given directory, later files will likely be in that same
+   directory, and looking for the file in all the directories in between
+   is thus a waste.  */
+
+void
+str_llist_float P2C(str_llist_type *, l,  str_llist_elt_type *, mover)
+{
+  str_llist_elt_type *last_moved, *unmoved;
+  
+  /* If we've already moved this element, never mind.  */
+  if (STR_LLIST_MOVED (*mover))
+    return;
+  
+  /* Find the first unmoved element (to insert before).  We're
+     guaranteed this will terminate, since MOVER itself is currently
+     unmoved, and it must be in L (by hypothesis).  */
+  for (last_moved = NULL, unmoved = *l; STR_LLIST_MOVED (*unmoved);
+       last_moved = unmoved, unmoved = STR_LLIST_NEXT (*unmoved))
+    ;
+
+  /* If we are the first unmoved element, nothing to relink.  */
+  if (unmoved != mover)
+    { /* Remember `mover's current successor, so we can relink `mover's
+         predecessor to it.  */
+      str_llist_elt_type *before_mover;
+      str_llist_elt_type *after_mover = STR_LLIST_NEXT (*mover);
+      
+      /* Find `mover's predecessor.  */
+      for (before_mover = unmoved; STR_LLIST_NEXT (*before_mover) != mover;
+           before_mover = STR_LLIST_NEXT (*before_mover))
+        ;
+      
+      /* `before_mover' now links to `after_mover'.  */
+      STR_LLIST_NEXT (*before_mover) = after_mover;
+
+      /* Insert `mover' before `unmoved' and after `last_moved' (or at
+         the head of the list).  */
+      STR_LLIST_NEXT (*mover) = unmoved;
+      if (!last_moved)
+        *l = mover;
+      else
+        STR_LLIST_NEXT (*last_moved) = mover;
+    }
+
+  /* We've moved it.  */
+  STR_LLIST_MOVED (*mover) = true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/tex-file.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,344 @@
+/* tex-file.c: stuff for all TeX formats.
+
+Copyright (C) 1993, 94, 95 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-vararg.h>
+#include <kpathsea/cnf.h>
+#include <kpathsea/default.h>
+#include <kpathsea/expand.h>
+#include <kpathsea/paths.h>
+#include <kpathsea/pathsearch.h>
+#include <kpathsea/tex-file.h>
+
+
+/* See tex-file.h.  */
+const_string kpse_fallback_font = NULL;
+unsigned *kpse_fallback_resolutions = NULL;
+string kpse_font_override_path = NULL;
+kpse_format_info_type kpse_format_info[kpse_last_format];
+
+/* These are not in the structure
+   because it's annoying to initialize lists in C.  */
+#define KPSE_GF_ENVS "GFFONTS", KPSE_GLYPH_ENVS
+#define KPSE_PK_ENVS "PKFONTS", "TEXPKS", KPSE_GLYPH_ENVS
+#define KPSE_GLYPH_ENVS "GLYPHFONTS", "TEXFONTS"
+#define KPSE_BASE_ENVS "MFBASES"
+#define KPSE_BIB_ENVS "BIBINPUTS"
+#define KPSE_BST_ENVS "BSTINPUTS"
+#define KPSE_CNF_ENVS "TEXMFCNF"
+#define KPSE_FMT_ENVS "TEXFORMATS"
+#define KPSE_MF_ENVS "MFINPUTS"
+#define KPSE_MFPOOL_ENVS "MFPOOL"
+#define KPSE_PICT_ENVS "TEXPICTS", KPSE_TEX_ENVS
+#define KPSE_TEX_ENVS "TEXINPUTS"
+#define KPSE_TEXPOOL_ENVS "TEXPOOL"
+#define KPSE_TFM_ENVS "TFMFONTS", "TEXFONTS"
+#define KPSE_VF_ENVS "VFFONTS", "TEXFONTS"
+#define KPSE_DVIPS_CONFIG_ENVS "TEXCONFIG"
+#define KPSE_DVIPS_HEADER_ENVS "DVIPSHEADERS"
+
+/* The compiled-in default list, DEFAULT_FONT_SIZES, is intended to be
+   set from the command line (presumably via the Makefile).  */
+
+#ifndef DEFAULT_FONT_SIZES
+#define DEFAULT_FONT_SIZES ""
+#endif
+
+void
+kpse_init_fallback_resolutions P1C(string, envvar)
+{
+  const_string size_var = ENVVAR (envvar, "TEXSIZES");
+  string size_str = getenv (size_var);
+  unsigned *last_resort_sizes = NULL;
+  unsigned size_count = 0;
+  string size_list = kpse_expand_default (size_str, DEFAULT_FONT_SIZES);
+
+  /* Initialize the list of last-resort sizes.  */
+  for (size_str = kpse_path_element (size_list); size_str != NULL;
+       size_str = kpse_path_element (NULL))
+    {
+      if (! *size_str)
+        continue;
+
+      size_count++;
+      XRETALLOC (last_resort_sizes, size_count, unsigned);
+      last_resort_sizes[size_count - 1] = atoi (size_str);
+    }
+
+  /* Add a zero to mark the end of the list.  */
+  size_count++;
+  XRETALLOC (last_resort_sizes, size_count, unsigned);
+  last_resort_sizes[size_count - 1] = 0;
+
+  kpse_fallback_resolutions = last_resort_sizes;
+}
+
+/* Find the final search path to use for the format entry INFO, given
+   FONT_P (whether the font override path applies), the compile-time
+   default (DEFAULT_PATH), and the environment variables to check (the
+   remaining arguments, terminated with NULL).  We set the `path' and
+   `path_source' members of INFO.  The `client_path' member must already
+   be set upon entry.  */
+   
+#define EXPAND_DEFAULT(try_path, source_string)			\
+if (try_path)							\
+  {								\
+    info->raw_path = try_path;					\
+    info->path = kpse_expand_default (try_path, info->path);	\
+    info->path_source = source_string;				\
+  }
+
+static void
+init_path PVAR3C(kpse_format_info_type *, info,  boolean, font_p,
+                 const_string, default_path,  ap)
+{
+  string env_name;
+  string var = NULL;
+  
+  info->font_override_p = font_p;
+  info->default_path = default_path;
+
+  /* First envvar that's set to a nonempty value will exit the loop.  If
+     none are set, we want the first cnf entry that matches.  Find the
+     cnf entries simultaneously, to avoid having to go through envvar
+     list twice -- because of the PVAR?C macro, that would mean having
+     to create a str_list and then use it twice.  Yuck.  */
+  while ((env_name = va_arg (ap, string)) != NULL)
+    {
+      if (!var)
+        {
+          string env_value = getenv (env_name);
+          if (env_value && *env_value)
+            var = env_name;
+        }
+
+      /* If we are initializing the cnf path, don't try to get any
+         values from the cnf files; that's infinite loop time.  */
+      if (!info->cnf_path && (!info->suffix || !STREQ (info->suffix, ".cnf")))
+        info->cnf_path = kpse_cnf_get (env_name);
+      
+      if (var && info->cnf_path)
+        break;
+    }
+  va_end (ap);
+  
+  /* Expand any extra :'s.  For each level (the font override path down
+     through the compile-time default), an extra : should be replaced
+     with the path at the next lower level.  For example, an extra : in
+     a user-set envvar should be replaced with the path from the cnf
+     file.  Things are complicated because none of the levels above the
+     very bottom are guaranteed to exist.  */
+
+  /* Assume we can reliably start with the compile-time default.  */
+  info->path = info->raw_path = info->default_path;
+  info->path_source = "compile-time paths.h";
+
+  EXPAND_DEFAULT (info->cnf_path, "texmf.cnf");
+  EXPAND_DEFAULT (info->client_path, "program config file");
+  if (var)
+    EXPAND_DEFAULT (getenv (var), concat (var, " environment variable"));
+  if (info->font_override_p)
+    EXPAND_DEFAULT (kpse_font_override_path, "font override variable");
+  info->path = kpse_path_expand (info->path);
+}}
+
+
+/* The path spec we are defining, one element of the global array.  */
+#define FMT_INFO kpse_format_info[format]
+
+/* Call `init_path', including appending the trailing NULL to the envvar
+   list. Also initialize the fields not needed in setting the path.
+   Don't set `program_enabled' -- it'll be false via the compiler
+   initialization, and programs may want to enable it beforehand.  */
+#define INIT_FORMAT(ext, font_p, default_path, envs) \
+  FMT_INFO.suffix = FMT_INFO.type = ext; \
+  init_path (&FMT_INFO, font_p, default_path, envs, NULL)
+
+/* A few file types allow for runtime generation by an external program.  */
+#define INIT_MT(prog, args) \
+  FMT_INFO.program = prog; FMT_INFO.program_args = args
+#define MAKETEXPK_SPEC \
+  "$KPATHSEA_DPI $MAKETEX_BASE_DPI $MAKETEX_MAG $MAKETEX_MODE"
+
+/* Initialize everything for FORMAT.  */
+
+const_string
+kpse_init_format P1C(kpse_file_format_type, format)
+{
+  /* If we get called twice, don't redo all the work.  */
+  if (FMT_INFO.path)
+    return FMT_INFO.path;
+    
+  switch (format)
+    { /* We could avoid this repetition by token pasting, but it doesn't
+         seem worth it.  */
+    case kpse_gf_format:
+      INIT_FORMAT ("gf", true, DEFAULT_GFFONTS, KPSE_GF_ENVS);
+      FMT_INFO.suffix_search_only = false;
+      break;
+    case kpse_pk_format:
+      INIT_MT ("MakeTeXPK", MAKETEXPK_SPEC);
+      INIT_FORMAT ("pk", true, DEFAULT_PKFONTS, KPSE_PK_ENVS);
+      FMT_INFO.suffix_search_only = true;
+      break;
+    case kpse_any_glyph_format:
+      INIT_MT ("MakeTeXPK", MAKETEXPK_SPEC);
+      INIT_FORMAT ("bitmap", true, DEFAULT_GLYPHFONTS, KPSE_GLYPH_ENVS);
+      FMT_INFO.suffix_search_only = true;
+      break;
+    case kpse_base_format:
+      INIT_FORMAT (".base", false, DEFAULT_MFBASES, KPSE_BASE_ENVS);
+      break;
+    case kpse_bib_format:
+      INIT_FORMAT (".bib", false, DEFAULT_BIBINPUTS, KPSE_BIB_ENVS);
+      break;
+    case kpse_bst_format:
+      INIT_FORMAT (".bst", false, DEFAULT_BSTINPUTS, KPSE_BST_ENVS);
+      break;
+    case kpse_cnf_format:
+      /* I admit this is ugly, but making another field just for
+         this one file type seemed a waste.  We use this value in cnf.c
+         as the filename to search for in the path.  */
+      if (!FMT_INFO.program)
+        FMT_INFO.program = "texmf.cnf";
+      INIT_FORMAT (".cnf", false, DEFAULT_TEXMFCNF, KPSE_CNF_ENVS);
+      break;
+    case kpse_fmt_format:
+      INIT_FORMAT (".fmt", false, DEFAULT_TEXFORMATS, KPSE_FMT_ENVS);
+      break;
+    case kpse_mf_format:
+      INIT_MT ("MakeTeXMF", NULL);
+      INIT_FORMAT (".mf", false, DEFAULT_MFINPUTS, KPSE_MF_ENVS);
+      break;
+    case kpse_mfpool_format:
+      INIT_FORMAT (".pool", false, DEFAULT_MFPOOL, KPSE_MFPOOL_ENVS);
+      break;
+    case kpse_tex_format:
+      INIT_MT ("MakeTeXTeX", NULL);
+      INIT_FORMAT (".tex", false, DEFAULT_TEXINPUTS, KPSE_TEX_ENVS);
+      break;
+    case kpse_texpool_format:
+      INIT_FORMAT (".pool", false, DEFAULT_TEXPOOL, KPSE_TEXPOOL_ENVS);
+      break;
+    case kpse_pict_format:
+      INIT_FORMAT (NULL, false, DEFAULT_TEXINPUTS, KPSE_PICT_ENVS);
+      FMT_INFO.type = "graphic/figure";
+      break;
+    case kpse_tfm_format:
+      INIT_MT ("MakeTeXTFM", NULL);
+      INIT_FORMAT (".tfm", false, DEFAULT_TFMFONTS, KPSE_TFM_ENVS);
+      FMT_INFO.suffix_search_only = true;
+      break;
+    case kpse_vf_format:
+      INIT_FORMAT (".vf", false, DEFAULT_VFFONTS, KPSE_VF_ENVS);
+      FMT_INFO.suffix_search_only = true;
+      break;
+    case kpse_dvips_config_format:
+      INIT_FORMAT (NULL, false, DEFAULT_TEXCONFIG, KPSE_DVIPS_CONFIG_ENVS);
+      FMT_INFO.type = "dvips config";
+      break;
+    case kpse_dvips_header_format:
+      INIT_FORMAT (NULL, false, DEFAULT_DVIPSHEADERS, KPSE_DVIPS_HEADER_ENVS);
+      FMT_INFO.type = "dvips header/type1 font";
+      break;
+    default:
+      FATAL1 ("(kpathsea) init_path: Unknown format %d", format);
+    }
+
+#ifdef DEBUG
+#define MAYBE_NULL(member) (FMT_INFO.member ? FMT_INFO.member : "(none)")
+
+  /* Describe the monster we've created.  */
+  if (KPSE_DEBUG_P (KPSE_DEBUG_PATHS))
+    {
+      DEBUGF2 ("Search path for %s files (from %s)\n",
+              FMT_INFO.type, FMT_INFO.path_source);
+      DEBUGF1 ("  = %s\n", FMT_INFO.path);
+      DEBUGF1 ("  before expansion = %s\n", FMT_INFO.raw_path);
+      DEBUGF1 ("  font override var applies = %d\n", FMT_INFO.font_override_p);
+      DEBUGF1 ("  application config file path = %s\n",
+              MAYBE_NULL (client_path));
+      DEBUGF1 ("  texmf.cnf path = %s\n", MAYBE_NULL (cnf_path));
+      DEBUGF1 ("  compile-time path = %s\n", MAYBE_NULL (default_path));
+      DEBUGF1 ("  suffix = %s\n", MAYBE_NULL (suffix));
+      DEBUGF1 ("  search only with suffix = %d\n",
+               FMT_INFO.suffix_search_only);
+      DEBUGF1 ("  runtime generation program = %s\n", MAYBE_NULL (program));
+      DEBUGF1 ("  extra program args = %s\n", MAYBE_NULL (program_args));
+      /* Don't print the `program_enabled_p' member, since it's likely
+         always false (made true on a per-font basis), and hence it
+         would just confuse matters.  */
+    }
+#endif /* DEBUG */
+
+  return FMT_INFO.path;
+}
+
+/* Look up a file NAME of type FORMAT, and the given MUST_EXIST.  This
+   initializes the path spec for FORMAT if it's the first lookup of that
+   type.  Return the filename found, or NULL.  */
+   
+string
+kpse_find_file P3C(const_string, name,  kpse_file_format_type, format,
+                   boolean, must_exist)
+{
+  boolean name_has_suffix;
+  const_string suffix;
+  string ret = NULL;
+
+  if (FMT_INFO.path == NULL)
+    kpse_init_format (format);
+
+  suffix = FMT_INFO.suffix;
+  
+  /* Does NAME already end in `.suffix'?  */
+  if (suffix)
+    { /* Don't do the strlen's at all if no SUFFIX.  */
+      unsigned suffix_len = strlen (suffix);
+      unsigned name_len = strlen (name);
+      name_has_suffix = (name_len > suffix_len
+                         && STREQ (suffix, name + name_len - suffix_len));
+    }
+  else
+    name_has_suffix = false;
+  
+  if (suffix && !name_has_suffix)
+    {
+      /* Append `.suffix' and search for it.  If we're going to search
+         for the original name if this fails, then set must_exist=false;
+         otherwise, we'd be looking on the disk for foo.eps.tex.  */
+      string full_name = concat (name, suffix);
+      ret = kpse_path_search (FMT_INFO.path, full_name,
+                             FMT_INFO.suffix_search_only ? must_exist : false);
+      free (full_name);
+    }
+
+  /* For example, looking for foo.eps, first we look for foo.eps.tex,
+     which presumably fails, then we want to look for foo.eps.  (But we
+     want to find foo.tex before foo, so have to try with `suffix'
+     first.)  Another example: tftopl passes in cmr10.tfm, but the
+     drivers just pass in cmr10. To avoid pounding the disk for `cmr10',
+     `suffix_search_only' for PK format is true. But then
+     `name_has_suffix' must override, or tftopl would wind up doing
+     no searches at all.  */
+  if (!ret && (name_has_suffix || !FMT_INFO.suffix_search_only))
+    ret = kpse_path_search (FMT_INFO.path, name, must_exist);
+
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/tex-glyph.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,383 @@
+/* tex-glyph.c: Search for GF/PK files.
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/absolute.h>
+#include <kpathsea/expand.h>
+#include <kpathsea/fontmap.h>
+#include <kpathsea/pathsearch.h>
+#include <kpathsea/tex-glyph.h>
+#include <kpathsea/tex-make.h>
+#include <kpathsea/variable.h>
+
+/* Routines are in bottom-up order.  */
+
+/* Support both cmr10.300pk and dpi300/cmr10.pk.  (Use the latter
+   instead of dpi300\cmr10.pk since DOS supports /'s, but Unix doesn't
+   support \'s.  */
+#define UNIX_BITMAP_SPEC "$KPATHSEA_NAME.$KPATHSEA_DPI$KPATHSEA_FORMAT"
+#define DPI_BITMAP_SPEC  "dpi$KPATHSEA_DPI/$KPATHSEA_NAME.$KPATHSEA_FORMAT"
+
+/* Look up FONT_NAME at resolution DPI in PATH, with filename suffix
+   EXTENSION.  Return file found or NULL.  */
+
+static string
+try_format P3C(const_string, font_name,  unsigned, dpi,
+               kpse_file_format_type,  format)
+{
+  static const_string bitmap_specs[]
+    = { UNIX_BITMAP_SPEC, DPI_BITMAP_SPEC, NULL };
+  const_string *spec;
+  boolean must_exist;
+  string ret = NULL;
+  const_string path = kpse_format_info[format].path;
+  if (!path)
+    path = kpse_init_format (format);
+  
+  /* Set the suffix on the name we'll be searching for.  */
+  xputenv ("KPATHSEA_FORMAT", kpse_format_info[format].suffix);
+
+  /* OK, the limits on this for loop are a little hokey, but it saves
+     having to repeat the body.  We want to do it once with `must_exist'
+     false to avoid looking on the disk for cmr10.600pk if
+     dpi600/cmr10.pk is in ls-R.  (The time spent in the extra variable
+     expansions and db searches is negligible.)  */
+  for (must_exist = false; !ret && must_exist <= true; must_exist++)
+    {
+      for (spec = bitmap_specs; !ret && *spec; spec++)
+        {
+          string name = kpse_var_expand (*spec);
+          ret = kpse_path_search (path, name, must_exist);
+          if (name != ret)
+            free (name);
+        }
+    }
+    
+  return ret;
+}
+
+/* Look for FONT_NAME at resolution DPI in format FORMAT.  Search the
+   (entire) PK path first, then the GF path, if we're looking for both.
+   Return any filename found, and (if we succeeded) fill in GLYPH_FILE.  */
+
+static string
+try_size P4C(const_string, font_name,  unsigned, dpi,
+             kpse_file_format_type, format,
+             kpse_glyph_file_type *, glyph_file)
+{
+  kpse_file_format_type format_found;
+  string ret;
+  boolean try_gf = format == kpse_gf_format || format == kpse_any_glyph_format;
+  boolean try_pk = format == kpse_pk_format || format == kpse_any_glyph_format;
+
+  xputenv_int ("KPATHSEA_DPI", dpi);
+  
+  /* Look for PK first (since it's more likely to be found), then GF.  */
+  ret = try_pk ? try_format (font_name, dpi, kpse_pk_format) : NULL;
+
+  if (ret != NULL)
+    format_found = kpse_pk_format;
+  else
+    {
+      if (try_gf)
+        {
+          ret = try_format (font_name, dpi, kpse_gf_format);
+          format_found = kpse_gf_format;
+        }
+    }
+  
+  if (ret != NULL && glyph_file)
+    { /* Success.  Fill in the return info.  Discard const.  */
+      glyph_file->name = (string) font_name;
+      glyph_file->dpi = dpi;
+      glyph_file->format = format_found;
+    }
+    
+  return ret;
+}
+
+/* Look for FONT_NAME at resolution DPI, then at the resolutions within
+   KPSE_BITMAP_TOLERANCE of DPI.  */
+
+static string
+try_resolution P4C(const_string, font_name,  unsigned, dpi,
+                   kpse_file_format_type, format,
+                   kpse_glyph_file_type *, glyph_file)
+{
+  string ret = try_size (font_name, dpi, format, glyph_file);
+  
+  if (!ret)
+    {
+      unsigned r;
+      unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi);
+      unsigned lower_bound = (int) (dpi - tolerance) < 0 ? 0 : dpi - tolerance;
+      unsigned upper_bound = dpi + tolerance;
+      
+      /* Prefer scaling up to scaling down, since scaling down can omit
+         character features (Tom did this in dvips).  */
+      for (r = lower_bound; !ret && r <= upper_bound; r++)
+        if (r != dpi)
+          ret = try_size (font_name, r, format, glyph_file);
+    }
+  
+  return ret;
+}
+
+/* Look up FONT_NAME in format FORMAT at DPI in the texfonts.map files
+   that we can find, returning the filename found and GLYPH_FILE.  */
+
+static string
+try_fontmap P4C(const_string, font_name,  unsigned, dpi,
+                kpse_file_format_type, format,
+                kpse_glyph_file_type *, glyph_file)
+{
+  static hash_table_type fontmap;
+  string *mapped_names;
+  string ret = NULL;
+
+  if (fontmap.size == 0)
+    { /* If we wanted to complicate our lives, we could handle separate
+         maps for GF and PK ones.  I don't see that this has any
+         practical utility, though, because if someone wants an alias,
+         most likely the alias should apply to non-glyphs as well as
+         glyphs (let alone to only GF format or PK format).  */
+      const_string map_path = kpse_init_format (kpse_any_glyph_format);
+      fontmap = map_create (map_path);
+    }
+
+  mapped_names = map_lookup (fontmap, font_name);
+  if (mapped_names)
+    {
+      string mapped_name;
+      while ((mapped_name = *mapped_names++) && !ret)
+        {
+          xputenv ("KPATHSEA_NAME", mapped_name);
+          ret = try_resolution (mapped_name, dpi, format, glyph_file);
+        }
+    }
+
+  return ret;
+}
+
+/* Look for FONT_NAME in `kpse_fallback_resolutions', omitting DPI if we
+   happen across it.  Return NULL if nothing found.  Pass GLYPH_FILE
+   along as usual.  Assume `kpse_fallback_resolutions' is sorted.  */
+
+static string
+try_fallback_resolutions P4C(const_string, font_name,  unsigned, dpi,
+                             kpse_file_format_type, format,
+                             kpse_glyph_file_type *, glyph_file)
+{
+  unsigned s;
+  int loc, max_loc;
+  int lower_loc, upper_loc;
+  unsigned lower_diff, upper_diff;
+  unsigned closest_diff = UINT_MAX;
+  string ret = NULL; /* In case the only fallback resolution is DPI.  */
+
+  /* First find the fallback size closest to DPI.  */
+  for (s = 0; kpse_fallback_resolutions[s] != 0; s++)
+    {
+      unsigned this_diff = abs (kpse_fallback_resolutions[s] - dpi);
+      if (this_diff < closest_diff)
+        {
+          closest_diff = this_diff;
+          loc = s;
+        }
+    }
+  if (s == 0)
+    return ret; /* If nothing in list, quit now.  */
+  
+  max_loc = s;
+  lower_loc = loc - 1;
+  upper_loc = loc + 1;
+  
+  for (;;)
+    {
+      unsigned fallback = kpse_fallback_resolutions[loc];
+      /* Don't bother to try DPI itself again.  */
+      if (fallback != dpi)
+        {
+          ret = try_resolution (font_name, fallback, format, glyph_file);
+          if (ret)
+            break;
+        }
+      
+      /* That didn't work. How far away are the locs above or below?  */
+      lower_diff = lower_loc > -1
+                   ? dpi - kpse_fallback_resolutions[lower_loc] : INT_MAX;
+      upper_diff = upper_loc < max_loc
+                   ? kpse_fallback_resolutions[upper_loc] - dpi : INT_MAX;
+      
+      /* But if we're at the end in both directions, quit.  */
+      if (lower_diff == INT_MAX && upper_diff == INT_MAX)
+        break;
+      
+      /* Go in whichever direction is closest.  */
+      if (lower_diff < upper_diff)
+        {
+          loc = lower_loc;
+          lower_loc--;
+        }
+      else
+        {
+          loc = upper_loc;
+          upper_loc++;
+        }
+    }
+
+  return ret;
+}
+
+/* See the .h file for description.  This is the entry point.  */
+
+string
+kpse_find_glyph P4C(const_string, font_name,  unsigned, dpi,
+                    kpse_file_format_type, format,
+                    kpse_glyph_file_type *, glyph_file)
+{
+  string ret;
+  kpse_glyph_source_type source;
+  
+  /* Start the search: try the name we're given.  */
+  source = kpse_glyph_source_normal;
+  xputenv ("KPATHSEA_NAME", font_name);
+  ret = try_resolution (font_name, dpi, format, glyph_file);
+  
+  /* Try all the various possibilities in order of preference.  */
+  if (!ret)
+    {
+      /* Maybe FONT_NAME was an alias.  */
+      source = kpse_glyph_source_alias;
+      ret = try_fontmap (font_name, dpi, format, glyph_file);
+
+      /* If not an alias, try creating it on the fly with MakeTeXPK,
+         unless FONT_NAME is absolute or explicitly relative.  */
+      if (!ret && !kpse_absolute_p (font_name, true))
+        {
+          source = kpse_glyph_source_maketex;
+          /* `try_resolution' leaves the envvar set randomly.  */
+          xputenv_int ("KPATHSEA_DPI", dpi);
+          ret = kpse_make_tex (format, font_name);
+        }
+       
+      /* If MakeTeX... succeeded, set return struct.  Doesn't make sense for
+         `kpse_make_tex' to set it, since it can only succeed or fail,
+         unlike the other routines.  */
+      if (ret)
+        {
+          KPSE_GLYPH_FILE_DPI (*glyph_file) = dpi;
+          /* Have to discard const here.  */
+          KPSE_GLYPH_FILE_NAME (*glyph_file) = (string) font_name;
+        }
+
+      /* If MakeTeX... failed, try any fallback resolutions.  */
+      else
+        {
+          if (kpse_fallback_resolutions)
+            ret = try_fallback_resolutions(font_name, dpi, format, glyph_file);
+
+          /* We're down to the font of last resort.  */
+          if (!ret && kpse_fallback_font)
+            {
+              const_string name = kpse_fallback_font;
+              source = kpse_glyph_source_fallback;
+              xputenv ("KPATHSEA_NAME", name);
+
+              /* As before, first try it at the given size.  */
+              ret = try_resolution (name, dpi, format, glyph_file);
+              
+              /* The fallback font at the fallback resolutions.  */
+              if (!ret && kpse_fallback_resolutions)
+                ret = try_fallback_resolutions (name, dpi, format, glyph_file);
+            }
+        }
+    }
+  
+  /* If RET is null, then the caller is not supposed to look at GLYPH_FILE,
+     so it doesn't matter if we assign something incorrect.  */
+  KPSE_GLYPH_FILE_SOURCE (*glyph_file) = source;
+  
+  return ret;
+}
+
+/* The tolerances change whether we base things on DPI1 or DPI2.  */
+
+boolean
+kpse_bitmap_tolerance P2C(double, dpi1,  double, dpi2)
+{
+  unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi2);
+  unsigned lower_bound = (int) (dpi2 - tolerance) < 0 ? 0 : dpi2 - tolerance;
+  unsigned upper_bound = dpi2 + tolerance;
+
+  return lower_bound <= dpi1 && dpi1 <= upper_bound;
+}
+
+#ifdef TEST
+
+void
+test_find_glyph (const_string font_name, unsigned dpi)
+{
+  string answer;
+  kpse_glyph_file_type ret;
+  
+  printf ("\nSearch for %s@%u:\n\t", font_name, dpi);
+
+  answer = kpse_find_glyph_format (font_name, dpi,
+                                   kpse_any_glyph_format, &ret);
+  if (answer)
+    {
+      string format = ret.format == kpse_pk_format ? "pk" : "gf";
+      if (!ret.name)
+        ret.name = "(null)";
+      printf ("%s\n\t(%s@%u, %s)\n", answer, ret.name, ret.dpi, format);
+    }
+  else
+    puts ("(null)");
+}
+
+
+int
+main ()
+{
+  test_find_glyph ("/usr/local/lib/tex/fonts/cm/cmr10", 300); /* absolute */
+  test_find_glyph ("cmr10", 300);     /* normal */
+  test_find_glyph ("logo10", 300);    /* find gf */
+  test_find_glyph ("cmr10", 299);     /* find 300 */
+  test_find_glyph ("circle10", 300);  /* in fontmap */
+  test_find_glyph ("none", 300);      /* do not find */
+  kpse_fallback_font = "cmr10";
+  test_find_glyph ("fallback", 300);  /* find fallback font cmr10 */
+  kpse_init_fallback_resolutions ("KPATHSEA_TEST_SIZES");
+  test_find_glyph ("fallbackdpi", 759); /* find fallback font cmr10@300 */
+  
+  xputenv ("GFFONTS", ".");
+  test_find_glyph ("cmr10", 300);     /* different GFFONTS/TEXFONTS */
+  
+  return 0;
+}
+
+#endif /* TEST */
+
+
+/*
+Local variables:
+test-compile-command: "gcc -g -I. -I.. -DTEST tex-glyph.c kpathsea.a"
+End:
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/tex-make.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,301 @@
+/* tex-make.c: Run external programs to make TeX-related files.
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-fopen.h>
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/concatn.h>
+#include <kpathsea/db.h>
+#include <kpathsea/fn.h>
+#include <kpathsea/magstep.h>
+#include <kpathsea/readable.h>
+#include <kpathsea/tex-make.h>
+#include <kpathsea/variable.h>
+
+
+/* We never throw away stdout, since that is supposed to be the filename
+   found, if all is successful.  This variable controls whether stderr
+   is thrown away.  */
+boolean kpse_make_tex_discard_errors = false;
+
+/* We set the envvar MAKETEX_MAG, which is part of the default spec for
+   MakeTeXPK above, based on KPATHSEA_DPI and MAKETEX_BASE_DPI.  */
+
+static void
+set_maketex_mag P1H(void)
+{
+  char q[MAX_INT_LENGTH * 3 + 3];
+  int m;
+  string dpi_str = getenv ("KPATHSEA_DPI");
+  string bdpi_str = getenv ("MAKETEX_BASE_DPI");
+  unsigned dpi = dpi_str ? atoi (dpi_str) : 0;
+  unsigned bdpi = bdpi_str ? atoi (bdpi_str) : 0;
+
+  /* If the environment variables aren't set, it's a bug.  */
+  assert (dpi != 0 && bdpi != 0);
+  
+  /* Fix up for roundoff error.  Hopefully the driver has already fixed
+     up DPI, but may as well be safe, and also get the magstep number.  */
+  (void) kpse_magstep_fix (dpi, bdpi, &m);
+  
+  /* Have to do something different for DOS?  */
+  if (m == 0)
+    sprintf (q, "%d+%d/%d", dpi / bdpi, dpi % bdpi, bdpi);
+  else
+    { /* m is encoded with LSB being a ``half'' bit (see magstep.h).  Are
+         we making an assumption here about two's complement?  Probably.
+         In any case, if m is negative, we have to put in the sign
+         explicitly, since m/2==0 if m==-1.  */
+      const_string sign = "";
+      if (m < 0)
+        {
+          m *= -1;
+          sign = "-";
+        }
+      sprintf (q, "magstep\\(%s%d.%d\\)", sign, m / 2, (m & 1) * 5);
+    }  
+  xputenv ("MAKETEX_MAG", q);
+}
+
+/* This MakeTeX... program was disabled, or the script failed.  If this
+   was a font creation (according to FORMAT), append CMD
+   to a file missfont.log in the current directory.  */
+
+static void
+misstex P2C(kpse_file_format_type, format,  const_string, cmd)
+{
+  static FILE *missfont = NULL;
+
+  /* If we weren't trying to make a font, do nothing.  Maybe should
+     allow people to specify what they want recorded?  */
+  if (format > kpse_any_glyph_format && format != kpse_tfm_format
+      && format != kpse_vf_format)
+    return;
+
+  /* If this is the first time, have to open the log file.  */
+  if (!missfont)
+    {
+      const_string missfont_name = "missfont.log";
+      missfont = fopen (missfont_name, FOPEN_A_MODE);
+      if (!missfont && getenv ("TEXMFOUTPUT"))
+        {
+          missfont_name = concat3 (getenv ("TEXMFOUTPUT"), DIR_SEP_STRING,
+                                   missfont_name);
+          missfont = fopen (missfont_name, FOPEN_A_MODE);
+        }
+
+      /* Should we really be unconditionally shouting this message?  */
+      if (missfont)
+        fprintf (stderr, "kpathsea: Appending font creation commands to %s.\n",
+                 missfont_name);
+    }
+  
+  /* Write the command if we have a log file.  */
+  if (missfont)
+    {
+      fputs (cmd, missfont);
+      putc ('\n', missfont);
+    }
+}  
+
+
+/* Assume the script outputs the filename it creates (and nothing
+   else) on standard output; hence, we run the script with `popen'.  */
+
+static string
+maketex P2C(kpse_file_format_type, format,  const_string, cmd)
+{
+  string ret;
+  FILE *f;
+  
+  /* Tell the user we are running the script, so they have a clue as to
+     what's going on if something messes up.  */
+  fprintf (stderr, "kpathsea: Running %s\n", cmd);
+  
+  /* Run the script.  */
+  f = popen (cmd, FOPEN_R_MODE);
+
+  if (f)
+    {
+      int c;
+      string fn;             /* The final filename.  */
+      unsigned len;          /* And its length.  */
+      fn_type output;
+      output = fn_init ();   /* Collect the script output.  */
+
+      /* Read all the output and terminate with a null.  */
+      while ((c = getc (f)) != EOF)
+        fn_1grow (&output, c);
+      fn_1grow (&output, 0);
+
+      /* Maybe should check for `EXIT_SUCCESS' status before even
+         looking at the output?  */
+      if (pclose (f) == -1)
+        FATAL_PERROR (cmd);
+
+      len = FN_LENGTH (output);
+      fn = FN_STRING (output);
+
+      /* Remove trailing newlines and returns.  */
+      while (len > 1 && (fn[len - 2] == '\n' || fn[len - 2] == '\r'))
+        {
+          fn[len - 2] = 0;
+          len--;
+        }
+
+      /* If no output from script, return NULL.  Otherwise check
+         what it output.  */
+      ret = len == 1 ? NULL : kpse_readable_file (fn);
+
+      /* Free the name if we're not returning it.  */
+      if (fn != ret)
+        free (fn);
+    }
+  else
+    /* popen failed.  Maybe should give error (optionally), but for
+       now be silent, to avoid annoying people who purposefully
+       don't have the script installed. */
+    ret = NULL;
+  
+  if (ret == NULL)
+    misstex (format, cmd);
+  else
+    db_insert (ret);
+    
+  return ret;
+}
+
+
+/* Create BASE in FORMAT and return the generated filename, or
+   return NULL.  */
+
+string
+kpse_make_tex P2C(kpse_file_format_type, format,  const_string, base)
+{
+  kpse_format_info_type spec; /* some compilers lack struct initialization */
+  string ret = NULL;
+  
+  spec = kpse_format_info[format];
+  
+  if (spec.program)
+    {
+      /* See the documentation for the envvars we're dealing with here.  */
+      string args, cmd;
+      const_string prog = spec.program; /* MakeTeXPK */
+      string PROG = uppercasify (prog); /* MAKETEXPK */
+      string progenv = getenv (PROG);   /* ENV{"MAKETEXPK"} */
+      const_string arg_spec = progenv ? progenv : spec.program_args;
+      string mode = getenv ("MAKETEX_MODE");
+      boolean unset_mode = false;
+      
+      set_maketex_mag ();
+      
+      /* Here's an awful kludge: if the mode is `/', unset it for the
+         call and then reset it.  We could ignore a mode of / in
+         MakeTeXPK, but then everyone's MakeTeXPK would have to handle
+         that special case, which seems too onerous.  `kpse_prog_init'
+         sets it to this in the first place when no mode is otherwise
+         specified; this is so when the user defines a resolution, they
+         don't also have to specify a mode; instead, MakeTeXPK's guesses
+         will take over.  They use / for the value because then when it
+         is expanded as part of the PKFONTS et al. path values, we'll
+         wind up searching all the pk directories.  We put $MAKETEX_MODE
+         in the path values in the first place so that sites with two
+         different devices with the same resolution can find the right
+         fonts; but such sites are uncommon, so they shouldn't make
+         things harder for everyone else.  */
+      if (mode && STREQ (mode, DIR_SEP_STRING))
+        {
+          xputenv ("MAKETEX_MODE", "");
+          unset_mode = true;
+        }
+      args = arg_spec ? kpse_var_expand (arg_spec) : (string) "";
+      if (unset_mode)
+        xputenv ("MAKETEX_MODE", DIR_SEP_STRING);
+      
+      /* The command is the program name plus the arguments.  */
+      cmd = concatn (prog, " ", base, " ", args, NULL);
+
+      if (spec.program_enabled_p)
+        {
+          /* Only way to discard errors is redirect stderr inside another
+             shell; otherwise, if the MakeTeX... script doesn't exist, we
+             will see the `sh: MakeTeX...: not found' error.  No point in
+             doing this if we're not actually going to run anything.  */
+          if (kpse_make_tex_discard_errors)
+            {
+              string old_cmd = cmd;
+              cmd = concat3 ("sh -c \"", cmd, "\" 2>/dev/null");
+              free (old_cmd);
+            }
+
+          ret = maketex (format, cmd);
+        }
+      else
+        misstex (format, cmd);
+
+      free (PROG);
+      free (cmd);
+      if (*args)
+        free (args);
+    }  
+
+  return ret;
+}
+
+#ifdef TEST
+
+void
+test_make_tex (kpse_file_format_type fmt, const_string base)
+{
+  string answer;
+  
+  printf ("\nAttempting %s in format %d:\n", base, fmt);
+
+  answer = kpse_make_tex (fmt, base);
+  puts (answer ? answer : "(null)");
+}
+
+
+int
+main ()
+{
+  xputenv ("KPATHSEA_DPI", "781"); /* call MakeTeXPK */
+  xputenv ("MAKETEX_BASE_DPI", "300"); /* call MakeTeXPK */
+  KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_pk_format]) = true;
+  test_make_tex (kpse_pk_format, "cmr10");
+
+  /* Fail with MakeTeXTFM.  */
+  KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_tfm_format]) = true;
+  test_make_tex (kpse_tfm_format, "foozler99");
+  
+  /* Call something disabled.  */
+  test_make_tex (kpse_bst_format, "no-way");
+  
+  return 0;
+}
+
+#endif /* TEST */
+
+
+/*
+Local variables:
+test-compile-command: "gcc -g -I. -I.. -DTEST tex-make.c kpathsea.a"
+End:
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/tilde.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,122 @@
+/* tilde.c: Expand user's home directories.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/tilde.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+
+/* If NAME has a leading ~ or ~user, Unix-style, expand it to the user's
+   home directory, and return a new malloced string.  If no ~, or no
+   <pwd.h>, just return NAME.  */
+
+string
+kpse_tilde_expand P1C(const_string, name)
+{
+#ifdef HAVE_PWD_H
+  const_string expansion;
+  const_string home;
+  
+  assert (name);
+  
+  /* If no leading tilde, do nothing.  */
+  if (*name != '~')
+    expansion = name;
+  
+  /* If `~' or `~/', use $HOME if it exists, or `.' if it doesn't.  */
+  else if (IS_DIR_SEP (name[1]) || name[1] == 0)
+    {
+      home = getenv ("HOME");
+      if (!home)
+        home = ".";
+        
+      expansion = name[1] == 0
+                  ? xstrdup (home) : concat3 (home, DIR_SEP_STRING, name + 2);
+    }
+  
+  /* If `~user' or `~user/', look up user in the passwd database.  */
+  else
+    {
+      struct passwd *p;
+      string user;
+      unsigned c = 2;
+      while (!IS_DIR_SEP (name[c]) && name[c] != 0)
+        c++;
+      
+      user = (string) xmalloc (c);
+      strncpy (user, name + 1, c - 1);
+      user[c - 1] = 0;
+      
+      /* We only need the cast here for those (deficient) systems
+         which do not declare `getpwnam' in <pwd.h>.  */
+      p = (struct passwd *) getpwnam (user);
+      free (user);
+
+      /* If no such user, just use `.'.  */
+      home = p == NULL ? "." : p->pw_dir;
+      
+      expansion = name[c] == 0 ? xstrdup (home) : concat (home, name + c);
+    }
+  
+  /* We may return the same thing as the original, and then we might not
+     be returning a malloc-ed string.  */
+  return (string) expansion;
+#else
+  return name;
+#endif /* not HAVE_PWD_H */
+}
+
+#ifdef TEST
+
+void
+test_expand_tilde (const_string filename)
+{
+  string answer;
+  
+  printf ("Tilde expansion of `%s':\t", filename ? filename : "(null)");
+  answer = kpse_expand_tilde (filename);
+  puts (answer);
+}
+
+int
+main ()
+{
+  string tilde_path = "tilde";
+
+  test_expand_tilde ("");
+  test_expand_tilde ("none");
+  test_expand_tilde ("~root");
+  test_expand_tilde ("~");
+  test_expand_tilde ("foo~bar");
+  
+  return 0;
+}
+
+#endif /* TEST */
+
+
+/*
+Local variables:
+standalone-compile-command: "gcc -g -I. -I.. -DTEST tilde.c kpathsea.a"
+End:
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/truncate.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,57 @@
+/* truncate.c: truncate too-long components in a filename.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-namemx.h>
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/c-pathmx.h>
+#include <kpathsea/truncate.h>
+
+
+/* Truncate any too-long components in NAME, returning the result.  It's
+   too bad this is necessary.  See comments in readable.c for why.  */
+
+string
+kpse_truncate_filename P1C(const_string, name)
+{
+  unsigned c_len = 0;        /* Length of current component.  */
+  unsigned ret_len = 0;      /* Length of constructed result.  */
+  
+  /* Allocate enough space.  */
+  string ret = (string) xmalloc (strlen (name) + 1);
+
+  for (; *name; name++)
+    {
+      if (IS_DIR_SEP (*name))
+        { /* At a directory delimiter, reset component length.  */
+          c_len = 0;
+        }
+      else if (c_len > NAME_MAX)
+        { /* If past the max for a component, ignore this character.  */
+          continue;
+        }
+
+      /* Copy this character.  */
+      ret[ret_len++] = *name;
+      c_len++;
+    }
+  ret[ret_len] = 0;
+
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/uppercasify.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,36 @@
+/* uppercasify.c: change all lowercase letters to uppercase.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-ctype.h>
+
+
+string
+uppercasify P1C(const_string, s)
+{
+  string target;
+  string ret = xstrdup (s);
+  
+  for (target = ret; *target; target++)
+    {
+      *target = TOUPPER (*target);
+    }
+  
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/variable.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,185 @@
+/* variable.c: variable expansion.
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/c-ctype.h>
+#include <kpathsea/cnf.h>
+#include <kpathsea/fn.h>
+#include <kpathsea/variable.h>
+
+
+/* Append the result of value of `var' to EXPANSION, where `var' begins
+   at START and ends at END.  If `var' is not set, do not complain.  */
+
+static void
+expand P3C(fn_type *, expansion,  const_string, start,  const_string, end)
+{
+  string value;
+  unsigned len = end - start + 1;
+  string var = xmalloc (len + 1);
+  strncpy (var, start, len);
+  var[len] = 0;
+  
+  /* First check the environment variable.  */
+  value = getenv (var);
+  
+  /* If no envvar, check the config files.  */
+  if (!value)
+    value = kpse_cnf_get (var);
+    
+  if (value)
+    {
+      value = kpse_var_expand (value);
+      fn_grow (expansion, value, strlen (value));
+      free (value);
+    }
+  
+  free (var);
+}
+
+/* Can't think of when it would be useful to change these (and the
+   diagnostic messages assume them), but ... */
+#ifndef IS_VAR_START /* starts all variable references */
+#define IS_VAR_START(c) ((c) == '$')
+#endif
+#ifndef IS_VAR_CHAR  /* variable name constituent */
+#define IS_VAR_CHAR(c) (ISALNUM (c) || (c) == '_')
+#endif
+#ifndef IS_VAR_BEGIN_DELIMITER /* start delimited variable name (after $) */
+#define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{')
+#endif
+#ifndef IS_VAR_END_DELIMITER
+#define IS_VAR_END_DELIMITER(c) ((c) == '}')
+#endif
+
+
+/* Maybe we should generalize to allow some or all of the various shell
+   ${...} constructs, especially ${var-value}.  */
+
+string
+kpse_var_expand P1C(const_string, src)
+{
+  const_string s;
+  string ret;
+  fn_type expansion;
+  expansion = fn_init ();
+  
+  /* Copy everything but variable constructs.  */
+  for (s = src; *s; s++)
+    {
+      if (IS_VAR_START (*s))
+        {
+          s++;
+          
+          /* Three cases: `$VAR', `${VAR}', `$<anything-else>'.  */
+          
+          if (IS_VAR_CHAR (*s))
+            { /* $V: collect name constituents, then expand.  */
+              const_string var_end = s;
+              
+              do
+                var_end++;
+              while (IS_VAR_CHAR (*var_end));
+              
+              var_end--; /* had to go one past */
+              expand (&expansion, s, var_end);
+              s = var_end;
+            }
+
+          else if (IS_VAR_BEGIN_DELIMITER (*s))
+            { /* ${: scan ahead for matching delimiter, then expand.  */
+              const_string var_end = ++s;
+              
+              while (*var_end && !IS_VAR_END_DELIMITER (*var_end))
+                var_end++;
+              
+              if (! *var_end)
+                {
+                  WARNING1 ("%s: No matching right brace for ${", src);
+                  s = var_end - 1; /* will incr to null at top of loop */
+                }
+              else
+                {
+                  expand (&expansion, s, var_end - 1);
+                  s = var_end; /* will incr past } at top of loop*/
+                }
+            }
+
+
+          else
+            { /* $<something-else>: error.  */
+              WARNING2 ("%s: Unrecognized variable construct `$%c'", src, *s);
+              /* Just ignore those chars and keep going.  */
+            }
+        }
+      else
+        fn_1grow (&expansion, *s);
+    }
+  fn_1grow (&expansion, 0);
+          
+  ret = FN_STRING (expansion);
+  return ret;
+}
+
+#ifdef TEST
+
+static void
+test_var (string test, string right_answer)
+{
+  string result = kpse_var_expand (test);
+  
+  printf ("expansion of `%s'\t=> %s", test, result);
+  if (!STREQ (result, right_answer))
+    printf (" [should be `%s']", right_answer);
+  putchar ('\n');
+}
+
+
+int
+main ()
+{
+   test_var ("a", "a");
+   test_var ("$foo", "");
+   test_var ("a$foo", "a");
+   test_var ("$foo a", " a");
+   test_var ("a$foo b", "a b");
+
+   xputenv ("FOO", "foo value");
+   test_var ("a$FOO", "afoo value");
+   
+   xputenv ("Dollar", "$");
+   test_var ("$Dollar a", "$ a");
+   
+   test_var ("a${FOO}b", "afoo valueb");
+   test_var ("a${}b", "ab");
+   
+   test_var ("$$", ""); /* and error */
+   test_var ("a${oops", "a"); /* and error */
+   
+   return 0;
+}
+
+#endif /* TEST */
+
+
+/*
+Local variables:
+standalone-compile-command: "gcc -g -I. -I.. -DTEST variable.c kpathsea.a"
+End:
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/version.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,1 @@
+char *kpathsea_version_string = (char *) "kpathsea version 2.6";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/xcalloc.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,35 @@
+/* xcalloc.c: calloc with error checking.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+
+address
+xcalloc P2C(unsigned, nelem,  unsigned, elsize)
+{
+  address new_mem = (address) calloc (nelem, elsize);
+  
+  if (new_mem == NULL)
+    {
+      fprintf (stderr, "xcalloc: request for %u elements of size %u failed.\n",
+               nelem, elsize);
+      abort ();
+    }
+  
+  return new_mem;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/xfopen.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,44 @@
+/* xfopen.c: fopen and fclose with error checking.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+
+/* These routines just check the return status from standard library
+   routines and abort if an error happens.  */
+
+FILE *
+xfopen P2C(const_string, filename,  const_string, mode)
+{
+  FILE *f = fopen (filename, mode);
+
+  if (f == NULL)
+    FATAL_PERROR (filename);
+
+  return f;
+}
+
+
+void
+xfclose P2C(FILE *, f,  const_string, filename)
+{
+  if (fclose (f) == EOF)
+    FATAL_PERROR (filename);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/xmalloc.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,41 @@
+/* xmalloc.c: malloc with error checking.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Don't include config.h or all our other usual includes, since
+   it's useful to just throw this file into other programs.  */
+
+#include <stdio.h>
+extern char *malloc ();
+
+
+void *
+xmalloc (size)
+    unsigned size;
+{
+  void *new_mem = (void *) malloc (size);
+
+  if (new_mem == NULL)
+    {
+      fprintf (stderr, "fatal: memory exhausted (xmalloc of %u bytes).\n",
+               size);
+      /* 1 means success on VMS, so pick a random number (ASCII `K').  */
+      exit (75);
+    }
+
+  return new_mem;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/xopendir.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,47 @@
+/* xopendir.c: opendir and closedir with error checking.
+
+Copyright (C) 1992, 93, 94 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/xopendir.h>
+
+
+DIR *
+xopendir P1C(string, dirname)
+{
+  DIR *d = opendir (dirname);
+
+  if (d == NULL)
+    FATAL_PERROR (dirname);
+
+  return d;
+}
+
+
+void
+xclosedir P1C(DIR *, d)
+{
+#ifdef VOID_CLOSEDIR
+  closedir (d);
+#else
+  int ret = closedir (d);
+  
+  if (ret != 0)
+    FATAL ("closedir failed");
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/xputenv.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,107 @@
+/* xputenv.c: set an environment variable without return.
+
+Copyright (C) 1993, 94 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+/* Avoid implicit declaration warning.  */
+extern int putenv ();
+
+/* This `x' function is different from the others in that it takes
+   different parameters than the standard function; but I find it much
+   more convenient to pass the variable and the value separately.  Also,
+   this way we can guarantee that the environment value won't become
+   garbage.  Also, putenv just overwrites old entries with
+   the new, and we want to reclaim that space -- this may be called
+   hundreds of times on a run.
+   
+   But naturally, some systems do it differently. In this case, it's
+   net2 that is smart and does its own saving/freeing. If you can write
+   a test for configure to check this, please send it to me. Until then,
+   you'll have to define SMART_PUTENV yourself. */
+
+void
+xputenv P2C(const_string, var_name,  const_string, value)
+{
+  static const_string *saved_env_items = NULL;
+  static unsigned saved_len;
+  string old_item = NULL;
+  string new_item = concat3 (var_name, "=", value);
+
+#ifndef SMART_PUTENV
+  /* Check if we have saved anything yet.  */
+  if (!saved_env_items)
+    {
+      saved_env_items = XTALLOC1 (const_string);
+      saved_env_items[0] = var_name;
+      saved_len = 1;
+    }
+  else
+    {
+      /* Check if we've assigned VAR_NAME before.  */
+      unsigned i;
+      unsigned len = strlen (var_name);
+      for (i = 0; i < saved_len && !old_item; i++)
+        {
+          if (STREQ (saved_env_items[i], var_name))
+            {
+              old_item = getenv (var_name);
+              assert (old_item);
+              /* Back up to the `NAME=' in the environment before the
+                 value that getenv returns.  */
+              old_item -= (len + 1);
+            }
+        }
+      
+      if (!old_item)
+        {
+          /* If we haven't seen VAR_NAME before, save it.  Assume it is
+             in safe storage.  */
+          saved_len++;
+          XRETALLOC (saved_env_items, saved_len, const_string);
+          saved_env_items[saved_len - 1] = var_name;
+        }
+    }
+#endif /* not SMART_PUTENV */
+
+  /* As far as I can see there's no way to distinguish between the
+     various errors; putenv doesn't have errno values.  */
+  if (putenv (new_item) < 0)
+    FATAL1 ("putenv (%s) failed", new_item);
+  
+#ifndef SMART_PUTENV
+  /* Can't free `new_item' because its contained value is now in
+     `environ', but we can free `old_item', since it's been replaced.  */
+  if (old_item)
+    free (old_item);
+#endif /* not SMART_PUTENV */
+}
+
+
+/* A special case for setting a variable to a numeric value
+   (specifically, KPATHSEA_DPI).  We don't need to dynamically allocate
+   and free the string for the number, since it's saved as part of the
+   environment value.  */
+
+void
+xputenv_int P2C(const_string, var_name,  int, num)
+{
+  char str[MAX_INT_LENGTH];
+  sprintf (str, "%d", num);
+  
+  xputenv (var_name, str);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/xrealloc.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,54 @@
+/* xrealloc.c: realloc with error checking.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Don't include config.h or all our other usual includes, since
+   it's useful to just throw this file into other programs.  */
+
+#include <stdio.h>
+extern char *realloc ();
+
+
+extern void *xmalloc ();
+
+void *
+xrealloc (old_ptr, size)
+    void *old_ptr;
+    unsigned size;
+{
+  void *new_mem;
+
+  if (old_ptr == NULL)
+    new_mem = xmalloc (size);
+  else
+    {
+      new_mem = (void *) realloc (old_ptr, size);
+      if (new_mem == NULL)
+        {
+          /* We used to print OLD_PTR here using %x, and casting its
+             value to unsigned, but that lost on the Alpha, where
+             pointers and unsigned had different sizes.  Since the info
+             is of little or no value anyway, just don't print it.  */
+          fprintf (stderr, "fatal: memory exhausted (realloc of %u bytes).\n",
+                   size);
+          /* 1 means success on VMS, so pick a random number (ASCII `B').  */
+          exit (66);
+        }
+    }
+
+  return new_mem;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/xstat.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,52 @@
+/* xstat.c: stat and (maybe) lstat with error checking.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+#include <kpathsea/xstat.h>
+
+
+struct stat
+xstat P1C(const_string, path)
+{
+  struct stat s;
+  
+  if (stat (path, &s) != 0)
+    FATAL_PERROR (path);
+  
+  return s;
+}
+
+
+/* If we don't have symbolic links, lstat is the same as stat, and
+   a #define is made in the include file.  We declare lstat to avoid an
+   implicit declaration warning for development; sigh.  */
+
+#ifdef S_ISLNK
+extern int lstat ();
+struct stat
+xlstat P1C(const_string, path)
+{
+  struct stat s;
+  
+  if (lstat (path, &s) != 0)
+    FATAL_PERROR (path);
+  
+  return s;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kpathsea/xstrdup.c	Thu Apr 20 19:15:51 1995 +0000
@@ -0,0 +1,29 @@
+/* xstrdup.c: strdup with error checking.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <kpathsea/config.h>
+
+
+/* Return a copy of S in new storage.  */
+
+string
+xstrdup P1C(const_string, s)
+{
+  string new_string = (string) xmalloc (strlen (s) + 1);
+  return strcpy (new_string, s);
+}