new beta-0.90.0
[luatex.git] / source / texk / kpathsea / elt-dirs.c
blob695449469281726e0bd81d22f68faa0b240af486
1 /* elt-dirs.c: Translate a path element to its corresponding director{y,ies}.
3 Copyright 1993, 1994, 1995, 1996, 1997, 2008, 2009, 2010, 2011 Karl Berry.
4 Copyright 1997, 1998, 1999, 2000, 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>
21 #include <kpathsea/c-pathch.h>
22 #include <kpathsea/expand.h>
23 #include <kpathsea/fn.h>
24 #include <kpathsea/pathsearch.h>
25 #include <kpathsea/xopendir.h>
27 /* To avoid giving prototypes for all the routines and then their real
28 definitions, we give all the subroutines first. The entry point is
29 the last routine in the file. */
31 /* Make a copy of DIR (unless it's null) and save it in L. Ensure that
32 DIR ends with a DIR_SEP for the benefit of later searches. */
34 static void
35 dir_list_add (str_llist_type *l, string dir)
37 char last_char = dir[strlen (dir) - 1];
38 string saved_dir
39 = IS_DIR_SEP_CH (last_char) || IS_DEVICE_SEP (last_char)
40 ? xstrdup (dir)
41 : concat (dir, DIR_SEP_STRING);
43 str_llist_add (l, saved_dir);
47 /* If DIR is a directory, add it to the list L. */
49 static void
50 checked_dir_list_add (kpathsea kpse, str_llist_type *l, string dir)
52 if (kpathsea_dir_p (kpse, dir))
53 dir_list_add (l, dir);
56 /* The cache. Typically, several paths have the same element; for
57 example, /usr/local/lib/texmf/fonts//. We don't want to compute the
58 expansion of such a thing more than once. Even though we also cache
59 the dir_links call, that's not enough -- without this path element
60 caching as well, the execution time doubles. */
62 /* Associate KEY with VALUE. We implement the cache as a simple linear
63 list, since it's unlikely to ever be more than a dozen or so elements
64 long. We don't bother to check here if PATH has already been saved;
65 we always add it to our list. We copy KEY but not VALUE; not sure
66 that's right, but it seems to be all that's needed. */
68 static void
69 cache (kpathsea kpse, const_string key, str_llist_type *value)
71 kpse->cache_length++;
72 XRETALLOC (kpse->the_cache, kpse->cache_length, cache_entry);
73 kpse->the_cache[kpse->cache_length - 1].key = xstrdup (key);
74 kpse->the_cache[kpse->cache_length - 1].value = value;
78 /* To retrieve, just check the list in order. */
80 static str_llist_type *
81 cached (kpathsea kpse, const_string key)
83 unsigned p;
85 for (p = 0; p < kpse->cache_length; p++)
87 if (FILESTRCASEEQ (kpse->the_cache[p].key, key))
88 return kpse->the_cache[p].value;
91 return NULL;
94 /* Handle the magic path constructs. */
96 /* Declare recursively called routine. */
97 static void expand_elt (kpathsea, str_llist_type *, string, unsigned);
100 /* POST is a pointer into the original element (which may no longer be
101 ELT) to just after the doubled DIR_SEP, perhaps to the null. Append
102 subdirectories of ELT (up to ELT_LENGTH, which must be a /) to
103 STR_LIST_PTR. */
105 #ifdef WIN32
106 /* Shared across recursive calls, it acts like a stack. */
107 static char dirname[MAX_PATH*2];
108 static wchar_t dirnamew[MAX_PATH];
109 static char *potname;
110 #endif
112 static void
113 do_subdir (kpathsea kpse, str_llist_type *str_list_ptr, string elt,
114 unsigned elt_length, string post)
116 #ifdef WIN32
117 WIN32_FIND_DATAW find_file_data;
118 HANDLE hnd;
119 int proceed;
120 int nlinks = 2;
121 #else
122 DIR *dir;
123 struct dirent *e;
124 #endif /* not WIN32 */
125 fn_type name;
127 /* Some old compilers don't allow aggregate initialization. */
128 name = fn_copy0 (elt, elt_length);
130 assert (IS_DIR_SEP_CH (elt[elt_length - 1])
131 || IS_DEVICE_SEP (elt[elt_length - 1]));
133 #if defined (WIN32)
134 strcpy(dirname, FN_STRING(name));
135 strcat(dirname, "/*.*"); /* "*.*" or "*" -- seems equivalent. */
136 get_wstring_from_fsyscp(dirname, dirnamew);
137 hnd = FindFirstFileW(dirnamew, &find_file_data);
139 if (hnd == INVALID_HANDLE_VALUE) {
140 fn_free(&name);
141 return;
144 /* Include top level before subdirectories, if nothing to match. */
145 if (*post == 0)
146 dir_list_add (str_list_ptr, FN_STRING (name));
147 else {
148 /* If we do have something to match, see if it exists. For
149 example, POST might be `pk/ljfour', and they might have a
150 directory `$TEXMF/fonts/pk/ljfour' that we should find. */
151 fn_str_grow (&name, post);
152 expand_elt (kpse, str_list_ptr, FN_STRING (name), elt_length);
153 fn_shrink_to (&name, elt_length);
155 proceed = 1;
156 while (proceed) {
157 if (find_file_data.cFileName[0] != L'.') {
158 int links;
160 /* Construct the potential subdirectory name. */
161 potname = get_fsyscp_from_wstring(find_file_data.cFileName, potname=NULL);
162 fn_str_grow (&name, potname);
163 free(potname);
165 /* Maybe we have cached the leafness of this directory.
166 The function will return 0 if unknown,
167 else the actual (Unix-like) value. */
168 links = kpathsea_dir_links (kpse, FN_STRING (name), 0);
170 if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
171 unsigned potential_len = FN_LENGTH (name);
172 /* in any case, compute the leafness */
173 nlinks++;
175 /* It's a directory, so append the separator. */
176 fn_str_grow (&name, DIR_SEP_STRING);
177 if (*post != 0) {
178 fn_str_grow (&name, post);
179 /* Unfortunately we can't check if the new element is
180 a leaf directory, because we don't have a directory
181 name here, we just have a path spec. This means we
182 may descend into a leaf directory cm/pk, if the
183 spec is ...fonts//pk//. */
184 expand_elt (kpse, str_list_ptr, FN_STRING (name), potential_len);
185 fn_shrink_to (&name, potential_len);
187 /* Should we recurse? To see if the subdirectory is a
188 leaf, check if it has two links (one for . and one for
189 ..). This means that symbolic links to directories do
190 not affect the leaf-ness. This is arguably wrong, but
191 the only alternative I know of is to stat every entry
192 in the directory, and that is unacceptably slow. */
194 if (links == 0 || links > 2)
195 /* All criteria are met; find subdirectories. */
196 do_subdir (kpse, str_list_ptr, FN_STRING (name),
197 potential_len, post);
198 else if (*post == 0)
199 /* Nothing to match, no recursive subdirectories to
200 look for: we're done with this branch. Add it. */
201 dir_list_add (str_list_ptr, FN_STRING (name));
203 fn_shrink_to (&name, elt_length);
205 proceed = FindNextFileW (hnd, &find_file_data);
207 /* Update the leafness of name. */
208 kpathsea_dir_links(kpse, FN_STRING(name), nlinks);
209 fn_free (&name);
210 FindClose(hnd);
212 #else /* not WIN32 */
214 /* If we can't open it, quit. */
215 dir = opendir (FN_STRING (name));
216 if (dir == NULL)
218 fn_free (&name);
219 return;
222 /* Include top level before subdirectories, if nothing to match. */
223 if (*post == 0)
224 dir_list_add (str_list_ptr, FN_STRING (name));
225 else
226 { /* If we do have something to match, see if it exists. For
227 example, POST might be `pk/ljfour', and they might have a
228 directory `$TEXMF/fonts/pk/ljfour' that we should find. */
229 fn_str_grow (&name, post);
230 expand_elt (kpse, str_list_ptr, FN_STRING (name), elt_length);
231 fn_shrink_to (&name, elt_length);
234 while ((e = readdir (dir)) != NULL)
235 { /* If it begins with a `.', never mind. (This allows ``hidden''
236 directories that the algorithm won't find.) */
237 if (e->d_name[0] != '.')
239 int links;
241 /* Construct the potential subdirectory name. */
242 fn_str_grow (&name, e->d_name);
244 /* If we can't stat it, or if it isn't a directory, continue. */
245 links = kpathsea_dir_links (kpse, FN_STRING (name), 0);
247 if (links >= 0)
249 unsigned potential_len = FN_LENGTH (name);
251 /* It's a directory, so append the separator. */
252 fn_str_grow (&name, DIR_SEP_STRING);
254 if (*post != 0)
256 fn_str_grow (&name, post);
257 /* Unfortunately we can't check if the new element is
258 a leaf directory, because we don't have a directory
259 name here, we just have a path spec. This means we
260 may descend into a leaf directory cm/pk, if the
261 spec is ...fonts//pk//. */
262 expand_elt (kpse, str_list_ptr, FN_STRING (name),
263 potential_len);
264 fn_shrink_to (&name, potential_len);
267 /* Should we recurse? To see if the subdirectory is a
268 leaf, check if it has two links (one for . and one for
269 ..). This means that symbolic links to directories do
270 not affect the leaf-ness. This is arguably wrong, but
271 the only alternative I know of is to stat every entry
272 in the directory, and that is unacceptably slow.
274 The #ifdef here makes all this configurable at
275 compile-time, so that if we're using VMS directories or
276 some such, we can still find subdirectories, even if it
277 is much slower. */
278 #ifdef ST_NLINK_TRICK
279 /* With SAS/C++ 6.55 on the Amiga, stat sets the st_nlink
280 field to -1 for a file, or to 1 for a directory.
281 Cygwin 1.7 also leaves st_nlink as 1:
282 http://cygwin.com/ml/cygwin-developers/2008-04/msg00110.html
284 if (links != 2)
285 #endif /* ST_NLINK_TRICK */
286 /* All criteria are met; find subdirectories. */
287 do_subdir (kpse, str_list_ptr, FN_STRING (name),
288 potential_len, post);
289 #ifdef ST_NLINK_TRICK
290 else if (*post == 0)
291 /* Nothing to match, no recursive subdirectories to
292 look for: we're done with this branch. Add it. */
293 dir_list_add (str_list_ptr, FN_STRING (name));
294 #endif
297 /* Remove the directory entry we just checked from `name'. */
298 fn_shrink_to (&name, elt_length);
302 fn_free (&name);
303 xclosedir (dir);
304 #endif /* not WIN32 */
308 /* Assume ELT is non-empty and non-NULL. Return list of corresponding
309 directories (with no terminating NULL entry) in STR_LIST_PTR. Start
310 looking for magic constructs at START. */
312 static void
313 expand_elt (kpathsea kpse, str_llist_type * str_list_ptr, string elt,
314 unsigned start)
316 string dir = elt + start, post;
318 while (*dir != 0)
320 if (IS_DIR_SEP_CH (*dir))
322 /* If two or more consecutive /'s, find subdirectories. */
323 if (IS_DIR_SEP_CH (dir[1]))
325 for (post = dir + 1; IS_DIR_SEP_CH (*post); post++) ;
326 do_subdir (kpse, str_list_ptr, elt, dir - elt + 1, post);
327 return;
330 /* No special stuff at this slash. Keep going. */
333 dir++;
336 /* When we reach the end of ELT, it will be a normal filename. */
337 checked_dir_list_add (kpse, str_list_ptr, elt);
340 /* On win32 we slashify ELT, i.e., change '\\' to '/', and then can use
341 IS_DIR_SEP_CH instead of IS_DIR_SEP and need not test for the presence
342 of 2-Byte Kanji (CP 932, SJIS) codes. */
344 /* The first bits of a path element can be problematic because they
345 look like a request to expand a whole disk, rather than a subtree.
346 - It can contain a drive specification.
347 - It can be a UNC path (w32, but they are part of the single
348 Unix specification as well).
349 The argument is a string as the function can diddle into the argument
350 to canonicalize it, which tends to matter on windows platforms.
351 - Always lower-case drive letters a-z, even those filesystem that
352 preserve case in filenames do not care about the case of the drive
353 letters.
354 - Remove unneeded double slashes. The problem is Windows does not
355 handle well filenames like c://dir/foo. So canonicalize the names.
356 The resulting name will always be shorter than the one passed, so no
357 problem.
358 - Remove multiple leading slashes to prevent expanding from the root
359 of a UNIX filesystem tree. */
361 unsigned
362 kpathsea_normalize_path (kpathsea kpse, string elt)
364 unsigned ret;
365 unsigned i;
367 #if defined(WIN32)
368 for (i = 0; elt[i]; i++) {
369 if (elt[i] == '\\')
370 elt[i] = '/';
371 else if (IS_KANJI(elt + i))
372 i++;
374 #endif
376 if (NAME_BEGINS_WITH_DEVICE(elt)) {
377 if (*elt >= 'A' && *elt <= 'Z')
378 *elt += 'a' - 'A';
379 ret = 2;
381 } else if (IS_UNC_NAME(elt)) {
382 for (ret = 2; elt[ret] && !IS_DIR_SEP_CH(elt[ret]); ret++)
385 } else
386 ret = 0;
388 for (i = ret; IS_DIR_SEP_CH(elt[i]); ++i)
390 if (i > ret + 1) {
391 #ifdef KPSE_DEBUG
392 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_STAT))
393 DEBUGF2 ("kpse_normalize_path (%s) => %u\n", elt, ret);
394 #endif /* KPSE_DEBUG */
396 memmove (elt + ret + 1, elt + i, strlen (elt + i) + 1);
399 return ret;
402 /* Here is the entry point. Returns directory list for ELT. */
404 str_llist_type *
405 kpathsea_element_dirs (kpathsea kpse, string elt)
407 str_llist_type *ret;
408 unsigned i;
410 /* If given nothing, return nothing. */
411 if (!elt || !*elt)
412 return NULL;
414 /* Normalize ELT before looking for a cached value. */
415 i = kpathsea_normalize_path (kpse, elt);
417 /* If we've already cached the answer for ELT, return it. */
418 ret = cached (kpse, elt);
419 if (ret)
420 return ret;
422 /* We're going to have a real directory list to return. */
423 ret = XTALLOC1 (str_llist_type);
424 *ret = NULL;
426 /* We handle the hard case in a subroutine. */
427 expand_elt (kpse, ret, elt, i);
429 /* Remember the directory list we just found, in case future calls are
430 made with the same ELT. */
431 cache (kpse, elt, ret);
433 #ifdef KPSE_DEBUG
434 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_EXPAND))
436 DEBUGF1 ("path element %s =>", elt);
437 if (ret)
439 str_llist_elt_type *e;
440 for (e = *ret; e; e = STR_LLIST_NEXT (*e))
441 fprintf (stderr, " %s", STR_LLIST (*e));
443 putc ('\n', stderr);
444 fflush (stderr);
446 #endif /* KPSE_DEBUG */
448 return ret;
451 #ifdef TEST
453 void
454 print_element_dirs (const_string elt)
456 str_llist_type *dirs;
458 printf ("Directories of %s:\t", elt ? elt : "(nil)");
459 fflush (stdout);
461 dirs = kpathsea_element_dirs (kpse_def, elt);
463 if (!dirs)
464 printf ("(nil)");
465 else
467 str_llist_elt_type *dir;
468 for (dir = *dirs; dir; dir = STR_LLIST_NEXT (*dir))
470 string d = STR_LLIST (*dir);
471 printf ("%s ", *d ? d : "`'");
475 putchar ('\n');
479 main ()
481 /* DEBUG_SET (DEBUG_STAT); */
482 /* All lists end with NULL. */
483 print_element_dirs (NULL); /* */
484 print_element_dirs (""); /* ./ */
485 print_element_dirs ("/k"); /* */
486 print_element_dirs (".//"); /* ./ ./archive/ */
487 print_element_dirs (".//archive"); /* ./ ./archive/ */
488 #ifdef AMIGA
489 print_element_dirs ("TeXMF:AmiWeb2c/texmf/fonts//"); /* lots */
490 print_element_dirs ("TeXMF:AmiWeb2c/share/texmf/fonts//bakoma"); /*just one*/
491 print_element_dirs ("TeXMF:AmiWeb2c/texmf/fonts//"); /* lots again [cache] */
492 print_element_dirs ("TeXMF:"); /* TeXMF: */
493 print_element_dirs ("TeXMF:/"); /* TeXMF: and all subdirs */
494 #else /* not AMIGA */
495 print_element_dirs ("/tmp/fonts//"); /* no need to stat anything */
496 print_element_dirs ("/usr/local/lib/tex/fonts//"); /* lots */
497 print_element_dirs ("/usr/local/lib/tex/fonts//times"); /* just one */
498 print_element_dirs ("/usr/local/lib/tex/fonts//"); /* lots again [cache] */
499 print_element_dirs ("~karl"); /* tilde expansion */
500 print_element_dirs ("$karl"); /* variable expansion */
501 print_element_dirs ("~${LOGNAME}"); /* both */
502 #endif /* not AMIGA */
503 return 0;
506 #endif /* TEST */
510 Local variables:
511 standalone-compile-command: "gcc -g -I. -I.. -DTEST elt-dirs.c kpathsea.a"
512 End: