beta-0.89.2
[luatex.git] / source / texk / kpathsea / db.c
blob2c1ed6344d0cdf10ded01384a9d348e73c3683ac
1 /* db.c: an external database to avoid filesystem lookups.
3 Copyright 1994, 1995, 1996, 1997, 2008, 2009, 2011, 2012, 2014 Karl Berry.
4 Copyright 1997-2005 Olaf Weber.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with this library; if not, see <http://www.gnu.org/licenses/>. */
19 #include <kpathsea/config.h>
20 #include <kpathsea/absolute.h>
21 #include <kpathsea/c-stat.h>
22 #include <kpathsea/c-fopen.h>
23 #include <kpathsea/c-pathch.h>
24 #include <kpathsea/db.h>
25 #include <kpathsea/hash.h>
26 #include <kpathsea/line.h>
27 #include <kpathsea/pathsearch.h>
28 #include <kpathsea/readable.h>
29 #include <kpathsea/str-list.h>
30 #include <kpathsea/tex-file.h>
31 #include <kpathsea/variable.h>
33 #ifndef DB_HASH_SIZE
34 /* Based on the size of 2014 texmf-dist/ls-R, about 130,000 entries. */
35 #define DB_HASH_SIZE 64007
36 #endif
37 #ifndef DB_NAME
38 #define DB_NAME "ls-R"
39 #endif
40 #ifndef DB_NAME_LC
41 #define DB_NAME_LC "ls-r"
42 #endif
44 /* In the loop in init() below where we check for DB_NAME_LC and DB_NAME
45 being the same file, it's convenient to ignore the first of a pair.
46 So put the canonical name second. Sure wish I hadn't used a capital
47 letter in the name in the first place. */
48 /* We use non-const strings initialized with string constants in order
49 to avoid some compiler warnings. */
50 static char db_name_lc[] = DB_NAME_LC;
51 static char db_name[] = DB_NAME;
52 static string db_names[] = {
53 db_name_lc,
54 db_name,
55 NULL
58 #ifndef ALIAS_NAME
59 #define ALIAS_NAME "aliases"
60 #endif
61 #ifndef ALIAS_HASH_SIZE
62 #define ALIAS_HASH_SIZE 1009
63 #endif
66 /* If DIRNAME contains any element beginning with a `.' (that is more
67 than just `./'), return true. This is to allow ``hidden''
68 directories -- ones that don't get searched. */
70 static boolean
71 ignore_dir_p (const_string dirname)
73 const_string dot_pos = dirname;
75 while ((dot_pos = strchr (dot_pos + 1, '.'))) {
76 /* If / before and no / after, skip it. */
77 if (IS_DIR_SEP_CH (dot_pos[-1]) && dot_pos[1] && !IS_DIR_SEP_CH (dot_pos[1]))
78 return true;
81 return false;
84 /* If no DB_FILENAME, return false (maybe they aren't using this feature).
85 Otherwise, add entries from DB_FILENAME to TABLE, and return true. */
87 static boolean
88 db_build (kpathsea kpse, hash_table_type *table, const_string db_filename)
90 string line;
91 unsigned dir_count = 0, file_count = 0, ignore_dir_count = 0;
92 unsigned len = strlen (db_filename) - sizeof (DB_NAME) + 1; /* Keep the /. */
93 string top_dir = (string)xmalloc (len + 1);
94 string cur_dir = NULL; /* First thing in ls-R might be a filename. */
95 FILE *db_file = fopen (db_filename, FOPEN_R_MODE);
96 #if defined(WIN32)
97 string pp;
98 #endif
100 strncpy (top_dir, db_filename, len);
101 top_dir[len] = 0;
103 if (db_file) {
104 while ((line = read_line (db_file)) != NULL) {
105 len = strlen (line);
107 #if defined(WIN32)
108 for (pp = line; *pp; pp++) {
109 if (IS_KANJI(pp))
110 pp++;
111 else
112 *pp = TRANSFORM(*pp);
114 #endif
116 /* A line like `/foo:' = new dir foo. Allow both absolute (/...)
117 and explicitly relative (./...) names here. It's a kludge to
118 pass in the directory name with the trailing : still attached,
119 but it doesn't actually hurt. */
120 if (len > 0 && line[len - 1] == ':'
121 && kpathsea_absolute_p (kpse, line, true)) {
122 /* New directory line. */
123 if (!ignore_dir_p (line)) {
124 /* If they gave a relative name, prepend full directory name now. */
125 line[len - 1] = DIR_SEP;
126 /* Skip over leading `./', it confuses `match' and is just a
127 waste of space, anyway. This will lose on `../', but `match'
128 won't work there, either, so it doesn't matter. */
129 cur_dir = *line == '.' ? concat (top_dir, line + 2) : xstrdup (line);
130 dir_count++;
131 } else {
132 cur_dir = NULL;
133 ignore_dir_count++;
136 /* Ignore blank, `.' and `..' lines. */
137 } else if (*line != 0 && cur_dir /* a file line? */
138 && !(*line == '.'
139 && (line[1] == 0 || (line[1] == '.' && line[2] == 0))))
141 /* Make a new hash table entry with a key of `line' and a data
142 of `cur_dir'. An already-existing identical key is ok, since
143 a file named `foo' can be in more than one directory. Share
144 `cur_dir' among all its files (and hence never free it).
146 Note that we assume that all names in the ls-R file have already
147 been case-smashed to lowercase where appropriate.
149 hash_insert_normalized (table, xstrdup (line), cur_dir);
150 file_count++;
152 } /* else ignore blank lines or top-level files
153 or files in ignored directories*/
155 free (line);
158 xfclose (db_file, db_filename);
160 if (file_count == 0) {
161 WARNING1 ("kpathsea: %s: No usable entries in ls-R", db_filename);
162 WARNING ("kpathsea: See the manual for how to generate ls-R");
163 db_file = NULL;
164 } else {
165 str_list_add (&(kpse->db_dir_list), xstrdup (top_dir));
168 #ifdef KPSE_DEBUG
169 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_HASH)) {
170 /* Don't make this a debugging bit, since the output is so
171 voluminous, and being able to specify -1 is too useful.
172 Instead, let people who want it run the program under
173 a debugger and change the variable that way. */
174 boolean hash_summary_only = true;
176 DEBUGF4 ("%s: %u entries in %d directories (%d hidden).\n",
177 db_filename, file_count, dir_count, ignore_dir_count);
178 DEBUGF ("ls-R hash table:");
179 hash_print (*table, hash_summary_only);
180 fflush (stderr);
182 #endif /* KPSE_DEBUG */
185 free (top_dir);
187 return db_file != NULL;
191 /* Insert FNAME into the hash table. This is for files that get built
192 during a run. We wouldn't want to reread all of ls-R, even if it got
193 rebuilt. */
195 void
196 kpathsea_db_insert (kpathsea kpse, const_string passed_fname)
198 /* We might not have found ls-R, or even had occasion to look for it
199 yet, so do nothing if we have no hash table. */
200 if (kpse->db.buckets) {
201 const_string dir_part;
202 string fname = xstrdup (passed_fname);
203 string baseptr = fname + (xbasename (fname) - fname);
204 const_string file_part = xstrdup (baseptr);
206 *baseptr = '\0'; /* Chop off the filename. */
207 dir_part = fname; /* That leaves the dir, with the trailing /. */
209 /* Note that we do not assuse that these names have been normalized. */
210 hash_insert (&(kpse->db), file_part, dir_part);
214 /* Return true if FILENAME could be in PATH_ELT, i.e., if the directory
215 part of FILENAME matches PATH_ELT. Have to consider // wildcards, but
216 $ and ~ expansion have already been done. */
218 static boolean
219 match (const_string filename, const_string path_elt)
221 const_string original_filename = filename;
222 boolean matched = false;
224 for (; *filename && *path_elt; filename++, path_elt++) {
225 if (FILECHARCASEEQ (*filename, *path_elt)) /* normal character match */
228 else if (IS_DIR_SEP_CH (*path_elt) /* at // */
229 && original_filename < filename && IS_DIR_SEP_CH (path_elt[-1])) {
230 while (IS_DIR_SEP_CH (*path_elt))
231 path_elt++; /* get past second and any subsequent /'s */
232 if (*path_elt == 0) {
233 /* Trailing //, matches anything. We could make this part of the
234 other case, but it seems pointless to do the extra work. */
235 matched = true;
236 break;
237 } else {
238 /* Intermediate //, have to match rest of PATH_ELT. */
239 for (; !matched && *filename; filename++) {
240 /* Try matching at each possible character. */
241 if (IS_DIR_SEP_CH (filename[-1])
242 && FILECHARCASEEQ (*filename, *path_elt))
243 matched = match (filename, path_elt);
245 /* Prevent filename++ when *filename='\0'. */
246 break;
250 else /* normal character nonmatch, quit */
251 break;
254 /* If we've reached the end of PATH_ELT, check that we're at the last
255 component of FILENAME (that is, no directory separators remaining);
256 only then have we matched. */
257 if (!matched && *path_elt == 0) {
258 /* Typically PATH_ELT ends with, say, `vf', and FILENAME ends with
259 `vf/ptmr.vf'. In that case, we'll be at the /. On the other
260 hand, if PATH_ELT ended with a / (as in `vf/'), FILENAME being
261 the same `vf/ptmr.vf', we'll be at the `p'.
262 Upshot: if we're at a dir sep in FILENAME, skip it. */
263 if (IS_DIR_SEP_CH (*filename))
264 filename++;
266 /* Here are the basic possibilities for the check on being at the
267 last component:
268 1) PATH_ELT is empty and FILENAME is `ptmr.vf' => match.
269 (we now have original_filename == filename)
270 2) PATH_ELT is empty and FILENAME is `foo/ptmr.vf' => no match.
271 (we now have original_filename == filename)
272 3) PATH_ELT is `vf/' and FILENAME is `vf/ptmr.vf'
273 (we are now after the / in each) => match.
274 4) PATH_ELT is `vf' and FILENAME is `vfoo.ext'
275 (we are now after the f in each) => no match.
277 When (the original) PATH_ELT was the empty string, we want to match
278 a FILENAME without dir seps. (This could be argued, and may never
279 happen in practice, but is the historical behavior.) */
280 /* if original_filename != filename then original_filename < filename */
281 if (original_filename == filename || IS_DIR_SEP_CH (filename[-1])) {
282 while (*filename && !IS_DIR_SEP_CH (*filename))
283 filename++;
284 matched = *filename == 0;
288 return matched;
292 /* If DB_DIR is a prefix of PATH_ELT, return true; otherwise false.
293 That is, the question is whether to try the db for a file looked up
294 in PATH_ELT. If PATH_ELT == ".", for example, the answer is no. If
295 PATH_ELT == "/usr/local/lib/texmf/fonts//tfm", the answer is yes.
297 In practice, ls-R is only needed for lengthy subdirectory
298 comparisons, but there's no gain to checking PATH_ELT to see if it is
299 a subdir match, since the only way to do that is to do a string
300 search in it, which is all we do anyway. */
302 static boolean
303 elt_in_db (const_string db_dir, const_string path_elt)
305 boolean found = false;
307 while (!found && FILECHARCASEEQ (*db_dir++, *path_elt++)) {
308 /* If we've matched the entire db directory, it's good. */
309 if (*db_dir == 0)
310 found = true;
312 /* If we've reached the end of PATH_ELT, but not the end of the db
313 directory, it's no good. */
314 else if (*path_elt == 0)
315 break;
318 return found;
321 /* If ALIAS_FILENAME exists, read it into TABLE. */
323 static boolean
324 alias_build (kpathsea kpse, hash_table_type *table,
325 const_string alias_filename)
327 string line, real, alias;
328 unsigned count = 0;
329 FILE *alias_file = fopen (alias_filename, FOPEN_R_MODE);
331 if (alias_file) {
332 while ((line = read_line (alias_file)) != NULL) {
333 /* comments or empty */
334 if (*line == 0 || *line == '%' || *line == '#') {
336 } else {
337 /* Each line should have two fields: realname aliasname. */
338 real = line;
339 while (*real && ISSPACE (*real))
340 real++;
341 alias = real;
342 while (*alias && !ISSPACE (*alias))
343 alias++;
344 *alias++ = 0;
345 while (*alias && ISSPACE (*alias))
346 alias++;
347 /* Is the check for errors strong enough? Should we warn the user
348 for potential errors? */
349 if (strlen (real) != 0 && strlen (alias) != 0) {
350 /* Stuff in the alias file should be normalized. */
351 hash_insert_normalized (table, xstrdup (alias), xstrdup (real));
352 count++;
355 free (line);
358 #ifdef KPSE_DEBUG
359 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_HASH)) {
360 /* As with ls-R above ... */
361 boolean hash_summary_only = true;
362 DEBUGF2 ("%s: %u aliases.\n", alias_filename, count);
363 DEBUGF ("alias hash table:");
364 hash_print (*table, hash_summary_only);
365 fflush (stderr);
367 #endif /* KPSE_DEBUG */
369 xfclose (alias_file, alias_filename);
372 return alias_file != NULL;
375 /* Initialize the path for ls-R files, and read them all into the hash
376 table `db'. If no usable ls-R's found, set kpse->db.buckets to NULL. */
378 void
379 kpathsea_init_db (kpathsea kpse)
381 const_string db_path;
382 string *db_files;
383 string *orig_db_files;
384 str_list_type unique_list;
385 int dbi;
386 boolean ok = false;
388 assert (sizeof(DB_NAME) == sizeof(DB_NAME_LC));
390 db_path = kpathsea_init_format (kpse, kpse_db_format);
391 db_files = kpathsea_path_search_list_generic (kpse, db_path, db_names,
392 true, true);
393 orig_db_files = db_files;
395 /* Mac OS X and others can use a case-insensitive, case-preserving
396 filesystem by default, in which case ls-R and ls-r point to the
397 same file. Also, Windows is case-insensitive. In these cases,
398 we want to avoid reading the same file multiple times. */
399 dbi = 0;
400 unique_list = str_list_init ();
402 while (db_files[dbi] != NULL) {
403 string path1 = db_files[dbi];
404 string path2 = db_files[dbi + 1];
406 /* first-pass check in case path1/path2 aren't even
407 potentially equal; mainly in case the order from
408 kpathsea_path_search_list_generic changes. */
409 if (path2
410 && strcasecmp (path1, path2) == 0
411 && same_file_p (path1, path2)) {
412 /* they are the same, skip over path1, we'll add path2
413 on the next iteration (when it's path1). */
414 #ifdef KPSE_DEBUG
415 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_HASH)) {
416 DEBUGF2 ("db:init(): skipping db same_file_p %s, will add %s.\n",
417 path1, path2);
419 #endif
420 free (path1);
422 } else {
423 /* they are not the same, add path1. */
424 #ifdef KPSE_DEBUG
425 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_HASH)) {
426 DEBUGF1 ("db:init(): using db file %s.\n", path1);
428 #endif
429 str_list_add (&unique_list, path1);
432 /* could be more clever and increment by two, but then would
433 have to avoid jumping off the end of db_files */
434 dbi++;
437 /* always add a NULL terminator. */
438 str_list_add (&unique_list, NULL);
440 free (orig_db_files);
441 db_files = STR_LIST (unique_list);
442 orig_db_files = db_files;
444 /* Must do this after the path searching (which ends up calling
445 kpse_db_search recursively), so kpse->db.buckets stays NULL. */
446 kpse->db = hash_create (DB_HASH_SIZE);
448 while (db_files && *db_files) {
449 if (db_build (kpse, &(kpse->db), *db_files))
450 ok = true;
451 free (*db_files);
452 db_files++;
455 if (!ok) {
456 /* If db can't be built, leave `size' nonzero (so we don't
457 rebuild it), but clear `buckets' (so we don't look in it). */
458 free (kpse->db.buckets);
459 kpse->db.buckets = NULL;
462 free (orig_db_files);
464 /* Add the content of any alias databases. There may exist more than
465 one alias file along DB_NAME files. This duplicates the above code
466 -- should be a function. */
467 ok = false;
468 db_files = kpathsea_all_path_search (kpse, db_path, ALIAS_NAME);
469 orig_db_files = db_files;
471 kpse->alias_db = hash_create (ALIAS_HASH_SIZE);
473 while (db_files && *db_files) {
474 if (alias_build (kpse, &(kpse->alias_db), *db_files))
475 ok = true;
476 free (*db_files);
477 db_files++;
480 if (!ok) {
481 free (kpse->alias_db.buckets);
482 kpse->alias_db.buckets = NULL;
485 free (orig_db_files);
488 /* Avoid doing anything if this PATH_ELT is irrelevant to the databases. */
489 str_list_type *
490 kpathsea_db_search (kpathsea kpse, const_string name,
491 const_string orig_path_elt, boolean all)
493 const_string *db_dirs, *orig_dirs;
494 const_string last_slash, path_elt;
495 string temp_str = NULL;
496 boolean done;
497 unsigned e;
498 str_list_type *ret = NULL;
499 const_string *aliases, *r;
500 boolean relevant = false;
502 /* If we failed to build the database (or if this is the recursive
503 call to build the db path), quit. */
504 if (kpse->db.buckets == NULL)
505 return NULL;
507 /* When tex-glyph.c calls us looking for, e.g., dpi600/cmr10.pk, we
508 won't find it unless we change NAME to just `cmr10.pk' and append
509 `/dpi600' to PATH_ELT. We are justified in using a literal `/'
510 here, since that's what tex-glyph.c unconditionally uses in
511 DPI_BITMAP_SPEC. But don't do anything if the / begins NAME; that
512 should never happen. */
513 last_slash = strrchr (name, '/');
514 if (last_slash && last_slash != name) {
515 unsigned len = last_slash - name + 1;
516 string dir_part = (string)xmalloc (len);
517 strncpy (dir_part, name, len - 1);
518 dir_part[len - 1] = 0;
519 path_elt = temp_str = concat3 (orig_path_elt, "/", dir_part);
520 name = last_slash + 1;
521 free (dir_part);
522 } else
523 path_elt = orig_path_elt;
525 /* Don't bother doing any lookups if this `path_elt' isn't covered by
526 any of database directories. We do this not so much because the
527 extra couple of hash lookups matter -- they don't -- but rather
528 because we want to return NULL in this case, so path_search can
529 know to do a disk search. */
530 for (e = 0; !relevant && e < STR_LIST_LENGTH (kpse->db_dir_list); e++) {
531 relevant = elt_in_db (STR_LIST_ELT (kpse->db_dir_list, e), path_elt);
533 if (!relevant)
534 return NULL;
536 /* If we have aliases for this name, use them. */
537 if (kpse->alias_db.buckets)
538 aliases = hash_lookup (kpse->alias_db, name);
539 else
540 aliases = NULL;
542 if (!aliases) {
543 aliases = XTALLOC1 (const_string);
544 aliases[0] = NULL;
546 { /* Push aliases up by one and insert the original name at the front. */
547 unsigned i;
548 unsigned len = 1; /* Have NULL element already allocated. */
549 for (r = aliases; *r; r++)
550 len++;
551 /* This is essentially
552 XRETALLOC (aliases, len + 1, const_string);
553 except that MSVC warns without the cast to `void *'. */
554 aliases = (const_string *) xrealloc ((void *) aliases,
555 (len + 1) * sizeof(const_string));
556 for (i = len; i > 0; i--) {
557 aliases[i] = aliases[i - 1];
559 aliases[0] = name;
562 done = false;
563 for (r = aliases; !done && *r; r++) {
564 const_string ctry = *r;
566 /* We have an ls-R db. Look up `try'. */
567 orig_dirs = db_dirs = hash_lookup (kpse->db, ctry);
569 ret = XTALLOC1 (str_list_type);
570 *ret = str_list_init ();
572 /* For each filename found, see if it matches the path element. For
573 example, if we have .../cx/cmr10.300pk and .../ricoh/cmr10.300pk,
574 and the path looks like .../cx, we don't want the ricoh file. */
575 while (!done && db_dirs && *db_dirs) {
576 string db_file = concat (*db_dirs, ctry);
577 boolean matched = match (db_file, path_elt);
579 #ifdef KPSE_DEBUG
580 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
581 DEBUGF3 ("db:match(%s,%s) = %d\n", db_file, path_elt, matched);
582 #endif
584 /* We got a hit in the database. Now see if the file actually
585 exists, possibly under an alias. */
586 if (matched) {
587 string found = NULL;
588 if (kpathsea_readable_file (kpse, db_file)) {
589 found = db_file;
591 } else {
592 const_string *a;
594 free (db_file); /* `db_file' wasn't on disk. */
596 /* The hit in the DB doesn't exist in disk. Now try all its
597 aliases. For example, suppose we have a hierarchy on CD,
598 thus `mf.bas', but ls-R contains `mf.base'. Find it anyway.
599 Could probably work around this with aliases, but
600 this is pretty easy and shouldn't hurt. The upshot is that
601 if one of the aliases actually exists, we use that. */
602 for (a = aliases + 1; *a && !found; a++) {
603 string atry = concat (*db_dirs, *a);
604 if (kpathsea_readable_file (kpse, atry))
605 found = atry;
606 else
607 free (atry);
611 /* If we have a real file, add it to the list, maybe done. */
612 if (found) {
613 str_list_add (ret, found);
614 if (!all && found)
615 done = true;
617 } else { /* no match in the db */
618 free (db_file);
622 /* On to the next directory, if any. */
623 db_dirs++;
626 /* This is just the space for the pointers, not the strings. */
627 if (orig_dirs && *orig_dirs)
628 free (orig_dirs);
631 free ((void *) aliases);
633 /* If we had to break up NAME, free the TEMP_STR. */
634 if (temp_str)
635 free (temp_str);
637 return ret;
640 str_list_type *
641 kpathsea_db_search_list (kpathsea kpse, string* names,
642 const_string path_elt, boolean all)
644 const_string *db_dirs, *orig_dirs;
645 const_string last_slash, name, path;
646 string temp_str = NULL;
647 boolean done;
648 unsigned e;
649 const_string *aliases, *r;
650 int n;
651 str_list_type *ret = NULL;
652 boolean relevant = false;
654 /* If we failed to build the database (or if this is the recursive
655 call to build the db path), quit. */
656 if (kpse->db.buckets == NULL)
657 return NULL;
659 /* Don't bother doing any lookups if this `path_elt' isn't covered by
660 any of database directories. We do this not so much because the
661 extra couple of hash lookups matter -- they don't -- but rather
662 because we want to return NULL in this case, so path_search can
663 know to do a disk search. */
664 for (e = 0; !relevant && e < STR_LIST_LENGTH (kpse->db_dir_list); e++) {
665 relevant = elt_in_db (STR_LIST_ELT (kpse->db_dir_list, e), path_elt);
667 if (!relevant)
668 return NULL;
670 done = false;
671 ret = XTALLOC1 (str_list_type);
672 *ret = str_list_init ();
674 /* Handle each name. */
675 for (n = 0; !done && names[n]; n++) {
676 name = names[n];
678 /* Absolute names should have been caught in our caller. */
679 if (kpathsea_absolute_p(kpse, name, true))
680 continue;
682 /* When tex-glyph.c calls us looking for, e.g., dpi600/cmr10.pk, we
683 won't find it unless we change NAME to just `cmr10.pk' and append
684 `/dpi600' to PATH_ELT. We are justified in using a literal `/'
685 here, since that's what tex-glyph.c unconditionally uses in
686 DPI_BITMAP_SPEC. But don't do anything if the / begins NAME; that
687 should never happen. */
688 last_slash = strrchr (name, '/');
689 if (last_slash && last_slash != name) {
690 unsigned len = last_slash - name + 1;
691 string dir_part = (string)xmalloc (len);
692 strncpy (dir_part, name, len - 1);
693 dir_part[len - 1] = 0;
694 path = temp_str = concat3 (path_elt, "/", dir_part);
695 name = last_slash + 1;
696 free (dir_part);
697 } else {
698 path = path_elt;
701 /* If we have aliases for this name, use them. */
702 if (kpse->alias_db.buckets)
703 aliases = hash_lookup (kpse->alias_db, name);
704 else
705 aliases = NULL;
707 if (!aliases) {
708 aliases = XTALLOC1 (const_string);
709 aliases[0] = NULL;
711 { /* Push aliases up by one and insert the original name at front. */
712 unsigned i;
713 unsigned len = 1; /* Have NULL element already allocated. */
714 for (r = aliases; *r; r++)
715 len++;
716 aliases = (const_string *) xrealloc ((void *) aliases,
717 (len + 1) * sizeof(const_string));
718 for (i = len; i > 0; i--) {
719 aliases[i] = aliases[i - 1];
721 aliases[0] = name;
724 for (r = aliases; !done && *r; r++) {
725 const_string ctry = *r;
727 /* We have an ls-R db. Look up `try'. */
728 orig_dirs = db_dirs = hash_lookup (kpse->db, ctry);
730 /* For each filename found, see if it matches the path element. For
731 example, if we have .../cx/cmr10.300pk and .../ricoh/cmr10.300pk,
732 and the path looks like .../cx, we don't want the ricoh file. */
733 while (!done && db_dirs && *db_dirs) {
734 string db_file = concat (*db_dirs, ctry);
735 boolean matched = match (db_file, path);
737 #ifdef KPSE_DEBUG
738 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
739 DEBUGF3 ("db:match(%s,%s) = %d\n", db_file, path, matched);
740 #endif
742 /* We got a hit in the database. Now see if the file actually
743 exists, possibly under an alias. */
744 if (matched) {
745 string found = NULL;
746 if (kpathsea_readable_file (kpse, db_file)) {
747 found = db_file;
749 } else {
750 const_string *a;
752 free (db_file); /* `db_file' wasn't on disk. */
754 /* The hit in the DB doesn't exist in disk. Now try all its
755 aliases. For example, suppose we have a hierarchy on CD,
756 thus `mf.bas', but ls-R contains `mf.base'. Find it anyway.
757 Could probably work around this with aliases, but
758 this is pretty easy and shouldn't hurt. The upshot is that
759 if one of the aliases actually exists, we use that. */
760 for (a = aliases + 1; *a && !found; a++) {
761 string atry = concat (*db_dirs, *a);
762 if (kpathsea_readable_file (kpse, atry))
763 found = atry;
764 else
765 free (atry);
769 /* If we have a real file, add it to the list, maybe done. */
770 if (found) {
771 str_list_add (ret, found);
772 if (!all && found)
773 done = true;
775 } else { /* no match in the db */
776 free (db_file);
779 /* On to the next directory, if any. */
780 db_dirs++;
783 /* This is just the space for the pointers, not the strings. */
784 if (orig_dirs && *orig_dirs)
785 free (orig_dirs);
788 free ((void *) aliases);
789 if (temp_str)
790 free (temp_str);
793 return ret;