Example #1
0
static boolean
db_build (kpathsea kpse, hash_table_type *table,  const_string db_filename)
{
  string line;
  unsigned dir_count = 0, file_count = 0, ignore_dir_count = 0;
  unsigned len = strlen (db_filename) - sizeof (DB_NAME) + 1; /* Keep the /. */
  string top_dir = (string)xmalloc (len + 1);
  string cur_dir = NULL; /* First thing in ls-R might be a filename.  */
  FILE *db_file = fopen (db_filename, FOPEN_R_MODE);
#if defined(WIN32)
  string pp;
#endif

  strncpy (top_dir, db_filename, len);
  top_dir[len] = 0;

  if (db_file) {
    while ((line = read_line (db_file)) != NULL) {
      len = strlen (line);

#if defined(WIN32)
      for (pp = line; *pp; pp++) {
        if (IS_KANJI(pp))
          pp++;
        else
          *pp = TRANSFORM(*pp);
      }
#endif

      /* A line like `/foo:' = new dir foo.  Allow both absolute (/...)
         and explicitly relative (./...) names here.  It's a kludge to
         pass in the directory name with the trailing : still attached,
         but it doesn't actually hurt.  */
      if (len > 0 && line[len - 1] == ':'
          && kpathsea_absolute_p (kpse, line, true)) {
        /* New directory line.  */
        if (!ignore_dir_p (line)) {
          /* If they gave a relative name, prepend full directory name now.  */
          line[len - 1] = DIR_SEP;
          /* Skip over leading `./', it confuses `match' and is just a
             waste of space, anyway.  This will lose on `../', but `match'
             won't work there, either, so it doesn't matter.  */
          cur_dir = *line == '.' ? concat (top_dir, line + 2) : xstrdup (line);
          dir_count++;
        } else {
          cur_dir = NULL;
          ignore_dir_count++;
        }

      /* Ignore blank, `.' and `..' lines.  */
      } else if (*line != 0 && cur_dir   /* a file line? */
                 && !(*line == '.'
                      && (line[1] == 0 || (line[1] == '.' && line[2] == 0))))
      {
        /* Make a new hash table entry with a key of `line' and a data
           of `cur_dir'.  An already-existing identical key is ok, since
           a file named `foo' can be in more than one directory.  Share
           `cur_dir' among all its files (and hence never free it).

           Note that we assume that all names in the ls-R file have already
           been case-smashed to lowercase where appropriate.
        */
        hash_insert_normalized (table, xstrdup (line), cur_dir);
        file_count++;

      } /* else ignore blank lines or top-level files
           or files in ignored directories*/

      free (line);
    }

    xfclose (db_file, db_filename);

    if (file_count == 0) {
      WARNING1 ("kpathsea: %s: No usable entries in ls-R", db_filename);
      WARNING ("kpathsea: See the manual for how to generate ls-R");
      db_file = NULL;
    } else {
      str_list_add (&(kpse->db_dir_list), xstrdup (top_dir));
    }

#ifdef KPSE_DEBUG
    if (KPATHSEA_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 hash_summary_only = true;

      DEBUGF4 ("%s: %u entries in %d directories (%d hidden).\n",
               db_filename, file_count, dir_count, ignore_dir_count);
      DEBUGF ("ls-R hash table:");
      hash_print (*table, hash_summary_only);
      fflush (stderr);
    }
#endif /* KPSE_DEBUG */
  }

  free (top_dir);

  return db_file != NULL;
}
Example #2
0
boolean
kpse_absolute_p (const_string filename, boolean relative_ok)
{
    return kpathsea_absolute_p (kpse_def, filename, relative_ok);
}
Example #3
0
str_list_type *
kpathsea_db_search_list (kpathsea kpse, string* names,
                         const_string path_elt, boolean all)
{
  const_string *db_dirs, *orig_dirs;
  const_string last_slash, name, path;
  string temp_str = NULL;
  boolean done;
  unsigned e;
  const_string *aliases, *r;
  int n;
  str_list_type *ret = NULL;
  boolean relevant = false;

  /* If we failed to build the database (or if this is the recursive
     call to build the db path), quit.  */
  if (kpse->db.buckets == NULL)
    return NULL;

  /* Don't bother doing any lookups if this `path_elt' isn't covered by
     any of database directories.  We do this not so much because the
     extra couple of hash lookups matter -- they don't -- but rather
     because we want to return NULL in this case, so path_search can
     know to do a disk search.  */
  for (e = 0; !relevant && e < STR_LIST_LENGTH (kpse->db_dir_list); e++) {
    relevant = elt_in_db (STR_LIST_ELT (kpse->db_dir_list, e), path_elt);
  }
  if (!relevant)
    return NULL;

  done = false;
  ret = XTALLOC1 (str_list_type);
  *ret = str_list_init ();

  /* Handle each name. */
  for (n = 0; !done && names[n]; n++) {
      name = names[n];

      /* Absolute names should have been caught in our caller. */
      if (kpathsea_absolute_p(kpse, name, true))
          continue;

      /* 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 = (string)xmalloc (len);
          strncpy (dir_part, name, len - 1);
          dir_part[len - 1] = 0;
          path = temp_str = concat3 (path_elt, "/", dir_part);
          name = last_slash + 1;
          free (dir_part);
      } else {
          path = path_elt;
      }

      /* If we have aliases for this name, use them.  */
      if (kpse->alias_db.buckets)
          aliases = hash_lookup (kpse->alias_db, name);
      else
          aliases = NULL;

      if (!aliases) {
          aliases = XTALLOC1 (const_string);
          aliases[0] = NULL;
      }
      {  /* Push aliases up by one and insert the original name at front.  */
          unsigned i;
          unsigned len = 1; /* Have NULL element already allocated.  */
          for (r = aliases; *r; r++)
              len++;
          aliases = (const_string *) xrealloc ((void *) aliases,
                                               (len + 1) * sizeof(const_string));
          for (i = len; i > 0; i--) {
              aliases[i] = aliases[i - 1];
          }
          aliases[0] = name;
      }

      for (r = aliases; !done && *r; r++) {
          const_string ctry = *r;

          /* We have an ls-R db.  Look up `try'.  */
          orig_dirs = db_dirs = hash_lookup (kpse->db, ctry);

          /* 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, ctry);
            boolean matched = match (db_file, path);

#ifdef KPSE_DEBUG
            if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
              DEBUGF3 ("db:match(%s,%s) = %d\n", db_file, path, matched);
#endif

            /* We got a hit in the database.  Now see if the file actually
               exists, possibly under an alias.  */
            if (matched) {
              string found = NULL;
              if (kpathsea_readable_file (kpse, db_file)) {
                found = db_file;

              } else {
                const_string *a;

                free (db_file); /* `db_file' wasn't on disk.  */

                /* The hit in the DB doesn't exist in disk.  Now try all its
                   aliases.  For example, suppose we have a hierarchy on CD,
                   thus `mf.bas', but ls-R contains `mf.base'.  Find it anyway.
                   Could probably work around this with aliases, but
                   this is pretty easy and shouldn't hurt.  The upshot is that
                   if one of the aliases actually exists, we use that.  */
                for (a = aliases + 1; *a && !found; a++) {
                  string atry = concat (*db_dirs, *a);
                  if (kpathsea_readable_file (kpse, atry))
                    found = atry;
                  else
                    free (atry);
                }
              }

              /* If we have a real file, add it to the list, maybe done.  */
              if (found) {
                str_list_add (ret, found);
                if (!all && found)
                  done = true;
              }
            } else { /* no match in the db */
              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);
      }

      free ((void *) aliases);
      if (temp_str)
          free (temp_str);
  }

  return ret;
}
Example #4
0
string
kpathsea_selfdir (kpathsea kpse, const_string argv0)
{
  string ret = NULL;
  string self = NULL;

  if (kpathsea_absolute_p (kpse, argv0, true)) {
    self = xstrdup (argv0);
  } else {
#ifdef AMIGA
#include <dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
    BPTR lock;
    struct DosLibrary *DOSBase
      = (struct DosLibrary *) OpenLibrary ("dos.library", 0L);
    assert (DOSBase);

    self = xmalloc (BUFSIZ);
    lock = findpath (argv0);
    if (lock != ((BPTR) -1)) {
      if (getpath (lock, self) == -1) {
        *self = '\0';
      } else {
        strcat (self,DIR_SEP_STRING);
        strcat (self,argv0);
      }
      UnLock (lock);
    }
    CloseLibrary((struct Library *) DOSBase);
#else /* not AMIGA */
    const_string elt;
    struct stat s;

    /* Have to check PATH.  But don't call kpse_path_search since we don't
       want to search any ls-R's or do anything special with //'s.  */
    for (elt = kpathsea_path_element (kpse, getenv ("PATH")); !self && elt;
         elt = kpathsea_path_element (kpse, NULL)) {
      string name;

      /* UNIX tradition interprets the empty path element as "." */
      if (*elt == 0) elt = ".";

      name = concat3 (elt, DIR_SEP_STRING, argv0);

      /* In order to do this perfectly, we'd have to check the owner bits only
         if we are the file owner, and the group bits only if we belong
         to the file group.  That's a lot of work, though, and it's not
         likely that kpathsea will ever be used with a program that's
         only executable by some classes and not others.  See the
         `file_status' function in execute_cmd.c in bash for what's
         necessary if we were to do it right.  */
      if (stat (name, &s) == 0 && s.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) {
        /* Do not stop at directories. */
        if (!S_ISDIR(s.st_mode))
          self = name;
      }
    }
#endif /* not AMIGA */
  }

  /* If argv0 is somehow dir/exename, `self' will still be NULL.  */
  if (!self)
    self = concat3 (".", DIR_SEP_STRING, argv0);

  ret = xdirname (remove_dots (kpse, expand_symlinks (kpse, self)));

  free (self);

  return ret;
}