w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

pathsearch.c
Go to the documentation of this file.
1 /* pathsearch.c: look up a filename in a path.
2 
3  Copyright 1993, 1994, 1995, 1997, 2007, 2009-2012, 2018, 2020 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 #include <kpathsea/xopendir.h>
31 
32 #include <time.h> /* for `time' */
33 
34 #ifdef __DJGPP__
35 #include <sys/stat.h> /* for stat bits */
36 #endif
37 
38 #ifdef WIN32
39 #undef fputs
40 #undef puts
41 #define fputs win32_fputs
42 #define puts win32_puts
43 #endif
44 
45 /* The very first search is for texmf.cnf, called when someone tries to
46  initialize the TFM path or whatever. init_path calls kpse_cnf_get
47  which calls kpse_all_path_search to find all the texmf.cnf's. We
48  need to do various special things in this case, since we obviously
49  don't yet have the configuration files when we're searching for the
50  configuration files. Therefore we have a followup_search member in
51  kpathsea_instance to distinguish the first search from all others. */
52 
53 
54 ␌
55 #ifdef KPSE_DEBUG
56 /* Print on FH elements of L surrounded by brackets, separated by spaces. */
57 
58 static void
59 print_space_list (FILE *fh, string *l)
60 {
61  fputs ("[", fh);
62  while (l && *l) {
63  fputs (*l, fh);
64  l++;
65  if (*l)
66  fputs (" ", fh);
67  }
68  fputs ("]", fh);
69 }
70 #endif /* KPSE_DEBUG */
71 ␌
72 /* This function is called after every search (except the first, since
73  we definitely want to allow enabling the logging in texmf.cnf) to
74  record the filename(s) found in $TEXMFLOG. */
75 
76 static void
78 {
79  if (kpse->log_opened == false) {
80  /* Get name from either envvar or config file. Thus, the first time
81  is called, for the first search, we will be opening texmf.cnf
82  and ls-R just to resolve the variable. */
83  string log_name = kpathsea_var_value (kpse, "TEXMFLOG");
84  kpse->log_opened = true;
85  if (log_name) {
87  if (!kpse->log_file)
88  perror (log_name);
89  free (log_name);
90  }
91  }
92 
93  if (
94 #ifdef KPSE_DEBUG
96 #endif /* KPSE_DEBUG */
97  kpse->log_file) {
98  unsigned e;
99 
100  /* FILENAMES should never be null, but safety doesn't hurt. */
101  for (e = 0; e < STR_LIST_LENGTH (filenames) && STR_LIST_ELT (filenames, e);
102  e++) {
103  string filename = STR_LIST_ELT (filenames, e);
104 
105  /* Only record absolute filenames, for privacy. */
106  if (kpse->log_file && kpathsea_absolute_p (kpse, filename, false)) {
107  fprintf (kpse->log_file, "%lu %s\n", (long unsigned) time (NULL),
108  filename);
109  }
110 
111 #ifdef KPSE_DEBUG
112  /* And show them online, if debugging. We've already started the
113  debugging line in `search' and
114  `kpathsea_path_search_list_generic', where this is called, so
115  just print the filename here, don't use DEBUGF. */
117  putc (' ', stderr);
118  fputs (filename, stderr);
119  }
120 #endif /* KPSE_DEBUG */
121  }
122  }
123 }
124 ␌
125 /* Either casefold_readable_file or kpathsea_readable_file. We need the
126  type even if we don't have casefolding enabled at compile-time. */
128 
129 #ifdef MONOCASE_FILENAMES
130 /* Don't do any of this fallback casefolding stuff on Windows. */
131 #undef KPSE_CASEFOLDING_SEARCH
132 #else
133 #define KPSE_CASEFOLDING_SEARCH 1
134 #endif
135 
136 #ifdef KPSE_CASEFOLDING_SEARCH
137 
138 /* Same as kpathsea_readable_file (readable.c), but check
139  case-insensitively on the last file name component. We return the
140  first match (in new memory), or NULL. In practice this is always
141  called after checking the filename as-is, so there's no use in
142  continuing to look for an exact match. The KPSE arg is only passed
143  to kpathsea_readable_file if we have a candidate match.
144 
145  Clearly we could do some caching here, but let's see if it's actually
146  necessary, given all the other levels of caching (disk, memory, cpu)
147  that are going on these days. */
148 
149 static string
151 {
152  string ret = NULL;
153  const_string this_base_name = xbasename (name);
154  string this_dir_name = xdirname (name);
155  DIR *thisdir = opendir (this_dir_name);
156 
157 #ifdef KPSE_DEBUG
159  DEBUGF2 (" casefold_readable_file(%s) in %s => ",
160  this_base_name, this_dir_name);
161  }
162 #endif
163 
164  /* We can be called with a name like `subdir/somefile', where subdir/
165  does not exist. So the opendir might fail, and that's ok. */
166  if (thisdir) {
167  struct dirent *e;
168 
169  while ((e = readdir (thisdir)) != NULL) {
170  /* The standard strcasecmp seems like enough for the comparison? */
171  if (strcasecmp (e->d_name, this_base_name) == 0) {
172  ret = concat3 (this_dir_name, DIR_SEP_STRING, e->d_name);
174  break; /* success */
175  } else {
176  /* This only happens when the name matches, but the potential file is
177  not actually readable, e.g., a broken symlink. It seems
178  sufficiently unusual to be worth logging. */
179  #ifdef KPSE_DEBUG
181  fprintf (stderr, "{casefolded candidate %s not readable, continuing}",ret);
182  }
183  #endif
184  free (ret); /* not readable, keep looking */
185  ret = NULL;
186  }
187  }
188  } /* end of readdir loop */
189  xclosedir (thisdir);
190  }
191  free (this_dir_name);
192 
194  fputs (ret ? ret : "(nil)", stderr);
195  fputc ('\n', stderr);
196  }
197  return ret;
198 }
199 #endif /* KPSE_CASEFOLDING_SEARCH */
200 ␌
201 /* Return a str_list of matches in DIRS of NAME.
202 
203  Concatenate each element in DIRS with NAME, assuming each ends with /.
204  If SEARCH_ALL is false, return a list containing just the first
205  readable (according to the READABLE_FILE_P function) regular file.
206  Else continue to search and return them all. In any case, if none,
207  return a list containing just NULL.
208 
209  DIRS is modified only in that the directory where a search matches is
210  floated toward the top of the list.
211 
212  We keep a single buffer for the potential filenames and reallocate
213  only when necessary. I'm not sure it's noticeably faster, but it
214  does seem cleaner. (We do waste a bit of space in the return
215  value, since we don't shrink it to the final size returned.) */
216 
217 #define INIT_ALLOC 75 /* Doesn't much matter what this number is. */
218 
219 static str_list_type
221  boolean search_all, readable_file_fn_type readable_file_p)
222 {
223  str_llist_elt_type *elt;
224  str_llist_elt_type *next_elt;
226  unsigned name_len = strlen (name);
227  unsigned allocated = INIT_ALLOC;
228  string potential = (string) xmalloc (allocated);
229 
230 #ifdef KPSE_DEBUG
232  const_string casefold =
233 #ifdef KPSE_CASEFOLDING_SEARCH
234  (readable_file_p == casefold_readable_file) ? "yes" : "no";
235 #else
236  "No";
237 #endif
238  DEBUGF3 (" dir_list_search(file=%s, find_all=%d, casefold=%s)\n",
239  name, search_all, casefold);
240  }
241 #endif
242 
243  ret = str_list_init ();
244 
245  for (elt = *dirs; elt; elt = next_elt) {
246  string readable_name;
247  const_string dir = STR_LLIST (*elt);
248  unsigned dir_len = strlen (dir);
249 
250  next_elt = STR_LLIST_NEXT (*elt); /* in case elt floats */
251 
252  while (dir_len + name_len + 1 > allocated) {
253  allocated += allocated;
254  XRETALLOC (potential, allocated, char);
255  }
256  strcpy (potential, dir);
257  strcat (potential, name);
258 
259  readable_name = readable_file_p (kpse, potential);
260  if (readable_name) {
261  str_list_add (&ret, readable_name);
262 
263  /* Move this element towards the top of the list. */
264  str_llist_float (dirs, elt);
265 
266  /* If caller only wanted one file returned, no need to
267  terminate the list with NULL; the caller knows to only look
268  at the first element. */
269  if (!search_all)
270  return ret;
271 
272  /* Start new filename. */
273  allocated = INIT_ALLOC;
274  potential = (string) xmalloc (allocated);
275  }
276  }
277 
278  /* If we get here, either we didn't find any files, or we were finding
279  all the files. But we're done with the last filename, anyway. */
280  free (potential);
281 
282  return ret;
283 }
284 ␌
285 /* This is analogous to dir_list_search above, except we search for
286  multiple NAMES instead of one (unfortunately the code is duplicated).
287  Absolute or explicitly relative items in NAMES are ignored; the
288  caller (kpathsea_path_search_list_generic) deals with those
289  separately. NAMES[i] is not modified. */
290 
291 
292 static str_list_type
294  boolean search_all, readable_file_fn_type readable_file_p)
295 {
296  str_llist_elt_type *elt;
297  str_llist_elt_type *next_elt;
299  unsigned allocated = INIT_ALLOC;
300  string potential = XTALLOC (allocated, char);
301 
302 #ifdef KPSE_DEBUG
304  const_string casefold =
305 #ifdef KPSE_CASEFOLDING_SEARCH
306  (readable_file_p == casefold_readable_file) ? "yes" : "no";
307 #else
308  "No";
309 #endif
310  DEBUGF (" dir_list_search_list(files=");
311  print_space_list (stderr, names);
312  fprintf (stderr, ", find_all=%d, casefold=%s)\n", search_all, casefold);
313  }
314 #endif
315 
316  ret = str_list_init ();
317 
318  for (elt = *dirs; elt; elt = next_elt) {
319  int i;
320  string readable_name;
321  const_string dir = STR_LLIST (*elt);
322  unsigned dir_len = strlen (dir);
323 
324  next_elt = STR_LLIST_NEXT (*elt); /* in case elt floats */
325 
326  for (i = 0; names[i]; i++) {
328  unsigned name_len;
329 
330  /* Don't bother with absolute & explicit relative. */
331  if (kpathsea_absolute_p (kpse, name, true))
332  continue;
333 
334  name_len = strlen (name);
335 
336  while (dir_len + name_len + 1 > allocated) {
337  allocated += allocated;
338  XRETALLOC (potential, allocated, char);
339  }
340 
341  strcpy (potential, dir);
342  strcat (potential + dir_len, name);
343  readable_name = readable_file_p (kpse, potential);
344  if (readable_name) {
345  str_list_add (&ret, readable_name);
346 
347  /* Move this element towards the top of the list. */
348  str_llist_float (dirs, elt);
349 
350  /* If caller only wanted one file returned, no need to
351  terminate the list with NULL; the caller knows to only look
352  at the first element. */
353  if (!search_all)
354  return ret;
355 
356  /* Start new filename. */
357  allocated = INIT_ALLOC;
358  potential = XTALLOC (allocated, char);
359  }
360  }
361  }
362 
363  /* If we get here, either we didn't find any files, or we were finding
364  all the files. But we're done with the last filename, anyway. */
365  free (potential);
366 
367  return ret;
368 }
369 ␌
370 /* This is called when NAME is absolute or explicitly relative; if it's
371  readable, return a one-element str_list containing it (in new
372  memory); otherwise, return an empty list. (We return a list so as to
373  have the same return value as the path_search function.) We also
374  check case-insensitively if enabled and needed. */
375 
376 static str_list_type
378 {
379  str_list_type ret_list;
380  string found;
381 
382  /* Some old compilers can't initialize structs. */
383  ret_list = str_list_init ();
384 
385  /* Do the first check. */
387 #ifdef KPSE_DEBUG
389  DEBUGF2 (" absolute_search(%s) => %s\n", name, found ? found : "(nil)");
390  }
391 #endif
392  if (found) {
393  found = xstrdup (found); /* Return new memory. */
394  }
395 
396 #ifdef KPSE_CASEFOLDING_SEARCH
397  /* Do the casefolding search only if both needed and enabled. */
398  if (!found) {
399  if (KPSE_CNF_P (kpathsea_var_value (kpse, "texmf_casefold_search"))) {
401 #ifdef KPSE_DEBUG
403  DEBUGF2 (" casefold search(%s) => %s\n",name,found ? found : "(nil)");
404  }
405 #endif /* KPSE_DEBUG */
406  }
407  }
408 #endif /* KPSE_CASEFOLDING_SEARCH */
409 
410  if (found) {
411  /* If we didn't find anything, we'll return an empty list. */
412  str_list_add (&ret_list, found);
413  }
414 
415  return ret_list;
416 }
417 ␌
418 /* This is the hard case -- look for NAME in PATH. If ALL is false,
419  return the first file found. Otherwise, search all elements of PATH.
420  We also check case-insensitively if needed and requested. */
421 
422 static str_list_type
424  boolean must_exist, boolean all)
425 {
426  string elt;
427  str_list_type ret_list;
428  boolean done = false;
429  ret_list = str_list_init (); /* some compilers lack struct initialization */
430 
431 #ifdef KPSE_DEBUG
433  DEBUGF4 (" path_search(file=%s, must_exist=%d, find_all=%d, path=%s)\n",
434  name, all, must_exist, path);
435  }
436 #endif
437 
438  for (elt = kpathsea_path_element (kpse, path); !done && elt;
439  elt = kpathsea_path_element (kpse, NULL)) {
441  boolean allow_disk_search = true;
442 
443  if (*elt == '!' && *(elt + 1) == '!') {
444  /* Those magic leading chars in a path element means don't search the
445  disk for this elt. And move past the magic to get to the name. */
446  allow_disk_search = false;
447  elt += 2;
448  }
449 
450  /* See elt-dirs.c for side effects of this function. */
452 
453  /* Try ls-R, unless we're searching for texmf.cnf. Our caller
454  (search), also tests followup_search, and does the resetting. */
456  : NULL;
457 
458  /* Search the filesystem if (1) the path spec allows it, and either
459  (2a) we are searching for texmf.cnf; or
460  (2b) no db exists; or
461  (2c) no db's are relevant to this elt; or
462  (3) MUST_EXIST && NAME was not in the db.
463  In (2*), `found' will be NULL.
464  In (3), `found' will be an empty list. */
465  if (allow_disk_search
466  && (!found || (must_exist && !STR_LIST (*found)))) {
467  /* Determine the directories in which to search: */
469  if (dirs && *dirs) {
470  if (!found) {
472  }
473  /* Search in the directories: */
474  *found = dir_list_search (kpse, dirs, name, all,
476 #ifdef KPSE_CASEFOLDING_SEARCH
477  if (!STR_LIST (*found)
479  "texmf_casefold_search"))) {
480  /* Nothing found; search again, case-insensitively: */
481  *found = dir_list_search (kpse, dirs, name, all,
483  }
484 #endif /* KPSE_CASEFOLDING_SEARCH */
485  }
486  }
487 
488  /* Did we find anything? */
489  if (found && STR_LIST (*found)) {
490  if (all) {
491  str_list_concat (&ret_list, *found);
492  } else {
493  str_list_add (&ret_list, STR_LIST_FIRST_ELT (*found));
494  done = true;
495  }
496  }
497 
498  /* Free the list space, if any (but not the elements). */
499  if (found) {
501  free (found);
502  }
503  }
504 
505  return ret_list;
506 }
507 ␌
508 /* Search PATH for ORIGINAL_NAME. If ALL is false, or ORIGINAL_NAME is
509  absolute_p, check ORIGINAL_NAME itself. Otherwise, look at each
510  element of PATH for the first readable ORIGINAL_NAME.
511 
512  Always return a list; if no files are found, the list will
513  contain just NULL. If ALL is true, the list will be
514  terminated with NULL.
515 
516  This function is a special case of kpathsea_path_search_list_generic
517  below (which takes a list of names, instead of a single name, to
518  search for), and so should be rewritten to call it. But this
519  function came first, and life is short, so the code duplication
520  is here. Sorry. Please fix. */
521 
522 static string *
524  boolean must_exist, boolean all)
525 {
526  str_list_type ret_list;
527  string name;
528  boolean absolute_p;
529 #ifdef __DJGPP__
530  /* We will use `stat' heavily, so let's request for
531  the fastest possible version of `stat', by telling
532  it what members of struct stat do we really need.
533 
534  We need to set this on each call because this is a
535  library function; the caller might need other options
536  from `stat'. Thus save the flags and restore them
537  before exit.
538 
539  This call tells `stat' that we do NOT need to recognize
540  executable files (neither by an extension nor by a magic
541  signature); that we do NOT need time stamp of root directories;
542  and that we do NOT need the write access bit in st_mode.
543 
544  Note that `kpse_set_program_name' needs the EXEC bits,
545  but it was already called by the time we get here. */
546  unsigned short save_djgpp_flags = _djstat_flags;
547 
548  _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT
549  | _STAT_ROOT_TIME | _STAT_WRITEBIT;
550 #endif
551 
552  /* Make a leading ~ count as an absolute filename, and expand $FOO's. */
553  name = kpathsea_expand (kpse, original_name);
554 
555 #ifdef KPSE_DEBUG
557  DEBUGF4 ("start search(xname=%s, must_exist=%d, find_all=%d, path=%s).\n",
558  name, must_exist, all, path);
559 #endif /* KPSE_DEBUG */
560 
561  /* If the first name is absolute or explicitly relative, no need to
562  consider PATH at all. */
563  absolute_p = kpathsea_absolute_p (kpse, name, true);
564 
565  /* Find the file(s). */
566  ret_list = absolute_p ? absolute_search (kpse, name)
568 
569  /* Append NULL terminator if we didn't find anything at all, or we're
570  supposed to find ALL and the list doesn't end in NULL now. */
571  if (STR_LIST_EMPTY (ret_list)
572  || (all && STR_LIST_LAST_ELT (ret_list) != NULL))
573  str_list_add (&ret_list, NULL);
574 
575  /* The very first search is for texmf.cnf. We can't log that, since
576  we want to allow setting TEXMFLOG in texmf.cnf. */
577  if (kpse->followup_search == false) {
578  kpse->followup_search = true;
579  } else {
580  /* Record the filenames we found, if desired. And wrap them in a
581  debugging line if we're doing that. */
582 #ifdef KPSE_DEBUG
584  DEBUGF1 ("returning from search(%s) =>", original_name);
585 #endif /* KPSE_DEBUG */
586  log_search (kpse, ret_list);
587 #ifdef KPSE_DEBUG
589  putc ('\n', stderr);
590 #endif /* KPSE_DEBUG */
591  }
592 
593 #ifdef __DJGPP__
594  /* Undo any side effects. */
595  _djstat_flags = save_djgpp_flags;
596 #endif
597 
598  /* Free the expanded name we were passed. It can't be in the return
599  list, since the path directories got unconditionally prepended. */
600  free (name);
601 
602  return STR_LIST (ret_list);
603 }
604 ␌
605 /* Search PATH for null-terminated array of NAMES. Always return a list;
606  if no files are found, the list will contain just NULL. If ALL is
607  true, the list will be terminated with NULL (but no NULL terminator
608  if ALL is false). This is a generalization of the `search' fn above. */
609 
610 string *
612  const_string path, string* names,
613  boolean must_exist, boolean all)
614 {
615  str_list_type ret_list;
616  string* namep;
617  string elt;
618  boolean done = false;
619  boolean all_absolute = true;
620 #ifdef __DJGPP__
621  /* See DJGPP comments above. */
622  unsigned short save_djgpp_flags = _djstat_flags;
623 
624  _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT
625  | _STAT_ROOT_TIME | _STAT_WRITEBIT;
626 #endif
627 
628  ret_list = str_list_init ();
629 
630 #ifdef KPSE_DEBUG
632  DEBUGF ("start generic search(files=");
633  print_space_list (stderr, names);
634  fprintf (stderr, ", must_exist=%d, find_all=%d, path=%s)\n",
635  must_exist, all, path);
636  }
637 #endif /* KPSE_DEBUG */
638 
639  /* kpathsea_find_file_generic in tex-file.c does the variable and
640  tilde expansion, so don't redo that here. Maybe we should have
641  done it differently, but we certainly don't want to create an
642  incompatibility now. */
643 
644  /* First catch any absolute or explicit relative names. */
645  for (namep = names; *namep; namep++) {
646  if (kpathsea_absolute_p (kpse, *namep, true)) {
647  str_list_type abs_ret_list = absolute_search (kpse, *namep);
648  /* That search can only return a zero- or one-element list, so: */
649  if (!STR_LIST_EMPTY (abs_ret_list)) {
650  str_list_add (&ret_list, STR_LIST_FIRST_ELT (abs_ret_list));
651  if (!all) { /* if they only wanted one, we're done */
652  goto out;
653  }
654  }
655  } else {
656  all_absolute = false;
657  }
658  }
659  /* Shortcut: if we were only given absolute/explicit relative names,
660  we can skip the rest. Typically, if one name is absolute, they
661  all are, because our caller derived them from each other. */
662  if (all_absolute) {
663 #ifdef KPSE_DEBUG
665  unsigned i;
666  DEBUGF (" generic search: all absolute, candidates are:");
667  /* List might not be NULL-terminated, so can't use print_space_list. */
668  for (i = 0; i < STR_LIST_LENGTH (ret_list); i++) {
669  fprintf (stderr, " %s", STR_LIST_ELT (ret_list, i));
670  }
671  fputs (".\n", stderr);
672  }
673 #endif
674  goto out;
675  }
676 
677  /* Look at each path element in turn. This is essentially the same
678  code as `path_search' above, unfortunately. */
679  for (elt = kpathsea_path_element (kpse, path); !done && elt;
680  elt = kpathsea_path_element (kpse, NULL)) {
682  boolean allow_disk_search = true;
683 
684  if (elt[0] == '!' && elt[1] == '!') {
685  /* !! magic string -> disallow disk searches. */
686  allow_disk_search = false;
687  elt += 2;
688  }
689 
690  /* See elt-dirs.c for side effects of this function. */
692 
693  /* Try ls-R, unless we're searching for texmf.cnf. */
696 
697  /* Search the filesystem in the same cases as `path_search' above. */
698  if (allow_disk_search
699  && (!found || (must_exist && !STR_LIST (*found)))) {
701  if (dirs && *dirs) {
702  if (!found) {
704  }
705  /* Search in the directories: */
708 #ifdef KPSE_CASEFOLDING_SEARCH
710  "texmf_casefold_search"))) {
711  /* Still nothing; search again, case-insensitively: */
714  }
715 #endif
716  }
717  }
718 
719  /* Did we find anything? */
720  if (found && STR_LIST (*found)) {
721  if (all) {
722  str_list_concat (&ret_list, *found);
723  } else {
724  str_list_add (&ret_list, STR_LIST_FIRST_ELT (*found));
725  done = true;
726  }
727  }
728  }
729 
730  out:
731  /* Uniqify, since our paths can often end up finding the same file
732  more than once. */
733  str_list_uniqify (&ret_list);
734 
735  /* Add NULL element to terminate return list if empty or multiple. */
736  if (STR_LIST_EMPTY (ret_list)
737  || (all && STR_LIST_LAST_ELT (ret_list) != NULL))
738  str_list_add (&ret_list, NULL);
739 
740  if (kpse->followup_search == false) {
741  kpse->followup_search = true;
742  } else {
743  /* Record the filenames we found, if desired. And wrap them in a
744  debugging line if we're doing that. */
745 #ifdef KPSE_DEBUG
747  DEBUGF ("returning from generic search(");
748  print_space_list (stderr, names);
749  fputs (") =>", stderr);
750  }
751 #endif /* KPSE_DEBUG */
752  log_search (kpse, ret_list);
753 #ifdef KPSE_DEBUG
755  putc ('\n', stderr);
756 #endif /* KPSE_DEBUG */
757  }
758 
759 #ifdef __DJGPP__
760  /* Undo any side effects. */
761  _djstat_flags = save_djgpp_flags;
762 #endif
763 
764  return STR_LIST (ret_list);
765 }
766 ␌
767 /* Search PATH for the first NAME according to MUST_EXIST. */
768 
769 string
771  boolean must_exist)
772 {
773  string *ret_list = search (kpse, path, name, must_exist, false);
774  string ret = *ret_list;
775  free (ret_list);
776  return ret;
777 }
778 
779 /* Search PATH for all files named NAME. Might have been better not
780  to assert `must_exist' here, but it's too late to change. */
781 
782 string *
784 {
785  string *ret = search (kpse, path, name, true, true);
786  return ret;
787 }
788 
789 #if defined (KPSE_COMPAT_API)
790 string
791 kpse_path_search (const_string path, const_string name, boolean must_exist)
792 {
794 }
795 
796 string *
797 kpse_all_path_search (const_string path, const_string name)
798 {
800 }
801 #endif /* KPSE_COMPAT_API */
802 
803 ␌
804 #ifdef TEST
805 
806 /* Each element of L on its own line, prefixed by a tab. */
807 
808 static void
809 print_tab_list (string *l)
810 {
811  while (l && *l) {
812  if (*l)
813  putchar ('\t');
814  printf ("%s\n", *l);
815  l++;
816  }
817 }
818 
819 static void
820 test_path_search (const_string path, const_string file)
821 {
822  string answer;
823  string *answer_list;
824 
825  printf ("\nSearch %s for %s:\t", path, file);
826  answer = kpse_path_search (path, file, 0);
827  puts (answer ? answer : "(nil)");
828 
829  printf ("Search %s for all %s:\t", path, file);
830  answer_list = kpse_all_path_search (path, file);
831  putchar ('\n');
832  print_tab_list (answer_list);
833 }
834 
835 static void
836 test_path_search_list_generic (void)
837 {
838  const_string path = "/u/karl/.fonts";
839  /* absolute: should return just console/both, because no case
840  sensitive match */
841  // string names[] = { "/u/karl/.fonts/lucidaConsoleDK.otf",
842  // "/u/karl/.fonts/lucidaGrandeMonoDK.otf", NULL };
843 
844  /* dirs: should return just grande, because case sensitive wins */
845  // string names[] = { "lucidaConsoleDK.otf", "LucidaGrandeMonoDK.otf", NULL };
846 
847  /* dirs: should return just console/both, because no case sensitive match */
848  string names[] = { "lucidaConsoleDK.otf", "lucidaGrandeMonoDK.otf", NULL };
849 
850  boolean all;
851  string *answer_list;
852 
853  printf ("\nGeneric search %s for ", path);
854  print_space_list (stdout, names);
855  puts (":\t");
856 
857  all = false; answer_list
859  puts (answer_list && *answer_list ? *answer_list : "(nil)");
860 
861  printf ("\nGeneric search %s for all ", path);
862  print_space_list (stdout, names);
863  puts (":");
864 
865  all = true; answer_list
867  print_tab_list (answer_list);
868 }
869 
870 #define TEXFONTS "/usr/local/texlive-rel/texmf-dist/fonts"
871 
872 int
873 main (int argc, char **argv)
874 {
875  xputenv ("KPATHSEA_DEBUG", "-1"); /* must be before setting progname */
876  kpse_set_program_name (argv[0], NULL);
877 
878  xputenv ("MALLOC_CHECK_", "3");
879  xputenv ("MALLOC_PERTURB_", "75");
880 
881  xputenv ("texmf_casefold_search", "1");
882  test_path_search (".:/k", "readme");
883  exit (0);
884  test_path_search_list_generic ();
885  exit (0);
886 
887  xputenv ("TEXMFCNF", "/nc");
888  /* casefolding with absolute search: */
889  test_path_search ("/k", "/u/karl/.fonts/lucidaConsoleDK.otf");
890  /* casefolding with directory search: */
891  test_path_search ("/u/karl/.fonts", "Lucidaconsoledk.otf");
892  /* exit (0); */
893  xputenv ("texmf_casefold_search", "0");
894  /* should fail since no casefolding: */
895  test_path_search ("/u/karl/.fonts", "lucidaconsoledk.otf");
896 
897  /* All lists end with NULL. */
898  test_path_search (".", "nonexistent");
899  test_path_search (".", "/nonexistent");
900  test_path_search ("/k" ENV_SEP_STRING ".", "README");
901  test_path_search ("/k" ENV_SEP_STRING ".", "/etc/fstab");
902  test_path_search ("." ENV_SEP_STRING TEXFONTS "//", "cmr10.tfm");
903  test_path_search ("." ENV_SEP_STRING TEXFONTS "//", "logo10.tfm");
904  test_path_search (TEXFONTS "//times" ENV_SEP_STRING "."
905  ENV_SEP_STRING ENV_SEP_STRING, "ptmr.vf");
906  test_path_search (TEXFONTS ENV_SEP_STRING
907  "/u/karl/.fonts", "LucidaConsoleDK.otf");
908 
909  test_path_search ("~karl", ".profile"); // nil, no ~ expansion on path
910  test_path_search ("/k", "~karl/.profile");
911 
912  xputenv ("NONEXIST", "nonexistent");
913  test_path_search (".", "$NONEXIST");
914  xputenv ("KPATHSEA", "kpathsea");
915  test_path_search ("/k" ENV_SEP_STRING "./doc", "$KPATHSEA.texi");
916  test_path_search ("/k" ENV_SEP_STRING "./doc", "${KPATHSEA}.texi");
917  test_path_search ("$KPATHSEA" ENV_SEP_STRING ".", "README");
918  test_path_search ("." ENV_SEP_STRING "$KPATHSEA", "README");
919 
920  return 0;
921 }
922 
923 #endif /* TEST */
924 
925 
926 /* ${wc} is the corresponding build directory.
927  -DMAKE_KPSE_DLL for inlined str_list_init etc.
928  Memory checking: -fsanitize=address or -lefence.
929 Local variables:
930 standalone-compile-command: "make --no-print-dir -C ${wc} && gcc -g -I. -I.. -I${wc}/.. -DMAKE_KPSE_DLL -DTEST pathsearch.c ${wc}/.libs/libkpathsea.a && ./a.out"
931 End:
932 */
void __cdecl perror(char const *_ErrMsg)
static const char * xbasename(const char *name)
Definition: afm2pl.c:410
#define name
static str_number log_name
Definition: aptex.h:481
#define free(a)
Definition: decNumber.cpp:310
size_t dir_len(char const *file)
Definition: dirname-lgpl.c:32
#define fopen
Definition: xxstdio.h:21
int printf()
char * strcpy()
static kpathsea kpse
Definition: support.c:104
FILE * out
Definition: hbf2gf.c:286
#define putc
Definition: jbib.h:20
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p scientific i
Definition: afcover.h:80
void exit()
#define xstrdup(s)
Definition: writet1.c:34
#define XTALLOC(n, t)
Definition: writet1.c:32
#define xmalloc(size)
Definition: writet1.c:33
int must_exist
Definition: cidtype2.c:87
char * concat3(const char *s1, const char *s2, const char *s3)
Definition: utils.c:178
boolean kpathsea_absolute_p(kpathsea kpse, const_string filename, boolean relative_ok)
Definition: absolute.c:28
#define strcasecmp
Definition: c-auto.h:150
#define FOPEN_A_MODE
Definition: c-fopen.h:28
#define DIR_SEP_STRING
Definition: c-pathch.h:56
#define ENV_SEP_STRING
Definition: c-pathch.h:92
str_list_type * kpathsea_db_search_list(kpathsea kpse, string *names, const_string path_elt, boolean all)
Definition: db.c:654
str_list_type * kpathsea_db_search(kpathsea kpse, const_string name, const_string orig_path_elt, boolean all)
Definition: db.c:503
#define KPSE_DEBUG_SEARCH
Definition: debug.h:73
#define DEBUGF2(str, e1, e2)
Definition: debug.h:85
#define DEBUGF1(str, e1)
Definition: debug.h:83
#define DEBUGF(str)
Definition: debug.h:81
#define KPSE_DEBUG
Definition: debug.h:53
#define DEBUGF4(str, e1, e2, e3, e4)
Definition: debug.h:89
#define KPATHSEA_DEBUG_P(bit)
Definition: debug.h:56
#define DEBUGF3(str, e1, e2, e3)
Definition: debug.h:87
struct dirent * readdir(DIR *dirp)
Definition: dirent.c:138
DIR * opendir(char *fname)
Definition: dirent.c:60
unsigned kpathsea_normalize_path(kpathsea kpse, string elt)
Definition: elt-dirs.c:364
str_llist_type * kpathsea_element_dirs(kpathsea kpse, string elt)
Definition: elt-dirs.c:407
string kpathsea_expand(kpathsea kpse, const_string s)
Definition: expand.c:35
KPSEDLL string xdirname(const_string name)
Definition: xdirname.c:29
#define XRETALLOC(addr, n, t)
Definition: lib.h:229
#define KPSE_CNF_P(val)
Definition: lib.h:129
#define XTALLOC1(t)
Definition: lib.h:228
string kpathsea_path_element(kpathsea kpse, const_string p)
Definition: path-elt.c:95
string * kpathsea_all_path_search(kpathsea kpse, const_string path, const_string name)
Definition: pathsearch.c:783
string(* readable_file_fn_type)(kpathsea, string)
Definition: pathsearch.c:127
string kpathsea_path_search(kpathsea kpse, const_string path, const_string name, boolean must_exist)
Definition: pathsearch.c:770
string * kpathsea_path_search_list_generic(kpathsea kpse, const_string path, string *names, boolean must_exist, boolean all)
Definition: pathsearch.c:611
string kpathsea_readable_file(kpathsea kpse, string name)
Definition: readable.c:123
const char * const_string
Definition: simpletypes.h:59
void str_list_free(str_list_type *l)
Definition: str-list.c:110
void str_list_add(str_list_type *l, string s)
Definition: str-list.c:28
void str_list_uniqify(str_list_type *l)
Definition: str-list.c:124
void str_list_concat(str_list_type *target, str_list_type more)
Definition: str-list.c:48
#define STR_LIST_LAST_ELT(l)
Definition: str-list.h:50
#define STR_LIST_EMPTY(l)
Definition: str-list.h:45
#define STR_LIST_FIRST_ELT(l)
Definition: str-list.h:49
#define STR_LIST_LENGTH(l)
Definition: str-list.h:44
#define STR_LIST_ELT(l, n)
Definition: str-list.h:48
#define STR_LIST(l)
Definition: str-list.h:47
void str_llist_float(str_llist_type *l, str_llist_elt_type *mover)
Definition: str-llist.c:52
#define STR_LLIST(sl)
Definition: str-llist.h:46
#define STR_LLIST_NEXT(sl)
Definition: str-llist.h:48
KPSEDLL kpathsea kpse_def
struct kpathsea_instance * kpathsea
Definition: types.h:221
string kpathsea_var_value(kpathsea kpse, const_string var)
Definition: variable.c:31
void xclosedir(DIR *d)
Definition: xopendir.c:36
static int ret
Definition: convert.c:72
#define fputs
Definition: mendex.h:67
#define fprintf
Definition: mendex.h:64
#define string
Definition: ctangleboot.c:111
list names
Definition: fc-lang.py:151
std::is_same< integer_sequence< bool, true, Bs... >, integer_sequence< bool, Bs..., true > > all
Definition: variant.hpp:799
char * filename[256]
Definition: pbmtopk.c:46
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld endif[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld_src SRC pixld MASK if DST_R else pixld DST_R endif if
time_t time()
#define dir
static string casefold_readable_file(kpathsea kpse, string name)
Definition: pathsearch.c:150
static str_list_type absolute_search(kpathsea kpse, string name)
Definition: pathsearch.c:377
static str_list_type path_search(kpathsea kpse, const_string path, string name, boolean must_exist, boolean all)
Definition: pathsearch.c:423
static string * search(kpathsea kpse, const_string path, const_string original_name, boolean must_exist, boolean all)
Definition: pathsearch.c:523
static void log_search(kpathsea kpse, str_list_type filenames)
Definition: pathsearch.c:77
static str_list_type dir_list_search(kpathsea kpse, str_llist_type *dirs, const_string name, boolean search_all, readable_file_fn_type readable_file_p)
Definition: pathsearch.c:220
static str_list_type dir_list_search_list(kpathsea kpse, str_llist_type *dirs, string *names, boolean search_all, readable_file_fn_type readable_file_p)
Definition: pathsearch.c:293
#define INIT_ALLOC
Definition: pathsearch.c:217
ShellFileEnvironment e
Definition: sh6.c:388
Definition: dirent.h:44
Definition: dirent.h:34
Definition: filedef.h:30
boolean log_opened
Definition: types.h:253
FILE * log_file
Definition: types.h:252
boolean followup_search
Definition: types.h:251
Definition: tpic.c:45
#define FILE
Definition: t1stdio.h:34
*job_name strlen((char *) job_name) - 4)
found
Definition: tex4ht.c:5000
#define argv
Definition: xmain.c:270
#define main
Definition: xmain.c:31
#define argc
Definition: xmain.c:269