void str_list_concat_elements P2C(str_list_type *, target, str_list_type, more) { if (STR_LIST_LENGTH(more) == 0) { return; } else if (STR_LIST_LENGTH(*target) == 0) { unsigned int i; STR_LIST_LENGTH(*target) = STR_LIST_LENGTH(more); STR_LIST(*target) = xmalloc(STR_LIST_LENGTH(more)*sizeof(char*)); for (i=0;i!=STR_LIST_LENGTH(more);++i) { STR_LIST_ELT(*target,i)=xstrdup(STR_LIST_ELT(more,i)); } return; } else { unsigned new_len; char ** new_list; unsigned int i,j; new_list = xmalloc(STR_LIST_LENGTH (*target) * STR_LIST_LENGTH (more) * sizeof(char*)); new_len = 0; for (j = 0; j != STR_LIST_LENGTH(more); ++j) { for (i = 0; i != STR_LIST_LENGTH(*target); ++i) { new_list[new_len] = concat(STR_LIST_ELT(*target,i), STR_LIST_ELT(more,j)); ++new_len; } } for (i = 0; i != STR_LIST_LENGTH(*target); ++i) free(STR_LIST_ELT(*target, i)); free(STR_LIST(*target)); STR_LIST_LENGTH(*target) = new_len; STR_LIST(*target) = new_list; } }
void str_list_free P1C(str_list_type *, l) { if (STR_LIST (*l)) { free (STR_LIST (*l)); STR_LIST (*l) = NULL; } }
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; }
const_string * hash_lookup (hash_table_type table, const_string key) { hash_element_type *p; cstr_list_type ret; unsigned n = hash (table, key); ret = cstr_list_init (); /* Look at everything in this bucket. */ for (p = table.buckets[n]; p != NULL; p = p->next) if (FILESTRCASEEQ (key, p->key)) cstr_list_add (&ret, p->value); /* If we found anything, mark end of list with null. */ if (STR_LIST (ret)) cstr_list_add (&ret, NULL); #ifdef KPSE_DEBUG #if defined (KPSE_COMPAT_API) { kpathsea kpse = kpse_def; if (KPATHSEA_DEBUG_P (KPSE_DEBUG_HASH)) { DEBUGF1 ("hash_lookup(%s) =>", key); if (!STR_LIST (ret)) fputs (" (nil)\n", stderr); else { const_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 #endif return STR_LIST (ret); }
str_list_type str_list_init P1H(void) { str_list_type ret; STR_LIST_LENGTH (ret) = 0; STR_LIST (ret) = NULL; return ret; }
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 (FILESTRCASEEQ (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 KPSE_DEBUG if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) { DEBUGF1 ("hash_lookup(%s) =>", key); if (!STR_LIST (ret)) fputs (" (nil)\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); }
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); }
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); }
search P4C(const_string, path, const_string, original_name, boolean, must_exist, boolean, all) { str_list_type ret_list; string name; boolean absolute_p; #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 /* Make a leading ~ count as an absolute filename, and expand $FOO's. */ name = kpse_expand (original_name); /* If the first name is absolute or explicitly relative, no need to consider PATH at all. */ absolute_p = kpse_absolute_p (name, true); if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) DEBUGF4 ("start 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); /* The very first search is for texmf.cnf. We can't log that, since we want to allow setting TEXMFLOG in texmf.cnf. */ 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) =>", original_name); 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; }
void kpathsea_init_db (kpathsea kpse) { const_string db_path; string *db_files; string *orig_db_files; str_list_type unique_list; int dbi; boolean ok = false; assert (sizeof(DB_NAME) == sizeof(DB_NAME_LC)); db_path = kpathsea_init_format (kpse, kpse_db_format); db_files = kpathsea_path_search_list_generic (kpse, db_path, db_names, true, true); orig_db_files = db_files; /* Mac OS X and others can use a case-insensitive, case-preserving filesystem by default, in which case ls-R and ls-r point to the same file. Also, Windows is case-insensitive. In these cases, we want to avoid reading the same file multiple times. */ dbi = 0; unique_list = str_list_init (); while (db_files[dbi] != NULL) { string path1 = db_files[dbi]; string path2 = db_files[dbi + 1]; /* first-pass check in case path1/path2 aren't even potentially equal; mainly in case the order from kpathsea_path_search_list_generic changes. */ if (path2 && strcasecmp (path1, path2) == 0 && same_file_p (path1, path2)) { /* they are the same, skip over path1, we'll add path2 on the next iteration (when it's path1). */ #ifdef KPSE_DEBUG if (KPATHSEA_DEBUG_P (KPSE_DEBUG_HASH)) { DEBUGF2 ("db:init(): skipping db same_file_p %s, will add %s.\n", path1, path2); } #endif free (path1); } else { /* they are not the same, add path1. */ #ifdef KPSE_DEBUG if (KPATHSEA_DEBUG_P (KPSE_DEBUG_HASH)) { DEBUGF1 ("db:init(): using db file %s.\n", path1); } #endif str_list_add (&unique_list, path1); } /* could be more clever and increment by two, but then would have to avoid jumping off the end of db_files */ dbi++; } /* always add a NULL terminator. */ str_list_add (&unique_list, NULL); free (orig_db_files); db_files = STR_LIST (unique_list); orig_db_files = db_files; /* Must do this after the path searching (which ends up calling kpse_db_search recursively), so kpse->db.buckets stays NULL. */ kpse->db = hash_create (DB_HASH_SIZE); while (db_files && *db_files) { if (db_build (kpse, &(kpse->db), *db_files)) ok = true; free (*db_files); db_files++; } if (!ok) { /* 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 (kpse->db.buckets); kpse->db.buckets = NULL; } free (orig_db_files); /* Add the content of any alias databases. There may exist more than one alias file along DB_NAME files. This duplicates the above code -- should be a function. */ ok = false; db_files = kpathsea_all_path_search (kpse, db_path, ALIAS_NAME); orig_db_files = db_files; kpse->alias_db = hash_create (ALIAS_HASH_SIZE); while (db_files && *db_files) { if (alias_build (kpse, &(kpse->alias_db), *db_files)) ok = true; free (*db_files); db_files++; } if (!ok) { free (kpse->alias_db.buckets); kpse->alias_db.buckets = NULL; } free (orig_db_files); }