1 /* pathsearch.c: look up a filename in a path.
2
3 Copyright 1993, 1994, 1995, 1997, 2007, 2009-2012 Karl Berry.
4 Copyright 1997-2005 Olaf Weber.
5
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.
10
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.
15
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/>. */
18
19 #include <kpathsea/config.h>
20 #include <kpathsea/c-pathch.h>
21 #include <kpathsea/c-fopen.h>
22 #include <kpathsea/absolute.h>
23 #include <kpathsea/expand.h>
24 #include <kpathsea/db.h>
25 #include <kpathsea/pathsearch.h>
26 #include <kpathsea/readable.h>
27 #include <kpathsea/str-list.h>
28 #include <kpathsea/str-llist.h>
29 #include <kpathsea/variable.h>
30
31 #include <time.h> /* for `time' */
32
33 #ifdef __DJGPP__
34 #include <sys/stat.h> /* for stat bits */
35 #endif
36
37 #ifdef WIN32
38 #undef fputs
39 #undef puts
40 #define fputs win32_fputs
41 #define puts win32_puts
42 #endif
43
44 /* The very first search is for texmf.cnf, called when someone tries to
45 initialize the TFM path or whatever. init_path calls kpse_cnf_get
46 which calls kpse_all_path_search to find all the texmf.cnf's. We
47 need to do various special things in this case, since we obviously
48 don't yet have the configuration files when we're searching for the
49 configuration files. */
50
51
52
53 /* This function is called after every search (except the first, since
54 we definitely want to allow enabling the logging in texmf.cnf) to
55 record the filename(s) found in $TEXMFLOG. */
56
57 static void
log_search(kpathsea kpse,str_list_type filenames)58 log_search (kpathsea kpse, str_list_type filenames)
59 {
60
61 if (kpse->log_opened == false) {
62 /* Get name from either envvar or config file. */
63 string log_name = kpathsea_var_value (kpse, "TEXMFLOG");
64 kpse->log_opened = true;
65 if (log_name) {
66 kpse->log_file = fopen (log_name, FOPEN_A_MODE);
67 if (!kpse->log_file)
68 perror (log_name);
69 free (log_name);
70 }
71 }
72
73 if (
74 #ifdef KPSE_DEBUG
75 KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH) ||
76 #endif /* KPSE_DEBUG */
77 kpse->log_file) {
78 unsigned e;
79
80 /* FILENAMES should never be null, but safety doesn't hurt. */
81 for (e = 0; e < STR_LIST_LENGTH (filenames) && STR_LIST_ELT (filenames, e);
82 e++) {
83 string filename = STR_LIST_ELT (filenames, e);
84
85 /* Only record absolute filenames, for privacy. */
86 if (kpse->log_file && kpathsea_absolute_p (kpse, filename, false))
87 fprintf (kpse->log_file, "%lu %s\n", (long unsigned) time (NULL),
88 filename);
89
90 #ifdef KPSE_DEBUG
91 /* And show them online, if debugging. We've already started
92 the debugging line in `search', where this is called, so
93 just print the filename here, don't use DEBUGF. */
94 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
95 putc (' ', stderr);
96 fputs (filename, stderr);
97 }
98 #endif /* KPSE_DEBUG */
99 }
100 }
101 }
102
103 /* Concatenate each element in DIRS with NAME (assume each ends with a
104 /, to save time). If SEARCH_ALL is false, return the first readable
105 regular file. Else continue to search for more. In any case, if
106 none, return a list containing just NULL.
107
108 We keep a single buffer for the potential filenames and reallocate
109 only when necessary. I'm not sure it's noticeably faster, but it
110 does seem cleaner. (We do waste a bit of space in the return
111 value, though, since we don't shrink it to the final size returned.) */
112
113 #define INIT_ALLOC 75 /* Doesn't much matter what this number is. */
114
115 static str_list_type
dir_list_search(kpathsea kpse,str_llist_type * dirs,const_string name,boolean search_all)116 dir_list_search (kpathsea kpse, str_llist_type *dirs, const_string name,
117 boolean search_all)
118 {
119 str_llist_elt_type *elt;
120 str_list_type ret;
121 unsigned name_len = strlen (name);
122 unsigned allocated = INIT_ALLOC;
123 string potential = (string)xmalloc (allocated);
124
125 ret = str_list_init ();
126
127 for (elt = *dirs; elt; elt = STR_LLIST_NEXT (*elt))
128 {
129 const_string dir = STR_LLIST (*elt);
130 unsigned dir_len = strlen (dir);
131
132 while (dir_len + name_len + 1 > allocated)
133 {
134 allocated += allocated;
135 XRETALLOC (potential, allocated, char);
136 }
137
138 strcpy (potential, dir);
139 strcat (potential, name);
140
141 if (kpathsea_readable_file (kpse, potential))
142 {
143 str_list_add (&ret, potential);
144
145 /* Move this element towards the top of the list. */
146 str_llist_float (dirs, elt);
147
148 /* If caller only wanted one file returned, no need to
149 terminate the list with NULL; the caller knows to only look
150 at the first element. */
151 if (!search_all)
152 return ret;
153
154 /* Start new filename. */
155 allocated = INIT_ALLOC;
156 potential = (string)xmalloc (allocated);
157 }
158 }
159
160 /* If we get here, either we didn't find any files, or we were finding
161 all the files. But we're done with the last filename, anyway. */
162 free (potential);
163
164 return ret;
165 }
166
167 /* Note: NAMES[i] is not modified. */
168 static str_list_type
dir_list_search_list(kpathsea kpse,str_llist_type * dirs,string * names,boolean search_all)169 dir_list_search_list (kpathsea kpse, str_llist_type *dirs, string* names,
170 boolean search_all)
171 {
172 str_llist_elt_type *elt;
173 str_list_type ret;
174 unsigned allocated = INIT_ALLOC;
175 string potential = XTALLOC(allocated, char);
176
177 ret = str_list_init ();
178
179 for (elt = *dirs; elt; elt = STR_LLIST_NEXT(*elt)) {
180 const_string dir = STR_LLIST (*elt);
181 unsigned dir_len = strlen (dir);
182 int i;
183
184 for (i = 0; names[i]; i++) {
185 const_string name = names[i];
186 unsigned name_len;
187
188 /* Don't bother with absolute & explicit relative. */
189 if (kpathsea_absolute_p(kpse, name, true))
190 continue;
191
192 name_len = strlen(name);
193
194 while (dir_len + name_len + 1 > allocated) {
195 allocated += allocated;
196 XRETALLOC (potential, allocated, char);
197 }
198
199 strcpy (potential, dir);
200 strcat (potential+dir_len, name);
201
202 if (kpathsea_readable_file (kpse, potential)) {
203 str_list_add (&ret, potential);
204
205 /* Move this element towards the top of the list. */
206 str_llist_float (dirs, elt);
207
208 /* If caller only wanted one file returned, no need to
209 terminate the list with NULL; the caller knows to only look
210 at the first element. */
211 if (!search_all)
212 return ret;
213
214 /* Start new filename. */
215 allocated = INIT_ALLOC;
216 potential = XTALLOC(allocated, char);
217 }
218 }
219 }
220
221 /* If we get here, either we didn't find any files, or we were finding
222 all the files. But we're done with the last filename, anyway. */
223 free (potential);
224
225 return ret;
226 }
227
228 /* This is called when NAME is absolute or explicitly relative; if it's
229 readable, return (a list containing) it; otherwise, return NULL. */
230
231 static str_list_type
absolute_search(kpathsea kpse,string name)232 absolute_search (kpathsea kpse, string name)
233 {
234 str_list_type ret_list;
235 string found = kpathsea_readable_file (kpse, name);
236
237 /* Some old compilers can't initialize structs. */
238 ret_list = str_list_init ();
239
240 /* If NAME wasn't found, free the expansion. */
241 if (name != found)
242 free (name);
243
244 /* Add `found' to the return list even if it's null; that tells
245 the caller we didn't find anything. */
246 str_list_add (&ret_list, found);
247
248 return ret_list;
249 }
250
251 /* This is the hard case -- look for NAME in PATH. If ALL is false,
252 return the first file found. Otherwise, search all elements of PATH. */
253
254 static str_list_type
path_search(kpathsea kpse,const_string path,string name,boolean must_exist,boolean all)255 path_search (kpathsea kpse, const_string path, string name,
256 boolean must_exist, boolean all)
257 {
258 string elt;
259 str_list_type ret_list;
260 boolean done = false;
261 ret_list = str_list_init (); /* some compilers lack struct initialization */
262
263 for (elt = kpathsea_path_element (kpse, path); !done && elt;
264 elt = kpathsea_path_element (kpse, NULL)) {
265 str_list_type *found;
266 boolean allow_disk_search = true;
267
268 if (*elt == '!' && *(elt + 1) == '!') {
269 /* Those magic leading chars in a path element means don't search the
270 disk for this elt. And move past the magic to get to the name. */
271 allow_disk_search = false;
272 elt += 2;
273 }
274
275 /* See elt-dirs.c for side effects of this function */
276 kpathsea_normalize_path(kpse, elt);
277
278 /* Try ls-R, unless we're searching for texmf.cnf. Our caller
279 (search), also tests first_search, and does the resetting. */
280 found = kpse->followup_search ? kpathsea_db_search (kpse, name, elt, all)
281 : NULL;
282
283 /* Search the filesystem if (1) the path spec allows it, and either
284 (2a) we are searching for texmf.cnf ; or
285 (2b) no db exists; or
286 (2c) no db's are relevant to this elt; or
287 (3) MUST_EXIST && NAME was not in the db.
288 In (2*), `found' will be NULL.
289 In (3), `found' will be an empty list. */
290 if (allow_disk_search && (!found || (must_exist && !STR_LIST (*found)))) {
291 str_llist_type *dirs = kpathsea_element_dirs (kpse, elt);
292 if (dirs && *dirs) {
293 if (!found)
294 found = XTALLOC1 (str_list_type);
295 *found = dir_list_search (kpse, dirs, name, all);
296 }
297 }
298
299 /* Did we find anything anywhere? */
300 if (found && STR_LIST (*found)) {
301 if (all)
302 str_list_concat (&ret_list, *found);
303 else {
304 str_list_add (&ret_list, STR_LIST_ELT (*found, 0));
305 done = true;
306 }
307 }
308
309 /* Free the list space, if any (but not the elements). */
310 if (found) {
311 str_list_free (found);
312 free (found);
313 }
314 }
315
316 /* Free the expanded name we were passed. It can't be in the return
317 list, since the path directories got unconditionally prepended. */
318 free (name);
319
320 return ret_list;
321 }
322
323 /* Search PATH for ORIGINAL_NAME. If ALL is false, or ORIGINAL_NAME is
324 absolute_p, check ORIGINAL_NAME itself. Otherwise, look at each
325 element of PATH for the first readable ORIGINAL_NAME.
326
327 Always return a list; if no files are found, the list will
328 contain just NULL. If ALL is true, the list will be
329 terminated with NULL. */
330
331 static string *
search(kpathsea kpse,const_string path,const_string original_name,boolean must_exist,boolean all)332 search (kpathsea kpse, const_string path, const_string original_name,
333 boolean must_exist, boolean all)
334 {
335 str_list_type ret_list;
336 string name;
337 boolean absolute_p;
338
339 #ifdef __DJGPP__
340 /* We will use `stat' heavily, so let's request for
341 the fastest possible version of `stat', by telling
342 it what members of struct stat do we really need.
343
344 We need to set this on each call because this is a
345 library function; the caller might need other options
346 from `stat'. Thus save the flags and restore them
347 before exit.
348
349 This call tells `stat' that we do NOT need to recognize
350 executable files (neither by an extension nor by a magic
351 signature); that we do NOT need time stamp of root directories;
352 and that we do NOT need the write access bit in st_mode.
353
354 Note that `kpse_set_program_name' needs the EXEC bits,
355 but it was already called by the time we get here. */
356 unsigned short save_djgpp_flags = _djstat_flags;
357
358 _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT
359 | _STAT_ROOT_TIME | _STAT_WRITEBIT;
360 #endif
361
362 /* Make a leading ~ count as an absolute filename, and expand $FOO's. */
363 name = kpathsea_expand (kpse, original_name);
364
365 /* If the first name is absolute or explicitly relative, no need to
366 consider PATH at all. */
367 absolute_p = kpathsea_absolute_p (kpse, name, true);
368
369 #ifdef KPSE_DEBUG
370 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
371 DEBUGF4 ("start search(file=%s, must_exist=%d, find_all=%d, path=%s).\n",
372 name, must_exist, all, path);
373 #endif /* KPSE_DEBUG */
374
375 /* Find the file(s). */
376 ret_list = absolute_p ? absolute_search (kpse, name)
377 : path_search (kpse, path, name, must_exist, all);
378
379 /* Append NULL terminator if we didn't find anything at all, or we're
380 supposed to find ALL and the list doesn't end in NULL now. */
381 if (STR_LIST_LENGTH (ret_list) == 0
382 || (all && STR_LIST_LAST_ELT (ret_list) != NULL))
383 str_list_add (&ret_list, NULL);
384
385 /* The very first search is for texmf.cnf. We can't log that, since
386 we want to allow setting TEXMFLOG in texmf.cnf. */
387 if (kpse->followup_search == false) {
388 kpse->followup_search = true;
389 } else {
390 /* Record the filenames we found, if desired. And wrap them in a
391 debugging line if we're doing that. */
392 #ifdef KPSE_DEBUG
393 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
394 DEBUGF1 ("search(%s) =>", original_name);
395 #endif /* KPSE_DEBUG */
396 log_search (kpse, ret_list);
397 #ifdef KPSE_DEBUG
398 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
399 putc ('\n', stderr);
400 #endif /* KPSE_DEBUG */
401 }
402
403 #ifdef __DJGPP__
404 /* Undo any side effects. */
405 _djstat_flags = save_djgpp_flags;
406 #endif
407
408 return STR_LIST (ret_list);
409 }
410
411 /* Search PATH for NAMES.
412
413 Always return a list; if no files are found, the list will
414 contain just NULL. If ALL is true, the list will be
415 terminated with NULL. */
416
417 string *
kpathsea_path_search_list_generic(kpathsea kpse,const_string path,string * names,boolean must_exist,boolean all)418 kpathsea_path_search_list_generic (kpathsea kpse,
419 const_string path, string* names,
420 boolean must_exist, boolean all)
421 {
422 str_list_type ret_list;
423 string* namep;
424 string elt;
425 boolean done = false;
426 boolean all_absolute = true;
427
428 #ifdef __DJGPP__
429 /* We will use `stat' heavily, so let's request for
430 the fastest possible version of `stat', by telling
431 it what members of struct stat do we really need.
432
433 We need to set this on each call because this is a
434 library function; the caller might need other options
435 from `stat'. Thus save the flags and restore them
436 before exit.
437
438 This call tells `stat' that we do NOT need to recognize
439 executable files (neither by an extension nor by a magic
440 signature); that we do NOT need time stamp of root directories;
441 and that we do NOT need the write access bit in st_mode.
442
443 Note that `kpse_set_program_name' needs the EXEC bits,
444 but it was already called by the time we get here. */
445 unsigned short save_djgpp_flags = _djstat_flags;
446
447 _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT
448 | _STAT_ROOT_TIME | _STAT_WRITEBIT;
449 #endif
450
451 ret_list = str_list_init();
452
453 #ifdef KPSE_DEBUG
454 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
455 DEBUGF1 ("start search(files=[%s", *names);
456 for (namep = names+1; *namep != NULL; namep++) {
457 fputc(' ', stderr);
458 fputs(*namep, stderr);
459 }
460 fprintf (stderr, "], must_exist=%d, find_all=%d, path=%s).\n",
461 must_exist, all, path);
462 }
463 #endif /* KPSE_DEBUG */
464
465 /* FIXME: is this really true? No need to do any expansion on names. */
466
467 /* First catch any absolute or explicit relative names. */
468 for (namep = names; *namep; namep++) {
469 if (kpathsea_absolute_p (kpse, *namep, true)) {
470 if (kpathsea_readable_file (kpse, *namep)) {
471 str_list_add (&ret_list, xstrdup(*namep));
472 if (!all)
473 goto out;
474 }
475 } else {
476 all_absolute = false;
477 }
478 }
479 /* Shortcut: if we were only given absolute/explicit relative names,
480 we can skip the rest. Typically, if one name is absolute, they
481 all are, because our caller derived them from each other. */
482 if (all_absolute)
483 goto out;
484
485 /* Look at each path element in turn. */
486 for (elt = kpathsea_path_element (kpse, path); !done && elt;
487 elt = kpathsea_path_element (kpse, NULL))
488 {
489 str_list_type *found;
490 boolean allow_disk_search = true;
491 if (elt[0] == '!' && elt[1] == '!') {
492 /* !! magic -> disallow disk searches. */
493 allow_disk_search = false;
494 elt += 2;
495 }
496
497 /* See elt-dirs.c for side effects of this function. */
498 kpathsea_normalize_path (kpse, elt);
499
500 /* Try ls-R, unless we're searching for texmf.cnf. */
501 found = kpse->followup_search
502 ? kpathsea_db_search_list (kpse, names, elt, all) : NULL;
503
504 /* Search the filesystem if (1) the path spec allows it, and either
505 (2a) we are searching for texmf.cnf ; or
506 (2b) no db exists; or
507 (2c) no db's are relevant to this elt; or
508 (3) MUST_EXIST && NAME was not in the db.
509 In (2*), `found' will be NULL.
510 In (3), `found' will be an empty list. */
511 if (allow_disk_search && (!found || (must_exist && !STR_LIST(*found)))) {
512 str_llist_type *dirs = kpathsea_element_dirs (kpse, elt);
513 if (dirs && *dirs) {
514 if (!found)
515 found = XTALLOC1 (str_list_type);
516 *found = dir_list_search_list (kpse, dirs, names, all);
517 }
518 }
519
520 /* Did we find anything? */
521 if (found && STR_LIST (*found)) {
522 if (all) {
523 str_list_concat (&ret_list, *found);
524 } else {
525 str_list_add (&ret_list, STR_LIST_ELT (*found, 0));
526 done = true;
527 }
528 }
529 }
530
531 out:
532 /* Uniqify, since our paths can often end up finding the same file
533 more than once. */
534 str_list_uniqify (&ret_list);
535
536 /* Add NULL if we will be returning multiple elements. */
537 if (STR_LIST_LENGTH (ret_list) == 0
538 || (all && STR_LIST_LAST_ELT (ret_list) != NULL))
539 str_list_add (&ret_list, NULL);
540
541 if (kpse->followup_search == false) {
542 kpse->followup_search = true;
543 } else {
544 /* Record the filenames we found, if desired. And wrap them in a
545 debugging line if we're doing that. */
546 #ifdef KPSE_DEBUG
547 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) {
548 DEBUGF1 ("search([%s", *names);
549 for (namep = names+1; *namep != NULL; namep++) {
550 fputc (' ', stderr);
551 fputs (*namep, stderr);
552 }
553 fputs ("]) =>", stderr);
554 }
555 #endif /* KPSE_DEBUG */
556 log_search (kpse, ret_list);
557 #ifdef KPSE_DEBUG
558 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH))
559 putc ('\n', stderr);
560 #endif /* KPSE_DEBUG */
561 }
562
563 #ifdef __DJGPP__
564 /* Undo any side effects. */
565 _djstat_flags = save_djgpp_flags;
566 #endif
567
568 return STR_LIST (ret_list);
569 }
570
571 /* Search PATH for the first NAME according to MUST_EXIST. */
572
573 string
kpathsea_path_search(kpathsea kpse,const_string path,const_string name,boolean must_exist)574 kpathsea_path_search (kpathsea kpse, const_string path, const_string name,
575 boolean must_exist)
576 {
577 string *ret_list = search (kpse, path, name, must_exist, false);
578 string ret = *ret_list;
579 free (ret_list);
580 return ret;
581 }
582
583 /* Search PATH for all files named NAME. Might have been better not
584 to assert `must_exist' here, but it's too late to change. */
585
586 string *
kpathsea_all_path_search(kpathsea kpse,const_string path,const_string name)587 kpathsea_all_path_search (kpathsea kpse, const_string path, const_string name)
588 {
589 string *ret = search (kpse, path, name, true, true);
590 return ret;
591 }
592
593 #if defined (KPSE_COMPAT_API)
594
595 string
kpse_path_search(const_string path,const_string name,boolean must_exist)596 kpse_path_search (const_string path, const_string name, boolean must_exist)
597 {
598 return kpathsea_path_search (kpse_def, path, name, must_exist);
599 }
600
601 string *
kpse_all_path_search(const_string path,const_string name)602 kpse_all_path_search (const_string path, const_string name)
603 {
604 return kpathsea_all_path_search (kpse_def, path, name);
605 }
606 #endif
607
608
609 #ifdef TEST
610
611 void
test_path_search(const_string path,const_string file)612 test_path_search (const_string path, const_string file)
613 {
614 string answer;
615 string *answer_list;
616
617 printf ("\nSearch %s for %s:\t", path, file);
618 answer = kpse_path_search (path, file, 0);
619 puts (answer ? answer : "(nil)");
620
621 printf ("Search %s for all %s:\t", path, file);
622 answer_list = kpse_all_path_search (path, file);
623 putchar ('\n');
624 while (*answer_list)
625 {
626 putchar ('\t');
627 puts (*answer_list);
628 answer_list++;
629 }
630 }
631
632 #define TEXFONTS "/usr/local/lib/tex/fonts"
633
634 int
main(int argc,char ** argv)635 main (int argc, char **argv)
636 {
637 kpse_set_program_name(argv[0], NULL);
638 /* All lists end with NULL. */
639 test_path_search (".", "nonexistent");
640 test_path_search (".", "/nonexistent");
641 test_path_search ("/k" ENV_SEP_STRING ".", "kpathsea.texi");
642 test_path_search ("/k" ENV_SEP_STRING ".", "/etc/fstab");
643 test_path_search ("." ENV_SEP_STRING TEXFONTS "//", "cmr10.tfm");
644 test_path_search ("." ENV_SEP_STRING TEXFONTS "//", "logo10.tfm");
645 test_path_search (TEXFONTS "//times" ENV_SEP_STRING "."
646 ENV_SEP_STRING ENV_SEP_STRING, "ptmr.vf");
647 test_path_search (TEXFONTS "/adobe//" ENV_SEP_STRING
648 "/usr/local/src/TeX+MF/typefaces//", "plcr.pfa");
649
650 test_path_search ("~karl", ".bashrc");
651 test_path_search ("/k", "~karl/.bashrc");
652
653 xputenv ("NONEXIST", "nonexistent");
654 test_path_search (".", "$NONEXISTENT");
655 xputenv ("KPATHSEA", "kpathsea");
656 test_path_search ("/k" ENV_SEP_STRING ".", "$KPATHSEA.texi");
657 test_path_search ("/k" ENV_SEP_STRING ".", "${KPATHSEA}.texi");
658 test_path_search ("$KPATHSEA" ENV_SEP_STRING ".", "README");
659 test_path_search ("." ENV_SEP_STRING "$KPATHSEA", "README");
660
661 return 0;
662 }
663
664 #endif /* TEST */
665
666
667 /*
668 Local variables:
669 standalone-compile-command: "gcc -posix -g -I. -I.. -DTEST pathsearch.c kpathsea.a"
670 End:
671 */
672