/* Expand all special constructs in a path, and include only the actually existing directories in the result. */ string kpse_path_expand P1C(const_string, path) { string ret; string xpath; string elt; unsigned len; /* Initialise ret to the empty string. */ ret = (string)xmalloc (1); *ret = 0; len = 0; /* Expand variables and braces first. */ xpath = kpse_brace_expand (path); /* Now expand each of the path elements, printing the results */ for (elt = kpse_path_element (xpath); elt; elt = kpse_path_element (NULL)) { str_llist_type *dirs; /* Skip and ignore magic leading chars. */ if (*elt == '!' && *(elt + 1) == '!') elt += 2; /* Search the disk for all dirs in the component specified. Be faster to check the database, but this is more reliable. */ dirs = kpse_element_dirs (elt); if (dirs && *dirs) { str_llist_elt_type *dir; for (dir = *dirs; dir; dir = STR_LLIST_NEXT (*dir)) { string thedir = STR_LLIST (*dir); unsigned dirlen = strlen (thedir); string save_ret = ret; /* We need to retain trailing slash if that's the root directory. * On unix, "/" is root dir, "" often taken to be current dir. * On windows, "C:/" is root dir of drive C, and "C:" is current * on drive C. There's no need to look at other cases, like UNC * names. */ if (dirlen == 1 || (dirlen == 3 && NAME_BEGINS_WITH_DEVICE (thedir) && IS_DIR_SEP (thedir[2]))) { ret = concat3 (ret, thedir, ENV_SEP_STRING); len += dirlen + 1; ret[len - 1] = ENV_SEP; } else { ret = concat (ret, thedir); len += dirlen; ret [len - 1] = ENV_SEP; } free (save_ret); } } } /* Get rid of trailing ':', if any. */ if (len != 0) ret[len - 1] = 0; return ret; }
void print_element_dirs (const_string elt) { str_llist_type *dirs; printf ("Directories of %s:\t", elt ? elt : "(nil)"); fflush (stdout); dirs = kpse_element_dirs (elt); if (!dirs) printf ("(nil)"); 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'); }
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; }