Exemple #1
0
static string *subdir_match(str_list_type subdirs, string * matches)
{
    string *ret = XTALLOC1(string);
    unsigned len = 1;
    unsigned m;

    for (m = 0; matches[m]; m++) {
        size_t loc;
        unsigned e;
        string s = xstrdup(matches[m]);
        for (loc = strlen(s); loc > 0 && !IS_DIR_SEP(s[loc - 1]); loc--);
        while (loc > 0 && IS_DIR_SEP(s[loc - 1])) {
            loc--;
        }
        s[loc] = 0;             /* wipe out basename */

        for (e = 0; e < STR_LIST_LENGTH(subdirs); e++) {
            string subdir = STR_LIST_ELT(subdirs, e);
            size_t subdir_len = strlen(subdir);
            while (subdir_len > 0 && IS_DIR_SEP(subdir[subdir_len - 1])) {
                subdir_len--;
                subdir[subdir_len] = 0; /* remove trailing slashes from subdir spec */
            }
            if (FILESTRCASEEQ(subdir, s + loc - subdir_len)) {
                /* matched, save this one.  */
                XRETALLOC(ret, len + 1, string);
                ret[len - 1] = matches[m];
                len++;
            }
        }
        free(s);
    }
    ret[len - 1] = NULL;
    return ret;
}
void
xputenv P2C(const_string, var_name,  const_string, value)
{
  static const_string *saved_env_items;
  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);
              old_item -= (len + 1);  /* Back up to the `NAME='.  */
            }
        }
      
      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 */
}
Exemple #3
0
str_llist_type *
kpathsea_element_dirs (kpathsea kpse, string elt)
{
  str_llist_type *ret;
  unsigned i;

  /* If given nothing, return nothing.  */
  if (!elt || !*elt)
    return NULL;

  /* Normalize ELT before looking for a cached value.  */
  i = kpathsea_normalize_path (kpse, elt);

  /* If we've already cached the answer for ELT, return it.  */
  ret = cached (kpse, elt);
  if (ret)
    return ret;

  /* We're going to have a real directory list to return.  */
  ret = XTALLOC1 (str_llist_type);
  *ret = NULL;

  /* We handle the hard case in a subroutine.  */
  expand_elt (kpse, ret, elt, i);

  /* Remember the directory list we just found, in case future calls are
     made with the same ELT.  */
  cache (kpse, elt, ret);

#ifdef KPSE_DEBUG
  if (KPATHSEA_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 /* KPSE_DEBUG */

  return ret;
}
Exemple #4
0
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.  */
    }
}
Exemple #5
0
void
xputenv P2C(const_string, var_name,  const_string, value)
{
  string old_item = NULL;
  string new_item = concat3 (var_name, "=", value);
  unsigned name_len = strlen (var_name);

#ifndef SMART_PUTENV

  static const_string *saved_env_items = NULL;
  static unsigned saved_len;
  boolean found = false;

  /* 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;
      for (i = 0; i < saved_len && !found; i++)
        {
          if (STREQ (saved_env_items[i], var_name))
            {
              found = true;
              old_item = getenv (var_name);
#ifdef WIN32
	      /* win32 putenv() removes the variable if called with
		 "VAR=". So we have to cope with this case. Distinction
		 is not made between the value being "" or the variable
		 not set. */
	      if (old_item)
		old_item -= (name_len + 1);
#else
              assert (old_item);
              /* Back up to the `NAME=' in the environment before the
                 value that getenv returns.  */
              old_item -= (name_len + 1);
#endif
            }
        }

      if (!found)
        {
          /* 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 */

  /* If the old and the new values are identical, don't do anything.
     This is both more memory-efficient and safer as far as our
     assumptions (about how putenv is implemented in libc) go.  */
  if (!old_item || !STREQ (old_item, new_item))
    {
      char *new_val;
      /* 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);

      /* If their putenv copied `new_item', we can free it.  */
      new_val = getenv (var_name);
      if (new_val && new_val - name_len - 1 != new_item)
        free (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.  */
#ifndef WIN32
      /* ... except on Win32, where old_item points to garbage.
         Or at least non free-able memory. Or at least, that's what
         BoundsChecker says... FP, 06/10/98) */
      if (old_item)
        free (old_item);
#endif
#endif /* not SMART_PUTENV */
    }
}
search_list P4C(const_string, path,  const_string*, names,
                boolean, must_exist,  boolean, all)
{
  str_list_type ret_list;
  const_string* namep;
  string elt;
  boolean done = false;

#ifdef __DJGPP__
  /* We will use `stat' heavily, so let's request for
     the fastest possible version of `stat', by telling
     it what members of struct stat do we really need.

     We need to set this on each call because this is a
     library function; the caller might need other options
     from `stat'.  Thus save the flags and restore them
     before exit.

     This call tells `stat' that we do NOT need to recognize
     executable files (neither by an extension nor by a magic
     signature); that we do NOT need time stamp of root directories;
     and that we do NOT need the write access bit in st_mode.

     Note that `kpse_set_progname' needs the EXEC bits,
     but it was already called by the time we get here.  */
  unsigned short save_djgpp_flags  = _djstat_flags;

  _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT
		  | _STAT_ROOT_TIME | _STAT_WRITEBIT;
#endif

  ret_list = str_list_init();

  if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) {
    DEBUGF1  ("start search(files=[%s", *names);
    for (namep = names+1; *namep != NULL; namep++) {
      fputc(' ', stderr);
      fputs(*namep, stderr);
    }
    fprintf (stderr, "], must_exist=%d, find_all=%d, path=%s).\n",
             must_exist, all, path);
  }
  
  /* No need to do any expansion on names.  */

  for (namep = names; *namep; namep++) {
      if (kpse_absolute_p(*namep, true) && kpse_readable_file(*namep)) {
          str_list_add(&ret_list, xstrdup(*namep));
          /* I know, I know... */
          goto out;
      }
  }

  /* Look at each path element in turn. */
  for (elt = kpse_path_element (path); !done && elt;
       elt = kpse_path_element (NULL))
  {
    str_list_type *found;
    boolean allow_disk_search = true;
    if (elt[0] == '!' && elt[1] == '!') {
      /* !! magic -> disallow disk searches. */
      allow_disk_search = false;
      elt += 2;
    }

    /* See elt-dirs.c for side effects of this function. */
    kpse_normalize_path(elt);

    /* Try ls-R, unless we're searching for texmf.cnf. */
    found = first_search ? NULL : kpse_db_search_list(names, elt, all);

    /* Search the filesystem if (1) the path spec allows it, and either
         (2a) we are searching for texmf.cnf ; or
         (2b) no db exists; or 
         (2c) no db's are relevant to this elt; or
         (3) MUST_EXIST && NAME was not in the db.
       In (2*), `found' will be NULL.
       In (3),  `found' will be an empty list. */
    if (allow_disk_search && (!found || (must_exist && !STR_LIST(*found)))) {
      str_llist_type *dirs = kpse_element_dirs (elt);
      if (dirs && *dirs) {
        if (!found)
          found = XTALLOC1 (str_list_type);
        *found = dir_list_search_list (dirs, names, all);
      }
    }

    /* Did we find anything? */
    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;
      }
    }
  }

 out:
  if (STR_LIST_LENGTH (ret_list) == 0
      || (all && STR_LIST_LAST_ELT (ret_list) != NULL))
    str_list_add (&ret_list, NULL);

  if (first_search) {
    first_search = false;
  } else {
    /* 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", *names);
      for (namep = names+1; *namep != NULL; namep++) {
        fputc(' ', stderr);
        fputs(*namep, stderr);
      }
      fputs ("]) =>", stderr);
    }
    log_search (ret_list);
    if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
      putc ('\n', stderr);
  }

#ifdef __DJGPP__
  /* Undo any side effects.  */
  _djstat_flags = save_djgpp_flags;
#endif
  
  return STR_LIST (ret_list);
}
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)) {
    str_list_type *found;
    boolean allow_disk_search = true;

    if (*elt == '!' && *(elt + 1) == '!') {
      /* Those magic leading chars in a path element means don't search the
         disk for this elt.  And move past the magic to get to the name.  */
      allow_disk_search = false;
      elt += 2;
    }

    /* See elt-dirs.c for side effects of this function */
    kpse_normalize_path(elt);
    
    /* Try ls-R, unless we're searching for texmf.cnf.  Our caller
       (search), also tests first_search, and does the resetting.  */
    found = first_search ? NULL : kpse_db_search (name, elt, all);

    /* Search the filesystem if (1) the path spec allows it, and either
         (2a) we are searching for texmf.cnf ; or
         (2b) no db exists; or 
         (2c) no db's are relevant to this elt; or
         (3) MUST_EXIST && NAME was not in the db.
       In (2*), `found' will be NULL.
       In (3),  `found' will be an empty list. */
    if (allow_disk_search && (!found || (must_exist && !STR_LIST (*found)))) {
      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) {
      str_list_free (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;
}      
Exemple #8
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;
}