Пример #1
0
static void
expand_elt (kpathsea kpse, str_llist_type * str_list_ptr, string elt,
               unsigned start)
{
  string dir = elt + start, post;

  while (*dir != 0)
    {
      if (IS_DIR_SEP_CH (*dir))
        {
          /* If two or more consecutive /'s, find subdirectories.  */
          if (IS_DIR_SEP_CH (dir[1]))
            {
              for (post = dir + 1; IS_DIR_SEP_CH (*post); post++) ;
            do_subdir (kpse, str_list_ptr, elt, dir - elt + 1, post);
              return;
            }

          /* No special stuff at this slash.  Keep going.  */
        }

      dir++;
    }

  /* When we reach the end of ELT, it will be a normal filename.  */
  checked_dir_list_add (kpse, str_list_ptr, elt);
}
Пример #2
0
static boolean
ignore_dir_p (const_string dirname)
{
  const_string dot_pos = dirname;

  while ((dot_pos = strchr (dot_pos + 1, '.'))) {
    /* If / before and no / after, skip it. */
    if (IS_DIR_SEP_CH (dot_pos[-1]) && dot_pos[1] && !IS_DIR_SEP_CH (dot_pos[1]))
      return true;
  }

  return false;
}
Пример #3
0
static void
dir_list_add (str_llist_type *l, string dir)
{
  char last_char = dir[strlen (dir) - 1];
  string saved_dir
    = IS_DIR_SEP_CH (last_char) || IS_DEVICE_SEP (last_char)
      ? xstrdup (dir)
      : concat (dir, DIR_SEP_STRING);

  str_llist_add (l, saved_dir);
}
Пример #4
0
unsigned
kpathsea_normalize_path (kpathsea kpse, string elt)
{
  unsigned ret;
  unsigned i;

#if defined(WIN32)
  for (i = 0; elt[i]; i++) {
    if (elt[i] == '\\')
      elt[i] = '/';
    else if (IS_KANJI(elt + i))
      i++;
  }
#endif

  if (NAME_BEGINS_WITH_DEVICE(elt)) {
    if (*elt >= 'A' && *elt <= 'Z')
      *elt += 'a' - 'A';
    ret = 2;

  } else if (IS_UNC_NAME(elt)) {
    for (ret = 2; elt[ret] && !IS_DIR_SEP_CH(elt[ret]); ret++)
      ;

  } else
    ret = 0;

  for (i = ret; IS_DIR_SEP_CH(elt[i]); ++i)
    ;
  if (i > ret + 1) {
#ifdef KPSE_DEBUG
  if (KPATHSEA_DEBUG_P (KPSE_DEBUG_STAT))
    DEBUGF2 ("kpse_normalize_path (%s) => %u\n", elt, ret);
#endif /* KPSE_DEBUG */

    memmove (elt + ret + 1, elt + i, strlen (elt + i) + 1);
  }

  return ret;
}
Пример #5
0
static void
do_subdir (kpathsea kpse, str_llist_type *str_list_ptr, string elt,
              unsigned elt_length, string post)
{
#ifdef WIN32
  WIN32_FIND_DATAW find_file_data;
  HANDLE hnd;
  int proceed;
  int nlinks = 2;
#else
  DIR *dir;
  struct dirent *e;
#endif /* not WIN32 */
  fn_type name;

  /* Some old compilers don't allow aggregate initialization.  */
  name = fn_copy0 (elt, elt_length);

  assert (IS_DIR_SEP_CH (elt[elt_length - 1])
          || IS_DEVICE_SEP (elt[elt_length - 1]));

#if defined (WIN32)
  strcpy(dirname, FN_STRING(name));
  strcat(dirname, "/*.*");         /* "*.*" or "*" -- seems equivalent. */
  get_wstring_from_fsyscp(dirname, dirnamew);
  hnd = FindFirstFileW(dirnamew, &find_file_data);

  if (hnd == INVALID_HANDLE_VALUE) {
    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);
    expand_elt (kpse, str_list_ptr, FN_STRING (name), elt_length);
    fn_shrink_to (&name, elt_length);
  }
  proceed = 1;
  while (proceed) {
    if (find_file_data.cFileName[0] != L'.') {
      int links;

      /* Construct the potential subdirectory name.  */
      potname = get_fsyscp_from_wstring(find_file_data.cFileName, potname=NULL);
      fn_str_grow (&name, potname);
      free(potname);

      /* Maybe we have cached the leafness of this directory.
                 The function will return 0 if unknown,
                 else the actual (Unix-like) value. */
      links = kpathsea_dir_links (kpse, FN_STRING (name), 0);

      if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
        unsigned potential_len = FN_LENGTH (name);
        /* in any case, compute the leafness */
        nlinks++;

        /* 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 (kpse, 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. */

        if (links == 0 || links > 2)
          /* All criteria are met; find subdirectories.  */
        do_subdir (kpse, str_list_ptr, FN_STRING (name),
                     potential_len, post);
        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));
      }
      fn_shrink_to (&name, elt_length);
    }
    proceed = FindNextFileW (hnd, &find_file_data);
  }
  /* Update the leafness of name. */
  kpathsea_dir_links(kpse, FN_STRING(name), nlinks);
  fn_free (&name);
  FindClose(hnd);

#else /* not WIN32 */

  /* 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);
      expand_elt (kpse, str_list_ptr, FN_STRING (name), elt_length);
      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 = kpathsea_dir_links (kpse, FN_STRING (name), 0);

          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 (kpse, 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 ST_NLINK_TRICK
              /* With SAS/C++ 6.55 on the Amiga, stat sets the st_nlink
                 field to -1 for a file, or to 1 for a directory.
                 Cygwin 1.7 also leaves st_nlink as 1:
                 http://cygwin.com/ml/cygwin-developers/2008-04/msg00110.html
                 */
              if (links != 2)
#endif /* ST_NLINK_TRICK */
                /* All criteria are met; find subdirectories.  */
                  do_subdir (kpse, str_list_ptr, FN_STRING (name),
                           potential_len, post);
#ifdef ST_NLINK_TRICK
              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);
#endif /* not WIN32 */
}
Пример #6
0
static boolean
match (const_string filename,  const_string path_elt)
{
  const_string original_filename = filename;
  boolean matched = false;

  for (; *filename && *path_elt; filename++, path_elt++) {
    if (FILECHARCASEEQ (*filename, *path_elt)) /* normal character match */
      ;

    else if (IS_DIR_SEP_CH (*path_elt)  /* at // */
             && original_filename < filename && IS_DIR_SEP_CH (path_elt[-1])) {
      while (IS_DIR_SEP_CH (*path_elt))
        path_elt++; /* get past second and any subsequent /'s */
      if (*path_elt == 0) {
        /* Trailing //, matches anything. We could make this part of the
           other case, but it seems pointless to do the extra work.  */
        matched = true;
        break;
      } else {
        /* Intermediate //, have to match rest of PATH_ELT.  */
        for (; !matched && *filename; filename++) {
          /* Try matching at each possible character.  */
          if (IS_DIR_SEP_CH (filename[-1])
              && FILECHARCASEEQ (*filename, *path_elt))
            matched = match (filename, path_elt);
        }
        /* Prevent filename++ when *filename='\0'. */
        break;
      }
    }

    else /* normal character nonmatch, quit */
      break;
  }

  /* If we've reached the end of PATH_ELT, check that we're at the last
     component of FILENAME (that is, no directory separators remaining);
     only then have we matched.  */
  if (!matched && *path_elt == 0) {
    /* Typically PATH_ELT ends with, say, `vf', and FILENAME ends with
       `vf/ptmr.vf'.  In that case, we'll be at the /.  On the other
       hand, if PATH_ELT ended with a / (as in `vf/'), FILENAME being
       the same `vf/ptmr.vf', we'll be at the `p'.
       Upshot: if we're at a dir sep in FILENAME, skip it.  */
    if (IS_DIR_SEP_CH (*filename))
      filename++;

    /* Here are the basic possibilities for the check on being at the
       last component:
       1) PATH_ELT is empty and FILENAME is `ptmr.vf'     => match.
          (we now have original_filename == filename)
       2) PATH_ELT is empty and FILENAME is `foo/ptmr.vf' => no match.
          (we now have original_filename == filename)
       3) PATH_ELT is `vf/' and FILENAME is `vf/ptmr.vf'
          (we are now after the / in each)                 => match.
       4) PATH_ELT is `vf' and FILENAME is `vfoo.ext'
          (we are now after the f in each)                 => no match.
       
       When (the original) PATH_ELT was the empty string, we want to match
       a FILENAME without dir seps.  (This could be argued, and may never
       happen in practice, but is the historical behavior.)  */
    /* if original_filename != filename then original_filename < filename */
    if (original_filename == filename || IS_DIR_SEP_CH (filename[-1])) {
      while (*filename && !IS_DIR_SEP_CH (*filename))
        filename++;
      matched = *filename == 0;
    }
  }

  return matched;
}