4378
|
1 /* pathsearch.c: look up a filename in a path. |
|
2 |
|
3 Copyright (C) 1993, 94, 95, 96, 97 Karl Berry. |
|
4 Copyright (C) 1993, 94, 95, 96, 97 Karl Berry & O. Weber. |
|
5 |
|
6 This library is free software; you can redistribute it and/or |
|
7 modify it under the terms of the GNU Library General Public |
|
8 License as published by the Free Software Foundation; either |
|
9 version 2 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 Library General Public License for more details. |
|
15 |
|
16 You should have received a copy of the GNU Library General Public |
|
17 License along with this library; if not, write to the Free Software |
|
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|
19 |
|
20 #if defined (HAVE_CONFIG_H) |
|
21 #include <config.h> |
|
22 #endif |
|
23 |
|
24 #include "kpse-config.h" |
4379
|
25 #include "kpse-xfns.h" |
4378
|
26 #include "kpse.h" |
|
27 |
|
28 #include <time.h> /* for `time' */ |
|
29 |
|
30 #ifdef __DJGPP__ |
|
31 #include <sys/stat.h> /* for stat bits */ |
|
32 #endif |
|
33 |
|
34 /* The very first search is for texmf.cnf, called when someone tries to |
|
35 initialize the TFM path or whatever. init_path calls kpse_cnf_get |
|
36 which calls kpse_all_path_search to find all the texmf.cnf's. We |
|
37 need to do various special things in this case, since we obviously |
|
38 don't yet have the configuration files when we're searching for the |
|
39 configuration files. */ |
|
40 static bool first_search = true; |
|
41 |
|
42 |
|
43 |
|
44 /* This function is called after every search (except the first, since |
|
45 we definitely want to allow enabling the logging in texmf.cnf) to |
|
46 record the filename(s) found in $TEXMFLOG. */ |
|
47 |
|
48 static void |
|
49 log_search (str_list_type filenames) |
|
50 { |
|
51 static FILE *log_file = NULL; |
|
52 static bool first_time = true; /* Need to open the log file? */ |
|
53 |
|
54 if (first_time) { |
|
55 /* Get name from either envvar or config file. */ |
|
56 char *log_name = kpse_var_value ("TEXMFLOG"); |
|
57 first_time = false; |
|
58 if (log_name) { |
|
59 log_file = fopen (log_name, FOPEN_A_MODE); |
|
60 if (!log_file) |
|
61 perror (log_name); |
|
62 free (log_name); |
|
63 } |
|
64 } |
|
65 |
|
66 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH) || log_file) { |
|
67 unsigned e; |
|
68 |
|
69 /* FILENAMES should never be null, but safety doesn't hurt. */ |
|
70 for (e = 0; e < STR_LIST_LENGTH (filenames) && STR_LIST_ELT (filenames, e); |
|
71 e++) { |
|
72 char *filename = STR_LIST_ELT (filenames, e); |
|
73 |
|
74 /* Only record absolute filenames, for privacy. */ |
|
75 if (log_file && kpse_absolute_p (filename, false)) |
|
76 fprintf (log_file, "%lu %s\n", (long unsigned) time (NULL), |
|
77 filename); |
|
78 |
|
79 /* And show them online, if debugging. We've already started |
|
80 the debugging line in `search', where this is called, so |
|
81 just print the filename here, don't use DEBUGF. */ |
|
82 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) |
|
83 fputs (filename, stderr); |
|
84 } |
|
85 } |
|
86 } |
|
87 |
|
88 /* Concatenate each element in DIRS with NAME (assume each ends with a |
|
89 /, to save time). If SEARCH_ALL is false, return the first readable |
|
90 regular file. Else continue to search for more. In any case, if |
|
91 none, return a list containing just NULL. |
|
92 |
|
93 We keep a single buffer for the potential filenames and reallocate |
|
94 only when necessary. I'm not sure it's noticeably faster, but it |
|
95 does seem cleaner. (We do waste a bit of space in the return |
|
96 value, though, since we don't shrink it to the final size returned.) */ |
|
97 |
|
98 #define INIT_ALLOC 75 /* Doesn't much matter what this number is. */ |
|
99 |
|
100 static str_list_type |
|
101 dir_list_search (str_llist_type *dirs, const char *name, bool search_all) |
|
102 { |
|
103 str_llist_elt_type *elt; |
|
104 str_list_type ret; |
|
105 unsigned name_len = strlen (name); |
|
106 unsigned allocated = INIT_ALLOC; |
|
107 char *potential = (char *) xmalloc (allocated); |
|
108 |
|
109 ret = str_list_init (); |
|
110 |
|
111 for (elt = *dirs; elt; elt = STR_LLIST_NEXT (*elt)) |
|
112 { |
|
113 const char *dir = STR_LLIST (*elt); |
|
114 unsigned dir_len = strlen (dir); |
|
115 |
|
116 while (dir_len + name_len + 1 > allocated) |
|
117 { |
|
118 allocated += allocated; |
|
119 XRETALLOC (potential, allocated, char); |
|
120 } |
|
121 |
|
122 strcpy (potential, dir); |
|
123 strcat (potential, name); |
|
124 |
|
125 if (kpse_readable_file (potential)) |
|
126 { |
|
127 str_list_add (&ret, potential); |
|
128 |
|
129 /* Move this element towards the top of the list. */ |
|
130 str_llist_float (dirs, elt); |
|
131 |
|
132 /* If caller only wanted one file returned, no need to |
|
133 terminate the list with NULL; the caller knows to only look |
|
134 at the first element. */ |
|
135 if (!search_all) |
|
136 return ret; |
|
137 |
|
138 /* Start new filename. */ |
|
139 allocated = INIT_ALLOC; |
|
140 potential = (char *) xmalloc (allocated); |
|
141 } |
|
142 } |
|
143 |
|
144 /* If we get here, either we didn't find any files, or we were finding |
|
145 all the files. But we're done with the last filename, anyway. */ |
|
146 free (potential); |
|
147 |
|
148 return ret; |
|
149 } |
|
150 |
|
151 /* This is called when NAME is absolute or explicitly relative; if it's |
|
152 readable, return (a list containing) it; otherwise, return NULL. */ |
|
153 |
|
154 static str_list_type |
|
155 absolute_search (char *name) |
|
156 { |
|
157 str_list_type ret_list; |
|
158 char *found = kpse_readable_file (name); |
|
159 |
|
160 /* Some old compilers can't initialize structs. */ |
|
161 ret_list = str_list_init (); |
|
162 |
|
163 /* If NAME wasn't found, free the expansion. */ |
|
164 if (name != found) |
|
165 free (name); |
|
166 |
|
167 /* Add `found' to the return list even if it's null; that tells |
|
168 the caller we didn't find anything. */ |
|
169 str_list_add (&ret_list, found); |
|
170 |
|
171 return ret_list; |
|
172 } |
|
173 |
|
174 /* This is the hard case -- look for NAME in PATH. If ALL is false, |
|
175 return the first file found. Otherwise, search all elements of PATH. */ |
|
176 |
|
177 static str_list_type |
|
178 path_search (const char *path, char *name, bool must_exist, bool all) |
|
179 { |
|
180 char *elt; |
|
181 str_list_type ret_list; |
|
182 bool done = false; |
|
183 ret_list = str_list_init (); /* some compilers lack struct initialization */ |
|
184 |
|
185 for (elt = kpse_path_element (path); !done && elt; |
|
186 elt = kpse_path_element (NULL)) { |
|
187 str_list_type *found; |
|
188 bool allow_disk_search = true; |
|
189 |
|
190 if (*elt == '!' && *(elt + 1) == '!') { |
|
191 /* Those magic leading chars in a path element means don't search the |
|
192 disk for this elt. And move past the magic to get to the name. */ |
|
193 allow_disk_search = false; |
|
194 elt += 2; |
|
195 } |
|
196 |
|
197 /* Do not touch the device if present */ |
|
198 if (NAME_BEGINS_WITH_DEVICE (elt)) { |
|
199 while (IS_DIR_SEP (*(elt + 2)) && IS_DIR_SEP (*(elt + 3))) { |
|
200 *(elt + 2) = *(elt + 1); |
|
201 *(elt + 1) = *elt; |
|
202 elt++; |
|
203 } |
|
204 } else { |
|
205 /* We never want to search the whole disk. */ |
|
206 while (IS_DIR_SEP (*elt) && IS_DIR_SEP (*(elt + 1))) |
|
207 elt++; |
|
208 } |
|
209 |
|
210 /* Try ls-R, unless we're searching for texmf.cnf. Our caller |
|
211 (search), also tests first_search, and does the resetting. */ |
|
212 found = first_search ? NULL : kpse_db_search (name, elt, all); |
|
213 |
|
214 /* Search the filesystem if (1) the path spec allows it, and either |
|
215 (2a) we are searching for texmf.cnf ; or |
|
216 (2b) no db exists; or |
|
217 (2c) no db's are relevant to this elt; or |
|
218 (3) MUST_EXIST && NAME was not in the db. |
|
219 In (2*), `found' will be NULL. |
|
220 In (3), `found' will be an empty list. */ |
|
221 if (allow_disk_search && (!found || (must_exist && !STR_LIST (*found)))) { |
|
222 str_llist_type *dirs = kpse_element_dirs (elt); |
|
223 if (dirs && *dirs) { |
|
224 if (!found) |
|
225 found = XTALLOC1 (str_list_type); |
|
226 *found = dir_list_search (dirs, name, all); |
|
227 } |
|
228 } |
|
229 |
|
230 /* Did we find anything anywhere? */ |
|
231 if (found && STR_LIST (*found)) |
|
232 if (all) |
|
233 str_list_concat (&ret_list, *found); |
|
234 else { |
|
235 str_list_add (&ret_list, STR_LIST_ELT (*found, 0)); |
|
236 done = true; |
|
237 } |
|
238 |
|
239 /* Free the list space, if any (but not the elements). */ |
|
240 if (found) { |
|
241 str_list_free (found); |
|
242 free (found); |
|
243 } |
|
244 } |
|
245 |
|
246 /* Free the expanded name we were passed. It can't be in the return |
|
247 list, since the path directories got unconditionally prepended. */ |
|
248 free (name); |
|
249 |
|
250 return ret_list; |
|
251 } |
|
252 |
|
253 /* Search PATH for ORIGINAL_NAME. If ALL is false, or ORIGINAL_NAME is |
|
254 absolute_p, check ORIGINAL_NAME itself. Otherwise, look at each |
|
255 element of PATH for the first readable ORIGINAL_NAME. |
|
256 |
|
257 Always return a list; if no files are found, the list will |
|
258 contain just NULL. If ALL is true, the list will be |
|
259 terminated with NULL. */ |
|
260 |
|
261 static char ** |
|
262 search (const char *path, const char *original_name, |
|
263 bool must_exist, bool all) |
|
264 { |
|
265 str_list_type ret_list; |
|
266 char *name; |
|
267 bool absolute_p; |
|
268 |
|
269 #ifdef __DJGPP__ |
|
270 /* We will use `stat' heavily, so let's request for |
|
271 the fastest possible version of `stat', by telling |
|
272 it what members of struct stat do we really need. |
|
273 |
|
274 We need to set this on each call because this is a |
|
275 library function; the caller might need other options |
|
276 from `stat'. Thus save the flags and restore them |
|
277 before exit. |
|
278 |
|
279 This call tells `stat' that we do NOT need to recognize |
|
280 executable files (neither by an extension nor by a magic |
|
281 signature); that we do NOT need time stamp of root directories; |
|
282 and that we do NOT need the write access bit in st_mode. |
|
283 |
|
284 Note that `kpse_set_progname' needs the EXEC bits, |
|
285 but it was already called by the time we get here. */ |
|
286 unsigned short save_djgpp_flags = _djstat_flags; |
|
287 |
|
288 _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT |
|
289 | _STAT_ROOT_TIME | _STAT_WRITEBIT; |
|
290 #endif |
|
291 |
|
292 /* Make a leading ~ count as an absolute filename, and expand $FOO's. */ |
|
293 name = kpse_expand (original_name); |
|
294 |
|
295 /* If the first name is absolute or explicitly relative, no need to |
|
296 consider PATH at all. */ |
|
297 absolute_p = kpse_absolute_p (name, true); |
|
298 |
|
299 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) |
|
300 DEBUGF4 ("start search(file=%s, must_exist=%d, find_all=%d, path=%s).\n", |
|
301 name, must_exist, all, path); |
|
302 |
|
303 /* Find the file(s). */ |
|
304 ret_list = absolute_p ? absolute_search (name) |
|
305 : path_search (path, name, must_exist, all); |
|
306 |
|
307 /* Append NULL terminator if we didn't find anything at all, or we're |
|
308 supposed to find ALL and the list doesn't end in NULL now. */ |
|
309 if (STR_LIST_LENGTH (ret_list) == 0 |
|
310 || (all && STR_LIST_LAST_ELT (ret_list) != NULL)) |
|
311 str_list_add (&ret_list, NULL); |
|
312 |
|
313 /* The very first search is for texmf.cnf. We can't log that, since |
|
314 we want to allow setting TEXMFLOG in texmf.cnf. */ |
|
315 if (first_search) { |
|
316 first_search = false; |
|
317 } else { |
|
318 /* Record the filenames we found, if desired. And wrap them in a |
|
319 debugging line if we're doing that. */ |
|
320 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) |
|
321 DEBUGF1 ("search(%s) =>", original_name); |
|
322 log_search (ret_list); |
|
323 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) |
|
324 putc ('\n', stderr); |
|
325 } |
|
326 |
|
327 #ifdef __DJGPP__ |
|
328 /* Undo any side effects. */ |
|
329 _djstat_flags = save_djgpp_flags; |
|
330 #endif |
|
331 |
|
332 return STR_LIST (ret_list); |
|
333 } |
|
334 |
|
335 /* Search PATH for the first NAME. */ |
|
336 |
|
337 char * |
|
338 kpse_path_search (const char *path, const char *name, bool must_exist) |
|
339 { |
|
340 static char **ret_list = 0; |
|
341 |
|
342 if (ret_list) |
|
343 { |
|
344 free (ret_list); |
|
345 ret_list = 0; /* Don't let an interrupt in search() cause trouble */ |
|
346 } |
|
347 |
|
348 ret_list = search (path, name, must_exist, false); |
|
349 |
|
350 return *ret_list; /* Freeing this is caller's responsibility */ |
|
351 } |
|
352 |
|
353 |
|
354 /* Search all elements of PATH for files named NAME. Not sure if it's |
|
355 right to assert `must_exist' here, but it suffices now. */ |
|
356 |
|
357 char ** |
|
358 kpse_all_path_search (const char *path, const char *name) |
|
359 { |
|
360 char **ret = search (path, name, true, true); |
|
361 return ret; |
|
362 } |
|
363 |
|
364 /* This is the hard case -- look in each element of PATH for each |
|
365 element of NAMES. If ALL is false, return the first file found. |
|
366 Otherwise, search all elements of PATH. */ |
|
367 |
|
368 static str_list_type |
|
369 path_find_first_of (const char *path, const char **names, |
|
370 bool must_exist, bool all) |
|
371 { |
|
372 const char **p; |
|
373 char *elt; |
|
374 const char *name; |
|
375 str_list_type ret_list; |
|
376 bool done = false; |
|
377 ret_list = str_list_init (); /* some compilers lack struct initialization */ |
|
378 |
|
379 for (elt = kpse_path_element (path); !done && elt; |
|
380 elt = kpse_path_element (NULL)) |
|
381 { |
|
382 str_llist_type *dirs; |
|
383 str_llist_elt_type *dirs_elt; |
|
384 str_list_type *found; |
|
385 bool allow_disk_search = true; |
|
386 |
|
387 if (*elt == '!' && *(elt + 1) == '!') |
|
388 { |
|
389 /* Those magic leading chars in a path element means don't |
|
390 search the disk for this elt. And move past the magic to |
|
391 get to the name. */ |
|
392 |
|
393 allow_disk_search = false; |
|
394 elt += 2; |
|
395 } |
|
396 |
|
397 /* Do not touch the device if present */ |
|
398 |
|
399 if (NAME_BEGINS_WITH_DEVICE (elt)) |
|
400 { |
|
401 while (IS_DIR_SEP (*(elt + 2)) && IS_DIR_SEP (*(elt + 3))) |
|
402 { |
|
403 *(elt + 2) = *(elt + 1); |
|
404 *(elt + 1) = *elt; |
|
405 elt++; |
|
406 } |
|
407 } |
|
408 else |
|
409 { |
|
410 /* We never want to search the whole disk. */ |
|
411 while (IS_DIR_SEP (*elt) && IS_DIR_SEP (*(elt + 1))) |
|
412 elt++; |
|
413 } |
|
414 |
|
415 /* We have to search one directory at a time. */ |
|
416 dirs = kpse_element_dirs (elt); |
|
417 for (dirs_elt = *dirs; dirs_elt; dirs_elt = STR_LLIST_NEXT (*dirs_elt)) |
|
418 { |
|
419 char *dir = STR_LLIST (*dirs_elt); |
|
420 |
|
421 for (p = names; !done && *p; p++) |
|
422 { |
|
423 name = *p; |
|
424 |
|
425 /* Try ls-R, unless we're searching for texmf.cnf. Our caller |
|
426 (find_first_of), also tests first_search, and does the |
|
427 resetting. */ |
|
428 found = first_search ? NULL : kpse_db_search (name, dir, all); |
|
429 |
|
430 /* Search the filesystem if (1) the path spec allows it, |
|
431 and either |
|
432 |
|
433 (2a) we are searching for texmf.cnf ; or |
|
434 (2b) no db exists; or |
|
435 (2c) no db's are relevant to this elt; or |
|
436 (3) MUST_EXIST && NAME was not in the db. |
|
437 |
|
438 In (2*), `found' will be NULL. |
|
439 In (3), `found' will be an empty list. */ |
|
440 |
|
441 if (allow_disk_search |
|
442 && (!found || (must_exist && !STR_LIST (*found)))) |
|
443 { |
|
444 static str_llist_type *tmp = 0; |
|
445 |
|
446 if (! tmp) |
|
447 { |
|
448 tmp = XTALLOC1 (str_llist_type); |
|
449 *tmp = NULL; |
|
450 str_llist_add (tmp, ""); |
|
451 } |
|
452 |
|
453 STR_LLIST (*(*tmp)) = dir; |
|
454 |
|
455 if (!found) |
|
456 found = XTALLOC1 (str_list_type); |
|
457 |
|
458 *found = dir_list_search (tmp, name, all); |
|
459 } |
|
460 |
|
461 /* Did we find anything anywhere? */ |
|
462 if (found && STR_LIST (*found)) |
|
463 { |
|
464 if (all) |
|
465 str_list_concat (&ret_list, *found); |
|
466 else |
|
467 { |
|
468 str_list_add (&ret_list, STR_LIST_ELT (*found, 0)); |
|
469 done = true; |
|
470 } |
|
471 } |
|
472 |
|
473 /* Free the list space, if any (but not the elements). */ |
|
474 if (found) |
|
475 { |
|
476 str_list_free (found); |
|
477 free (found); |
|
478 } |
|
479 } |
|
480 } |
|
481 } |
|
482 |
|
483 return ret_list; |
|
484 } |
|
485 |
|
486 static char ** |
|
487 find_first_of (const char *path, const char **names, |
|
488 bool must_exist, bool all) |
|
489 { |
|
490 str_list_type ret_list; |
|
491 |
|
492 #ifdef __DJGPP__ |
|
493 /* We will use `stat' heavily, so let's request for |
|
494 the fastest possible version of `stat', by telling |
|
495 it what members of struct stat do we really need. |
|
496 |
|
497 We need to set this on each call because this is a |
|
498 library function; the caller might need other options |
|
499 from `stat'. Thus save the flags and restore them |
|
500 before exit. |
|
501 |
|
502 This call tells `stat' that we do NOT need to recognize |
|
503 executable files (neither by an extension nor by a magic |
|
504 signature); that we do NOT need time stamp of root directories; |
|
505 and that we do NOT need the write access bit in st_mode. |
|
506 |
|
507 Note that `kpse_set_progname' needs the EXEC bits, |
|
508 but it was already called by the time we get here. */ |
|
509 unsigned short save_djgpp_flags = _djstat_flags; |
|
510 |
|
511 _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT |
|
512 | _STAT_ROOT_TIME | _STAT_WRITEBIT; |
|
513 #endif |
|
514 |
|
515 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) |
|
516 { |
|
517 const char **p; |
|
518 fputs ("start find_first_of((", stderr); |
|
519 for (p = names; *p; p++) |
|
520 { |
|
521 if (p == names) |
|
522 fputs (*p, stderr); |
|
523 else |
|
524 fprintf (stderr, ", %s", *p); |
|
525 } |
|
526 fprintf (stderr, "), path=%s, must_exist=%d).\n", path, must_exist); |
|
527 } |
|
528 |
|
529 /* Find the file. */ |
|
530 ret_list = path_find_first_of (path, names, must_exist, all); |
|
531 |
|
532 /* Append NULL terminator if we didn't find anything at all, or we're |
|
533 supposed to find ALL and the list doesn't end in NULL now. */ |
|
534 if (STR_LIST_LENGTH (ret_list) == 0 |
|
535 || (all && STR_LIST_LAST_ELT (ret_list) != NULL)) |
|
536 str_list_add (&ret_list, NULL); |
|
537 |
|
538 /* The very first search is for texmf.cnf. We can't log that, since |
|
539 we want to allow setting TEXMFLOG in texmf.cnf. */ |
|
540 if (first_search) { |
|
541 first_search = false; |
|
542 } else { |
|
543 /* Record the filenames we found, if desired. And wrap them in a |
|
544 debugging line if we're doing that. */ |
|
545 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) |
|
546 { |
|
547 const char **p; |
|
548 fputs ("find_first_of(", stderr); |
|
549 for (p = names; *p; p++) |
|
550 { |
|
551 if (p == names) |
|
552 fputs (*p, stderr); |
|
553 else |
|
554 fprintf (stderr, ", %s", *p); |
|
555 } |
|
556 fputs (") =>", stderr); |
|
557 } |
|
558 log_search (ret_list); |
|
559 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) |
|
560 putc ('\n', stderr); |
|
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 each element of PATH for each element of NAMES. Return the |
|
572 first one found. */ |
|
573 |
|
574 char * |
|
575 kpse_path_find_first_of (const char *path, const char **names, |
|
576 bool must_exist) |
|
577 { |
|
578 static char **ret_list = 0; |
|
579 |
|
580 if (ret_list) |
|
581 { |
|
582 free (ret_list); |
|
583 ret_list = 0; /* Don't let an interrupt in search() cause trouble */ |
|
584 } |
|
585 |
|
586 ret_list = find_first_of (path, names, must_exist, false); |
|
587 |
|
588 return *ret_list; /* Freeing this is caller's responsibility */ |
|
589 } |
|
590 |
|
591 /* Search each element of PATH for each element of NAMES and return a |
|
592 list containing everything found, in the order found. */ |
|
593 |
|
594 char ** |
|
595 kpse_all_path_find_first_of (const char *path, const char **names) |
|
596 { |
|
597 char **ret = find_first_of (path, names, true, true); |
|
598 return ret; |
|
599 } |
|
600 |
|
601 /* expand.c: general expansion. Some of this file (the brace-expansion |
|
602 code from bash) is covered by the GPL; this is the only GPL-covered |
|
603 code in kpathsea. The part of the file that I wrote (the first |
|
604 couple of functions) is covered by the LGPL. */ |
|
605 |
|
606 #ifdef HAVE_PWD_H |
|
607 #include <pwd.h> |
|
608 #endif |
|
609 |
|
610 /* If NAME has a leading ~ or ~user, Unix-style, expand it to the user's |
|
611 home directory, and return a new malloced string. If no ~, or no |
|
612 <pwd.h>, just return NAME. */ |
|
613 |
|
614 static char * |
|
615 kpse_tilde_expand (const char *name) |
|
616 { |
|
617 const char *expansion; |
|
618 const char *home; |
|
619 |
|
620 assert (name); |
|
621 |
|
622 /* If no leading tilde, do nothing. */ |
|
623 if (*name != '~') { |
|
624 expansion = name; |
|
625 |
|
626 /* If a bare tilde, return the home directory or `.'. (Very unlikely |
|
627 that the directory name will do anyone any good, but ... */ |
|
628 } else if (name[1] == 0) { |
|
629 expansion = xstrdup (getenv ("HOME")); |
|
630 if (!expansion) { |
|
631 expansion = xstrdup ("."); |
|
632 } |
|
633 |
|
634 /* If `~/', remove any trailing / or replace leading // in $HOME. |
|
635 Should really check for doubled intermediate slashes, too. */ |
|
636 } else if (IS_DIR_SEP (name[1])) { |
|
637 unsigned c = 1; |
|
638 home = getenv ("HOME"); |
|
639 if (!home) { |
|
640 home = "."; |
|
641 } |
|
642 if (IS_DIR_SEP (*home) && IS_DIR_SEP (home[1])) { /* handle leading // */ |
|
643 home++; |
|
644 } |
|
645 if (IS_DIR_SEP (home[strlen (home) - 1])) { /* omit / after ~ */ |
|
646 c++; |
|
647 } |
|
648 expansion = concat (home, name + c); |
|
649 |
|
650 /* If `~user' or `~user/', look up user in the passwd database (but |
|
651 OS/2 doesn't have this concept. */ |
|
652 } else |
|
653 #ifdef HAVE_PWD_H |
|
654 { |
|
655 struct passwd *p; |
|
656 char *user; |
|
657 unsigned c = 2; |
|
658 while (!IS_DIR_SEP (name[c]) && name[c] != 0) /* find user name */ |
|
659 c++; |
|
660 |
|
661 user = (char *) xmalloc (c); |
|
662 strncpy (user, name + 1, c - 1); |
|
663 user[c - 1] = 0; |
|
664 |
|
665 /* We only need the cast here for (deficient) systems |
|
666 which do not declare `getpwnam' in <pwd.h>. */ |
|
667 p = (struct passwd *) getpwnam (user); |
|
668 free (user); |
|
669 |
|
670 /* If no such user, just use `.'. */ |
|
671 home = p ? p->pw_dir : "."; |
|
672 if (IS_DIR_SEP (*home) && IS_DIR_SEP (home[1])) { /* handle leading // */ |
|
673 home++; |
|
674 } |
|
675 if (IS_DIR_SEP (home[strlen (home) - 1]) && name[c] != 0) |
|
676 c++; /* If HOME ends in /, omit the / after ~user. */ |
|
677 |
|
678 expansion = name[c] == 0 ? xstrdup (home) : concat (home, name + c); |
|
679 } |
|
680 #else /* not HAVE_PWD_H */ |
|
681 expansion = name; |
|
682 #endif /* not HAVE_PWD_H */ |
|
683 |
|
684 /* We may return the same thing as the original, and then we might not |
|
685 be returning a malloc-ed string. Callers beware. Sorry. */ |
|
686 return (char *) expansion; |
|
687 } |
|
688 |
|
689 /* Do variable expansion first so ~${USER} works. (Besides, it's what the |
|
690 shells do.) */ |
|
691 |
|
692 char * |
|
693 kpse_expand (const char *s) |
|
694 { |
|
695 char *var_expansion = kpse_var_expand (s); |
|
696 char *tilde_expansion = kpse_tilde_expand (var_expansion); |
|
697 |
|
698 /* `kpse_var_expand' always gives us new memory; `kpse_tilde_expand' |
|
699 doesn't, necessarily. So be careful that we don't free what we are |
|
700 about to return. */ |
|
701 if (tilde_expansion != var_expansion) |
|
702 free (var_expansion); |
|
703 |
|
704 return tilde_expansion; |
|
705 } |
|
706 |
|
707 |
|
708 /* Forward declarations of functions from the original expand.c */ |
|
709 static char **brace_expand (const char *); |
|
710 static void free_array (char **); |
|
711 |
|
712 /* If $KPSE_DOT is defined in the environment, prepend it to any relative |
|
713 path components. */ |
|
714 |
|
715 static char * |
|
716 kpse_expand_kpse_dot (char *path) |
|
717 { |
|
718 char *ret, *elt; |
|
719 char *kpse_dot = getenv("KPSE_DOT"); |
|
720 #ifdef MSDOS |
|
721 bool malloced_kpse_dot = false; |
|
722 #endif |
|
723 |
|
724 if (kpse_dot == NULL) |
|
725 return path; |
|
726 ret = (char *) xmalloc(1); |
|
727 *ret = 0; |
|
728 |
|
729 #ifdef MSDOS |
|
730 /* Some setups of ported Bash force $KPSE_DOT to have the //d/foo/bar |
|
731 form (when `pwd' is used), which is not understood by libc and the OS. |
|
732 Convert them back to the usual d:/foo/bar form. */ |
|
733 if (kpse_dot[0] == '/' && kpse_dot[1] == '/' |
|
734 && kpse_dot[2] >= 'A' && kpse_dot[2] <= 'z' && kpse_dot[3] == '/') { |
|
735 kpse_dot++; |
|
736 kpse_dot = xstrdup (kpse_dot); |
|
737 kpse_dot[0] = kpse_dot[1]; /* drive letter */ |
|
738 kpse_dot[1] = ':'; |
|
739 malloced_kpse_dot = true; |
|
740 } |
|
741 #endif |
|
742 |
|
743 for (elt = kpse_path_element (path); elt; elt = kpse_path_element (NULL)) { |
|
744 char *save_ret = ret; |
|
745 /* We assume that the !! magic is only used on absolute components. |
|
746 Single "." get special treatment, as does "./" or its equivalent. */ |
|
747 if (kpse_absolute_p (elt, false) || (elt[0] == '!' && elt[1] == '!')) { |
|
748 ret = concat3(ret, elt, ENV_SEP_STRING); |
|
749 } else if (elt[0] == '.' && elt[1] == 0) { |
|
750 ret = concat3 (ret, kpse_dot, ENV_SEP_STRING); |
|
751 } else if (elt[0] == '.' && IS_DIR_SEP(elt[1])) { |
|
752 ret = concatn (ret, kpse_dot, elt + 1, ENV_SEP_STRING, NULL); |
|
753 } else { |
|
754 ret = concatn (ret, kpse_dot, DIR_SEP_STRING, elt, ENV_SEP_STRING, NULL); |
|
755 } |
|
756 free (save_ret); |
|
757 } |
|
758 |
|
759 #ifdef MSDOS |
|
760 if (malloced_kpse_dot) free (kpse_dot); |
|
761 #endif |
|
762 |
|
763 ret[strlen (ret) - 1] = 0; |
|
764 return ret; |
|
765 } |
|
766 |
|
767 /* Do brace expansion on ELT; then do variable and ~ expansion on each |
|
768 element of the result; then do brace expansion again, in case a |
|
769 variable definition contained braces (e.g., $TEXMF). Return a |
|
770 string comprising all of the results separated by ENV_SEP_STRING. */ |
|
771 |
|
772 static char * |
|
773 kpse_brace_expand_element (const char *elt) |
|
774 { |
|
775 unsigned i; |
|
776 char **expansions = brace_expand (elt); |
|
777 char *ret = (char *) xmalloc (1); |
|
778 *ret = 0; |
|
779 |
|
780 for (i = 0; expansions[i]; i++) { |
|
781 /* Do $ and ~ expansion on each element. */ |
|
782 char *x = kpse_expand (expansions[i]); |
|
783 char *save_ret = ret; |
|
784 if (!STREQ (x, expansions[i])) { |
|
785 /* If we did any expansions, do brace expansion again. Since |
|
786 recursive variable definitions are not allowed, this recursion |
|
787 must terminate. (In practice, it's unlikely there will ever be |
|
788 more than one level of recursion.) */ |
|
789 char *save_x = x; |
|
790 x = kpse_brace_expand_element (x); |
|
791 free (save_x); |
|
792 } |
|
793 ret = concat3 (ret, x, ENV_SEP_STRING); |
|
794 free (save_ret); |
|
795 free (x); |
|
796 } |
|
797 |
|
798 free_array (expansions); |
|
799 ret[strlen (ret) - 1] = 0; /* waste the trailing null */ |
|
800 return ret; |
|
801 } |
|
802 |
|
803 /* Be careful to not waste all the memory we allocate for each element. */ |
|
804 |
|
805 char * |
|
806 kpse_brace_expand (const char *path) |
|
807 { |
|
808 char *kpse_dot_expansion; |
|
809 char *elt; |
|
810 unsigned len; |
|
811 /* Must do variable expansion first because if we have |
|
812 foo = .:~ |
|
813 TEXINPUTS = $foo |
|
814 we want to end up with TEXINPUTS = .:/home/karl. |
|
815 Since kpse_path_element is not reentrant, we must get all |
|
816 the path elements before we start the loop. */ |
|
817 char *xpath = kpse_var_expand (path); |
|
818 char *ret = (char *) xmalloc (1); |
|
819 *ret = 0; |
|
820 |
|
821 for (elt = kpse_path_element (xpath); elt; elt = kpse_path_element (NULL)) { |
|
822 char *save_ret = ret; |
|
823 /* Do brace expansion first, so tilde expansion happens in {~ka,~kb}. */ |
|
824 char *expansion = kpse_brace_expand_element (elt); |
|
825 ret = concat3 (ret, expansion, ENV_SEP_STRING); |
|
826 free (expansion); |
|
827 free (save_ret); |
|
828 } |
|
829 |
|
830 /* Waste the last byte by overwriting the trailing env_sep with a null. */ |
|
831 len = strlen (ret); |
|
832 if (len != 0) |
|
833 ret[len - 1] = 0; |
|
834 free (xpath); |
|
835 |
|
836 kpse_dot_expansion = kpse_expand_kpse_dot (ret); |
|
837 if (kpse_dot_expansion != ret) |
|
838 free (ret); |
|
839 |
|
840 return kpse_dot_expansion; |
|
841 } |
|
842 |
|
843 /* Expand all special constructs in a path, and include only the actually |
|
844 existing directories in the result. */ |
|
845 char * |
|
846 kpse_path_expand (const char *path) |
|
847 { |
|
848 char *ret; |
|
849 char *xpath; |
|
850 char *elt; |
|
851 unsigned len; |
|
852 |
|
853 /* Initialise ret to the empty string. */ |
|
854 ret = (char *) xmalloc (1); |
|
855 *ret = 0; |
|
856 len = 0; |
|
857 |
|
858 /* Expand variables and braces first. */ |
|
859 xpath = kpse_brace_expand (path); |
|
860 |
|
861 /* Now expand each of the path elements, printing the results */ |
|
862 for (elt = kpse_path_element (xpath); elt; elt = kpse_path_element (NULL)) { |
|
863 str_llist_type *dirs; |
|
864 |
|
865 /* Skip and ignore magic leading chars. */ |
|
866 if (*elt == '!' && *(elt + 1) == '!') |
|
867 elt += 2; |
|
868 |
|
869 /* Do not touch the device if present */ |
|
870 if (NAME_BEGINS_WITH_DEVICE (elt)) { |
|
871 while (IS_DIR_SEP (*(elt + 2)) && IS_DIR_SEP (*(elt + 3))) { |
|
872 *(elt + 2) = *(elt + 1); |
|
873 *(elt + 1) = *elt; |
|
874 elt++; |
|
875 } |
|
876 } else { |
|
877 /* We never want to search the whole disk. */ |
|
878 while (IS_DIR_SEP (*elt) && IS_DIR_SEP (*(elt + 1))) |
|
879 elt++; |
|
880 } |
|
881 |
|
882 /* Search the disk for all dirs in the component specified. |
|
883 Be faster to check the database, but this is more reliable. */ |
|
884 dirs = kpse_element_dirs (elt); |
|
885 if (dirs && *dirs) { |
|
886 str_llist_elt_type *dir; |
|
887 |
|
888 for (dir = *dirs; dir; dir = STR_LLIST_NEXT (*dir)) { |
|
889 char *thedir = STR_LLIST (*dir); |
|
890 unsigned dirlen = strlen (thedir); |
|
891 char *save_ret = ret; |
|
892 /* Retain trailing slash if that's the root directory. */ |
|
893 if (dirlen == 1 || (dirlen == 3 && NAME_BEGINS_WITH_DEVICE (thedir) |
|
894 && IS_DIR_SEP (thedir[2]))) { |
|
895 ret = concat3 (ret, thedir, ENV_SEP_STRING); |
|
896 len += dirlen + 1; |
|
897 ret[len - 1] = ENV_SEP; |
|
898 } else { |
|
899 ret = concat (ret, thedir); |
|
900 len += dirlen; |
|
901 ret [len - 1] = ENV_SEP; |
|
902 } |
|
903 free (save_ret); |
|
904 } |
|
905 } |
|
906 } |
|
907 /* Get rid of trailing ':', if any. */ |
|
908 if (len != 0) |
|
909 ret[len - 1] = 0; |
|
910 return ret; |
|
911 } |
|
912 |
|
913 /* braces.c -- code for doing word expansion in curly braces. Taken from |
|
914 bash 1.14.5. [Ans subsequently modified for kpatshea.] |
|
915 |
|
916 Copyright (C) 1987,1991 Free Software Foundation, Inc. |
|
917 |
|
918 This program is free software; you can redistribute it and/or modify it |
|
919 under the terms of the GNU General Public License as published by |
|
920 the Free Software Foundation; either version 1, or (at your option) |
|
921 any later version. |
|
922 |
|
923 This program is distributed in the hope that it will be useful, but |
|
924 WITHOUT ANY WARRANTY; without even the implied warranty of |
|
925 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
926 General Public License for more details. |
|
927 |
|
928 You should have received a copy of the GNU General Public License |
|
929 along with this program; see the file COPYING. If not, write to the |
|
930 Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
|
931 MA 02111-1307, USA. */ |
|
932 |
|
933 |
|
934 #define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n') |
|
935 #define savestring xstrdup |
|
936 |
|
937 /* Basic idea: |
|
938 |
|
939 Segregate the text into 3 sections: preamble (stuff before an open brace), |
|
940 postamble (stuff after the matching close brace) and amble (stuff after |
|
941 preamble, and before postamble). Expand amble, and then tack on the |
|
942 expansions to preamble. Expand postamble, and tack on the expansions to |
|
943 the result so far. |
|
944 */ |
|
945 |
|
946 /* The character which is used to separate arguments. */ |
|
947 static int brace_arg_separator = ','; |
|
948 |
|
949 static int brace_gobbler (const char *, int *, int); |
|
950 static char **expand_amble (const char *), |
|
951 **array_concat (char **, char **); |
|
952 |
|
953 /* Return the length of ARRAY, a NULL terminated array of char *. */ |
|
954 static int |
|
955 array_len (char **array) |
|
956 { |
|
957 register int i; |
|
958 for (i = 0; array[i]; i++); |
|
959 return (i); |
|
960 } |
|
961 |
|
962 /* Free the contents of ARRAY, a NULL terminated array of char *. */ |
|
963 static void |
|
964 free_array (char **array) |
|
965 { |
|
966 register int i = 0; |
|
967 |
|
968 if (!array) return; |
|
969 |
|
970 while (array[i]) |
|
971 free (array[i++]); |
|
972 free (array); |
|
973 } |
|
974 |
|
975 /* Allocate and return a new copy of ARRAY and its contents. */ |
|
976 static char ** |
|
977 copy_array (char **array) |
|
978 { |
|
979 register int i; |
|
980 int len; |
|
981 char **new_array; |
|
982 |
|
983 len = array_len (array); |
|
984 |
|
985 new_array = (char **)xmalloc ((len + 1) * sizeof (char *)); |
|
986 for (i = 0; array[i]; i++) |
|
987 new_array[i] = savestring (array[i]); |
|
988 new_array[i] = (char *)NULL; |
|
989 |
|
990 return (new_array); |
|
991 } |
|
992 |
|
993 |
|
994 /* Return an array of strings; the brace expansion of TEXT. */ |
|
995 static char ** |
|
996 brace_expand (const char *text) |
|
997 { |
|
998 register int start; |
|
999 char *preamble, *amble; |
|
1000 const char *postamble; |
|
1001 char **tack, **result; |
|
1002 int i, c; |
|
1003 |
|
1004 /* Find the text of the preamble. */ |
|
1005 i = 0; |
|
1006 c = brace_gobbler (text, &i, '{'); |
|
1007 |
|
1008 preamble = (char *) xmalloc (i + 1); |
|
1009 strncpy (preamble, text, i); |
|
1010 preamble[i] = 0; |
|
1011 |
|
1012 result = (char **) xmalloc (2 * sizeof (char *)); |
|
1013 result[0] = preamble; |
|
1014 result[1] = NULL; |
|
1015 |
|
1016 /* Special case. If we never found an exciting character, then |
|
1017 the preamble is all of the text, so just return that. */ |
|
1018 if (c != '{') |
|
1019 return (result); |
|
1020 |
|
1021 /* Find the amble. This is the stuff inside this set of braces. */ |
|
1022 start = ++i; |
|
1023 c = brace_gobbler (text, &i, '}'); |
|
1024 |
|
1025 /* What if there isn't a matching close brace? */ |
|
1026 if (!c) |
|
1027 { |
|
1028 WARNING1 ("%s: Unmatched {", text); |
|
1029 free (preamble); /* Same as result[0]; see initialization. */ |
|
1030 result[0] = savestring (text); |
|
1031 return (result); |
|
1032 } |
|
1033 |
|
1034 amble = (char *) xmalloc (1 + (i - start)); |
|
1035 strncpy (amble, &text[start], (i - start)); |
|
1036 amble[i - start] = 0; |
|
1037 |
|
1038 postamble = &text[i + 1]; |
|
1039 |
|
1040 tack = expand_amble (amble); |
|
1041 result = array_concat (result, tack); |
|
1042 free (amble); |
|
1043 free_array (tack); |
|
1044 |
|
1045 tack = brace_expand (postamble); |
|
1046 result = array_concat (result, tack); |
|
1047 free_array (tack); |
|
1048 |
|
1049 return (result); |
|
1050 } |
|
1051 |
|
1052 |
|
1053 /* Expand the text found inside of braces. We simply try to split the |
|
1054 text at BRACE_ARG_SEPARATORs into separate strings. We then brace |
|
1055 expand each slot which needs it, until there are no more slots which |
|
1056 need it. */ |
|
1057 static char ** |
|
1058 expand_amble (const char *text) |
|
1059 { |
|
1060 char **result, **partial; |
|
1061 char *tem; |
|
1062 int start, i, c; |
|
1063 |
|
1064 result = NULL; |
|
1065 |
|
1066 for (start = 0, i = 0, c = 1; c; start = ++i) |
|
1067 { |
|
1068 int c0, c1; |
|
1069 int i0, i1; |
|
1070 i0 = i; |
|
1071 c0 = brace_gobbler (text, &i0, brace_arg_separator); |
|
1072 i1 = i; |
|
1073 c1 = brace_gobbler (text, &i1, ENV_SEP); |
|
1074 c = c0 | c1; |
|
1075 i = (i0 < i1 ? i0 : i1); |
|
1076 |
|
1077 tem = (char *) xmalloc (1 + (i - start)); |
|
1078 strncpy (tem, &text[start], (i - start)); |
|
1079 tem[i- start] = 0; |
|
1080 |
|
1081 partial = brace_expand (tem); |
|
1082 |
|
1083 if (!result) |
|
1084 result = partial; |
|
1085 else |
|
1086 { |
|
1087 register int lr = array_len (result); |
|
1088 register int lp = array_len (partial); |
|
1089 register int j; |
|
1090 |
|
1091 result = (char **) xrealloc (result, (1 + lp + lr) * sizeof (char *)); |
|
1092 |
|
1093 for (j = 0; j < lp; j++) |
|
1094 result[lr + j] = partial[j]; |
|
1095 |
|
1096 result[lr + j] = NULL; |
|
1097 free (partial); |
|
1098 } |
|
1099 free (tem); |
|
1100 } |
|
1101 return (result); |
|
1102 } |
|
1103 |
|
1104 /* Return a new array of strings which is the result of appending each |
|
1105 string in ARR2 to each string in ARR1. The resultant array is |
|
1106 len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents) |
|
1107 are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2 |
|
1108 is returned. */ |
|
1109 static char ** |
|
1110 array_concat (char **arr1, char **arr2) |
|
1111 { |
|
1112 register int i, j, len, len1, len2; |
|
1113 register char **result; |
|
1114 |
|
1115 if (!arr1) |
|
1116 return (copy_array (arr2)); |
|
1117 |
|
1118 if (!arr2) |
|
1119 return (copy_array (arr1)); |
|
1120 |
|
1121 len1 = array_len (arr1); |
|
1122 len2 = array_len (arr2); |
|
1123 |
|
1124 result = (char **) xmalloc ((1 + (len1 * len2)) * sizeof (char *)); |
|
1125 |
|
1126 len = 0; |
|
1127 for (i = 0; i < len2; i++) |
|
1128 { |
|
1129 int strlen_2 = strlen (arr2[i]); |
|
1130 |
|
1131 for (j = 0; j < len1; j++) |
|
1132 { |
|
1133 int strlen_1 = strlen (arr1[j]); |
|
1134 |
|
1135 result[len] = (char *) xmalloc (1 + strlen_1 + strlen_2); |
|
1136 strcpy (result[len], arr1[j]); |
|
1137 strcpy (result[len] + strlen_1, arr2[i]); |
|
1138 len++; |
|
1139 } |
|
1140 } |
|
1141 free_array (arr1); |
|
1142 |
|
1143 result[len] = NULL; |
|
1144 return (result); |
|
1145 } |
|
1146 |
|
1147 /* Start at INDEX, and skip characters in TEXT. Set INDEX to the |
|
1148 index of the character matching SATISFY. This understands about |
|
1149 quoting. Return the character that caused us to stop searching; |
|
1150 this is either the same as SATISFY, or 0. */ |
|
1151 static int |
|
1152 brace_gobbler (const char *text, int *indx, int satisfy) |
|
1153 { |
|
1154 register int i, c, quoted, level, pass_next; |
|
1155 |
|
1156 level = quoted = pass_next = 0; |
|
1157 |
|
1158 for (i = *indx; (c = text[i]); i++) |
|
1159 { |
|
1160 if (pass_next) |
|
1161 { |
|
1162 pass_next = 0; |
|
1163 continue; |
|
1164 } |
|
1165 |
|
1166 /* A backslash escapes the next character. This allows backslash to |
|
1167 escape the quote character in a double-quoted string. */ |
|
1168 if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`')) |
|
1169 { |
|
1170 pass_next = 1; |
|
1171 continue; |
|
1172 } |
|
1173 |
|
1174 if (quoted) |
|
1175 { |
|
1176 if (c == quoted) |
|
1177 quoted = 0; |
|
1178 continue; |
|
1179 } |
|
1180 |
|
1181 if (c == '"' || c == '\'' || c == '`') |
|
1182 { |
|
1183 quoted = c; |
|
1184 continue; |
|
1185 } |
|
1186 |
|
1187 if (c == satisfy && !level && !quoted) |
|
1188 { |
|
1189 /* We ignore an open brace surrounded by whitespace, and also |
|
1190 an open brace followed immediately by a close brace, that |
|
1191 was preceded with whitespace. */ |
|
1192 if (c == '{' && |
|
1193 ((!i || brace_whitespace (text[i - 1])) && |
|
1194 (brace_whitespace (text[i + 1]) || text[i + 1] == '}'))) |
|
1195 continue; |
|
1196 /* If this is being compiled as part of bash, ignore the `{' |
|
1197 in a `${}' construct */ |
|
1198 if ((c != '{') || !i || (text[i - 1] != '$')) |
|
1199 break; |
|
1200 } |
|
1201 |
|
1202 if (c == '{') |
|
1203 level++; |
|
1204 else if (c == '}' && level) |
|
1205 level--; |
|
1206 } |
|
1207 |
|
1208 *indx = i; |
|
1209 return (c); |
|
1210 } |
|
1211 |
|
1212 /* db.c: an external database to avoid filesystem lookups. */ |
|
1213 |
|
1214 #ifndef DEFAULT_TEXMFDBS |
|
1215 #define DEFAULT_TEXMFDBS "/usr/local/share/texmf:/var/tmp/texfonts" |
|
1216 #endif |
|
1217 |
|
1218 /* Perhaps we could use this for path values themselves; for now, we use |
|
1219 it only for the program_enabled_p value. */ |
|
1220 typedef enum |
|
1221 { |
|
1222 kpse_src_implicit, /* C initialization to zero */ |
|
1223 kpse_src_compile, /* configure/compile-time default */ |
|
1224 kpse_src_texmf_cnf, /* texmf.cnf, the kpathsea config file */ |
|
1225 kpse_src_client_cnf, /* application config file, e.g., config.ps */ |
|
1226 kpse_src_env, /* environment variable */ |
|
1227 kpse_src_x, /* X Window System resource */ |
|
1228 kpse_src_cmdline /* command-line option */ |
|
1229 } kpse_src_type; |
|
1230 |
|
1231 |
|
1232 /* For each file format, we record the following information. The main |
|
1233 thing that is not part of this structure is the environment variable |
|
1234 lists. They are used directly in tex-file.c. We could incorporate |
|
1235 them here, but it would complicate the code a bit. We could also do |
|
1236 it via variable expansion, but not now, maybe not ever: |
|
1237 ${PKFONTS-${TEXFONTS-/usr/local/lib/texmf/fonts//}}. */ |
|
1238 |
|
1239 typedef struct |
|
1240 { |
|
1241 const char *type; /* Human-readable description. */ |
|
1242 const char *path; /* The search path to use. */ |
|
1243 const char *raw_path; /* Pre-$~ (but post-default) expansion. */ |
|
1244 const char *path_source; /* Where the path started from. */ |
|
1245 const char *override_path; /* From client environment variable. */ |
|
1246 const char *client_path; /* E.g., from dvips's config.ps. */ |
|
1247 const char *cnf_path; /* From texmf.cnf. */ |
|
1248 const char *default_path; /* If all else fails. */ |
|
1249 const char **suffix; /* For kpse_find_file to check for/append. */ |
|
1250 const char **alt_suffix; /* More suffixes to check for. */ |
|
1251 bool suffix_search_only; /* Only search with a suffix? */ |
|
1252 const char *program; /* ``mktexpk'', etc. */ |
|
1253 const char *program_args; /* Args to `program'. */ |
|
1254 bool program_enabled_p; /* Invoke `program'? */ |
|
1255 kpse_src_type program_enable_level; /* Who said to invoke `program'. */ |
|
1256 bool binmode; /* The files must be opened in binary mode. */ |
|
1257 } kpse_format_info_type; |
|
1258 |
|
1259 /* The sole variable of that type, indexed by `kpse_file_format_type'. |
|
1260 Initialized by calls to `kpse_find_file' for `kpse_init_format'. */ |
|
1261 static kpse_format_info_type kpse_format_info; |
|
1262 |
|
1263 #define DB_ENVS "TEXMFDBS" |
|
1264 |
|
1265 /* And EXPAND_DEFAULT calls kpse_expand_default on try_path and the |
|
1266 present info->path. */ |
|
1267 #define EXPAND_DEFAULT(try_path, source_string) \ |
|
1268 if (try_path) { \ |
|
1269 info->raw_path = try_path; \ |
|
1270 info->path = kpse_expand_default (try_path, info->path); \ |
|
1271 info->path_source = source_string; \ |
|
1272 } |
|
1273 |
|
1274 /* Find the final search path to use for the format entry INFO, given |
|
1275 the compile-time default (DEFAULT_PATH), and the environment |
|
1276 variables to check (the remaining arguments, terminated with NULL). |
|
1277 We set the `path' and `path_source' members of INFO. The |
|
1278 `client_path' member must already be set upon entry. */ |
|
1279 |
|
1280 static void |
|
1281 init_path (kpse_format_info_type *info, const char *default_path, ...) |
|
1282 { |
|
1283 char *env_name; |
|
1284 char *var = NULL; |
|
1285 va_list ap; |
|
1286 |
|
1287 va_start (ap, default_path); |
|
1288 |
|
1289 info->default_path = default_path; |
|
1290 |
|
1291 /* First envvar that's set to a nonempty value will exit the loop. If |
|
1292 none are set, we want the first cnf entry that matches. Find the |
|
1293 cnf entries simultaneously, to avoid having to go through envvar |
|
1294 list twice -- because of the PVAR?C macro, that would mean having |
|
1295 to create a str_list and then use it twice. Yuck. */ |
|
1296 while ((env_name = va_arg (ap, char *)) != NULL) { |
|
1297 /* Since sh doesn't like envvar names with `.', check PATH_prog |
|
1298 rather than PATH.prog. */ |
|
1299 if (!var) { |
|
1300 /* Try simply PATH. */ |
|
1301 char *env_value = getenv (env_name); |
|
1302 if (env_value && *env_value) { |
|
1303 var = env_name; |
|
1304 } |
|
1305 } |
|
1306 |
|
1307 if (var && info->cnf_path) |
|
1308 break; |
|
1309 } |
|
1310 va_end (ap); |
|
1311 |
|
1312 /* Expand any extra :'s. For each level, we replace an extra : with |
|
1313 the path at the next lower level. For example, an extra : in a |
|
1314 user-set envvar should be replaced with the path from the cnf file. |
|
1315 things are complicated because none of the levels above the very |
|
1316 bottom are guaranteed to exist. */ |
|
1317 |
|
1318 /* Assume we can reliably start with the compile-time default. */ |
|
1319 info->path = info->raw_path = info->default_path; |
|
1320 info->path_source = "compile-time paths.h"; |
|
1321 |
|
1322 EXPAND_DEFAULT (info->cnf_path, "texmf.cnf"); |
|
1323 EXPAND_DEFAULT (info->client_path, "program config file"); |
|
1324 if (var) |
|
1325 EXPAND_DEFAULT (getenv (var), concat (var, " environment variable")); |
|
1326 EXPAND_DEFAULT (info->override_path, "application override variable"); |
|
1327 info->path = kpse_brace_expand (info->path); |
|
1328 } |
|
1329 |
|
1330 |
|
1331 /* Some file types have more than one suffix. */ |
|
1332 |
|
1333 static void |
|
1334 add_suffixes (const char ***list, ...) |
|
1335 { |
|
1336 const char *s; |
|
1337 unsigned count = 0; |
|
1338 va_list ap; |
|
1339 |
|
1340 va_start (ap, list); |
|
1341 |
|
1342 while ((s = va_arg (ap, char *)) != NULL) { |
|
1343 count++; |
|
1344 XRETALLOC (*list, count + 1, const char *); |
|
1345 (*list)[count - 1] = s; |
|
1346 } |
|
1347 va_end (ap); |
|
1348 (*list)[count] = NULL; |
|
1349 } |
|
1350 |
|
1351 |
|
1352 static char * |
|
1353 remove_dbonly (const char *path) |
|
1354 { |
|
1355 char *ret = XTALLOC(strlen (path) + 1, char), *q=ret; |
|
1356 const char *p=path; |
|
1357 bool new_elt=true; |
|
1358 |
|
1359 while (*p) { |
|
1360 if (new_elt && *p && *p == '!' && *(p+1) == '!') |
|
1361 p += 2; |
|
1362 else { |
|
1363 new_elt = (*p == ENV_SEP); |
|
1364 *q++ = *p++; |
|
1365 } |
|
1366 } |
|
1367 *q = '\0'; |
|
1368 return(ret); |
|
1369 } |
|
1370 |
|
1371 /* Initialize everything for FORMAT. */ |
|
1372 |
|
1373 static const char * |
|
1374 kpse_init_format (void) |
|
1375 { |
|
1376 /* If we get called twice, don't redo all the work. */ |
|
1377 if (kpse_format_info.path) |
|
1378 return kpse_format_info.path; |
|
1379 |
|
1380 kpse_format_info.type = "ls-R"; |
|
1381 init_path (&kpse_format_info, DEFAULT_TEXMFDBS, DB_ENVS, NULL); |
|
1382 add_suffixes(&kpse_format_info.suffix, "ls-R", NULL); |
|
1383 kpse_format_info.path = remove_dbonly (kpse_format_info.path); |
|
1384 |
|
1385 #ifdef KPSE_DEBUG |
|
1386 #define MAYBE(member) (kpse_format_info.member ? kpse_format_info.member : "(none)") |
|
1387 |
|
1388 /* Describe the monster we've created. */ |
|
1389 if (KPSE_DEBUG_P (KPSE_DEBUG_PATHS)) |
|
1390 { |
|
1391 DEBUGF2 ("Search path for %s files (from %s)\n", |
|
1392 kpse_format_info.type, kpse_format_info.path_source); |
|
1393 DEBUGF1 (" = %s\n", kpse_format_info.path); |
|
1394 DEBUGF1 (" before expansion = %s\n", kpse_format_info.raw_path); |
|
1395 DEBUGF1 (" application override path = %s\n", MAYBE (override_path)); |
|
1396 DEBUGF1 (" application config file path = %s\n", MAYBE (client_path)); |
|
1397 DEBUGF1 (" texmf.cnf path = %s\n", MAYBE (cnf_path)); |
|
1398 DEBUGF1 (" compile-time path = %s\n", MAYBE (default_path)); |
|
1399 DEBUGF (" default suffixes ="); |
|
1400 if (kpse_format_info.suffix) { |
|
1401 const char **ext; |
|
1402 for (ext = kpse_format_info.suffix; ext && *ext; ext++) { |
|
1403 fprintf (stderr, " %s", *ext); |
|
1404 } |
|
1405 putc ('\n', stderr); |
|
1406 } else { |
|
1407 fputs (" (none)\n", stderr); |
|
1408 } |
|
1409 DEBUGF (" other suffixes ="); |
|
1410 if (kpse_format_info.alt_suffix) { |
|
1411 const char **alt; |
|
1412 for (alt = kpse_format_info.alt_suffix; alt && *alt; alt++) { |
|
1413 fprintf (stderr, " %s", *alt); |
|
1414 } |
|
1415 putc ('\n', stderr); |
|
1416 } else { |
|
1417 fputs (" (none)\n", stderr); |
|
1418 } |
|
1419 DEBUGF1 (" search only with suffix = %d\n",kpse_format_info.suffix_search_only); |
|
1420 DEBUGF1 (" runtime generation program = %s\n", MAYBE (program)); |
|
1421 DEBUGF1 (" extra program args = %s\n", MAYBE (program_args)); |
|
1422 DEBUGF1 (" program enabled = %d\n", kpse_format_info.program_enabled_p); |
|
1423 DEBUGF1 (" program enable level = %d\n", kpse_format_info.program_enable_level); |
|
1424 } |
|
1425 #endif /* KPSE_DEBUG */ |
|
1426 |
|
1427 return kpse_format_info.path; |
|
1428 } |
|
1429 |
|
1430 static hash_table_type db; /* The hash table for all the ls-R's. */ |
|
1431 /* SMALL: The old size of the hash table was 7603, with the assumption |
|
1432 that a minimal ls-R bas about 3500 entries. But a typical ls-R will |
|
1433 be more like double that size. */ |
|
1434 #ifndef DB_HASH_SIZE |
|
1435 #define DB_HASH_SIZE 15991 |
|
1436 #endif |
|
1437 #ifndef DB_NAME |
|
1438 #define DB_NAME "ls-R" |
|
1439 #endif |
|
1440 |
|
1441 static hash_table_type alias_db; |
|
1442 #ifndef ALIAS_NAME |
|
1443 #define ALIAS_NAME "aliases" |
|
1444 #endif |
|
1445 #ifndef ALIAS_HASH_SIZE |
|
1446 #define ALIAS_HASH_SIZE 1009 |
|
1447 #endif |
|
1448 |
|
1449 static str_list_type db_dir_list; |
|
1450 |
|
1451 /* If DIRNAME contains any element beginning with a `.' (that is more |
|
1452 than just `./'), return true. This is to allow ``hidden'' |
|
1453 directories -- ones that don't get searched. */ |
|
1454 |
|
1455 static bool |
|
1456 ignore_dir_p (const char *dirname) |
|
1457 { |
|
1458 const char *dot_pos = dirname; |
|
1459 |
|
1460 while ((dot_pos = strchr (dot_pos + 1, '.'))) { |
|
1461 /* If / before and no / after, skip it. */ |
|
1462 if (IS_DIR_SEP (dot_pos[-1]) && dot_pos[1] && !IS_DIR_SEP (dot_pos[1])) |
|
1463 return true; |
|
1464 } |
|
1465 |
|
1466 return false; |
|
1467 } |
|
1468 |
|
1469 /* Allocate in increments of this size. */ |
|
1470 #define BLOCK_SIZE 75 |
|
1471 |
|
1472 static char * |
|
1473 read_line (FILE *f) |
|
1474 { |
|
1475 int c; |
|
1476 unsigned limit = BLOCK_SIZE; |
|
1477 unsigned loc = 0; |
|
1478 char *line = (char *) xmalloc (limit); |
|
1479 |
|
1480 while ((c = getc (f)) != EOF && c != '\n' && c != '\r') |
|
1481 { |
|
1482 line[loc] = c; |
|
1483 loc++; |
|
1484 |
|
1485 /* By testing after the assignment, we guarantee that we'll always |
|
1486 have space for the null we append below. We know we always |
|
1487 have room for the first char, since we start with BLOCK_SIZE. */ |
|
1488 if (loc == limit) |
|
1489 { |
|
1490 limit += BLOCK_SIZE; |
|
1491 line = (char *) xrealloc (line, limit); |
|
1492 } |
|
1493 } |
|
1494 |
|
1495 /* If we read anything, return it. This can't represent a last |
|
1496 ``line'' which doesn't end in a newline, but so what. */ |
|
1497 if (c != EOF) |
|
1498 { |
|
1499 /* Terminate the string. We can't represent nulls in the file, |
|
1500 either. Again, it doesn't matter. */ |
|
1501 line[loc] = 0; |
|
1502 /* Absorb LF of a CRLF pair. */ |
|
1503 if (c == '\r') { |
|
1504 c = getc (f); |
|
1505 if (c != '\n') |
|
1506 ungetc (c, f); |
|
1507 } |
|
1508 } |
|
1509 else /* At end of file. */ |
|
1510 { |
|
1511 free (line); |
|
1512 line = NULL; |
|
1513 } |
|
1514 |
|
1515 return line; |
|
1516 } |
|
1517 |
|
1518 /* If no DB_FILENAME, return false (maybe they aren't using this feature). |
|
1519 Otherwise, add entries from DB_FILENAME to TABLE, and return true. */ |
|
1520 |
|
1521 static bool |
|
1522 db_build (hash_table_type *table, const char *db_filename) |
|
1523 { |
|
1524 char *line; |
|
1525 unsigned dir_count = 0, file_count = 0, ignore_dir_count = 0; |
|
1526 unsigned len = strlen (db_filename) - sizeof (DB_NAME) + 1; /* Keep the /. */ |
|
1527 char *top_dir = (char *) xmalloc (len + 1); |
|
1528 char *cur_dir = NULL; /* First thing in ls-R might be a filename. */ |
|
1529 FILE *db_file = fopen (db_filename, FOPEN_R_MODE); |
|
1530 |
|
1531 strncpy (top_dir, db_filename, len); |
|
1532 top_dir[len] = 0; |
|
1533 |
|
1534 if (db_file) { |
|
1535 while ((line = read_line (db_file)) != NULL) { |
|
1536 len = strlen (line); |
|
1537 |
|
1538 /* A line like `/foo:' = new dir foo. Allow both absolute (/...) |
|
1539 and explicitly relative (./...) names here. It's a kludge to |
|
1540 pass in the directory name with the trailing : still attached, |
|
1541 but it doesn't actually hurt. */ |
|
1542 if (len > 0 && line[len - 1] == ':' && kpse_absolute_p (line, true)) { |
|
1543 /* New directory line. */ |
|
1544 if (!ignore_dir_p (line)) { |
|
1545 /* If they gave a relative name, prepend full directory name now. */ |
|
1546 line[len - 1] = DIR_SEP; |
|
1547 /* Skip over leading `./', it confuses `match' and is just a |
|
1548 waste of space, anyway. This will lose on `../', but `match' |
|
1549 won't work there, either, so it doesn't matter. */ |
|
1550 cur_dir = *line == '.' ? concat (top_dir, line + 2) : xstrdup (line); |
|
1551 dir_count++; |
|
1552 } else { |
|
1553 cur_dir = NULL; |
|
1554 ignore_dir_count++; |
|
1555 } |
|
1556 |
|
1557 /* Ignore blank, `.' and `..' lines. */ |
|
1558 } else if (*line != 0 && cur_dir /* a file line? */ |
|
1559 && !(*line == '.' |
|
1560 && (line[1] == '0' || (line[1] == '.' && line[2] == 0)))) |
|
1561 {/* Make a new hash table entry with a key of `line' and a data |
|
1562 of `cur_dir'. An already-existing identical key is ok, since |
|
1563 a file named `foo' can be in more than one directory. Share |
|
1564 `cur_dir' among all its files (and hence never free it). */ |
|
1565 hash_insert (table, xstrdup (line), cur_dir); |
|
1566 file_count++; |
|
1567 |
|
1568 } /* else ignore blank lines or top-level files |
|
1569 or files in ignored directories*/ |
|
1570 |
|
1571 free (line); |
|
1572 } |
|
1573 |
|
1574 xfclose (db_file, db_filename); |
|
1575 |
|
1576 if (file_count == 0) { |
|
1577 WARNING1 ("kpathsea: No usable entries in %s", db_filename); |
|
1578 WARNING ("kpathsea: See the manual for how to generate ls-R"); |
|
1579 db_file = NULL; |
|
1580 } else { |
|
1581 str_list_add (&db_dir_list, xstrdup (top_dir)); |
|
1582 } |
|
1583 |
|
1584 #ifdef KPSE_DEBUG |
|
1585 if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) { |
|
1586 /* Don't make this a debugging bit, since the output is so |
|
1587 voluminous, and being able to specify -1 is too useful. |
|
1588 Instead, let people who want it run the program under |
|
1589 a debugger and change the variable that way. */ |
|
1590 bool hash_summary_only = true; |
|
1591 |
|
1592 DEBUGF4 ("%s: %u entries in %d directories (%d hidden).\n", |
|
1593 db_filename, file_count, dir_count, ignore_dir_count); |
|
1594 DEBUGF ("ls-R hash table:"); |
|
1595 hash_print (*table, hash_summary_only); |
|
1596 fflush (stderr); |
|
1597 } |
|
1598 #endif /* KPSE_DEBUG */ |
|
1599 } |
|
1600 |
|
1601 free (top_dir); |
|
1602 |
|
1603 return db_file != NULL; |
|
1604 } |
|
1605 |
|
1606 |
|
1607 /* Insert FNAME into the hash table. This is for files that get built |
|
1608 during a run. We wouldn't want to reread all of ls-R, even if it got |
|
1609 rebuilt. */ |
|
1610 |
|
1611 void |
|
1612 kpse_db_insert (const char *passed_fname) |
|
1613 { |
|
1614 /* We might not have found ls-R, or even had occasion to look for it |
|
1615 yet, so do nothing if we have no hash table. */ |
|
1616 if (db.buckets) { |
|
1617 const char *dir_part; |
|
1618 char *fname = xstrdup (passed_fname); |
|
1619 char *baseptr = xbasename (fname); |
|
1620 const char *file_part = xstrdup (baseptr); |
|
1621 |
|
1622 *baseptr = '\0'; /* Chop off the filename. */ |
|
1623 dir_part = fname; /* That leaves the dir, with the trailing /. */ |
|
1624 |
|
1625 hash_insert (&db, file_part, dir_part); |
|
1626 } |
|
1627 } |
|
1628 |
|
1629 /* Return true if FILENAME could be in PATH_ELT, i.e., if the directory |
|
1630 part of FILENAME matches PATH_ELT. Have to consider // wildcards, but |
|
1631 $ and ~ expansion have already been done. */ |
|
1632 |
|
1633 static bool |
|
1634 match (const char *filename, const char *path_elt) |
|
1635 { |
|
1636 const char *original_filename = filename; |
|
1637 bool matched = false; |
|
1638 |
|
1639 for (; *filename && *path_elt; filename++, path_elt++) { |
|
1640 if (FILECHARCASEEQ (*filename, *path_elt)) /* normal character match */ |
|
1641 ; |
|
1642 |
|
1643 else if (IS_DIR_SEP (*path_elt) /* at // */ |
|
1644 && original_filename < filename && IS_DIR_SEP (path_elt[-1])) { |
|
1645 while (IS_DIR_SEP (*path_elt)) |
|
1646 path_elt++; /* get past second and any subsequent /'s */ |
|
1647 if (*path_elt == 0) { |
|
1648 /* Trailing //, matches anything. We could make this part of the |
|
1649 other case, but it seems pointless to do the extra work. */ |
|
1650 matched = true; |
|
1651 break; |
|
1652 } else { |
|
1653 /* Intermediate //, have to match rest of PATH_ELT. */ |
|
1654 for (; !matched && *filename; filename++) { |
|
1655 /* Try matching at each possible character. */ |
|
1656 if (IS_DIR_SEP (filename[-1]) |
|
1657 && FILECHARCASEEQ (*filename, *path_elt)) |
|
1658 matched = match (filename, path_elt); |
|
1659 } |
|
1660 /* Prevent filename++ when *filename='\0'. */ |
|
1661 break; |
|
1662 } |
|
1663 } |
|
1664 |
|
1665 else /* normal character nonmatch, quit */ |
|
1666 break; |
|
1667 } |
|
1668 |
|
1669 /* If we've reached the end of PATH_ELT, check that we're at the last |
|
1670 component of FILENAME, we've matched. */ |
|
1671 if (!matched && *path_elt == 0) { |
|
1672 /* Probably PATH_ELT ended with `vf' or some such, and FILENAME ends |
|
1673 with `vf/ptmr.vf'. In that case, we'll be at a directory |
|
1674 separator. On the other hand, if PATH_ELT ended with a / (as in |
|
1675 `vf/'), FILENAME being the same `vf/ptmr.vf', we'll be at the |
|
1676 `p'. Upshot: if we're at a dir separator in FILENAME, skip it. |
|
1677 But if not, that's ok, as long as there are no more dir separators. */ |
|
1678 if (IS_DIR_SEP (*filename)) |
|
1679 filename++; |
|
1680 |
|
1681 while (*filename && !IS_DIR_SEP (*filename)) |
|
1682 filename++; |
|
1683 matched = *filename == 0; |
|
1684 } |
|
1685 |
|
1686 return matched; |
|
1687 } |
|
1688 |
|
1689 |
|
1690 /* If DB_DIR is a prefix of PATH_ELT, return true; otherwise false. |
|
1691 That is, the question is whether to try the db for a file looked up |
|
1692 in PATH_ELT. If PATH_ELT == ".", for example, the answer is no. If |
|
1693 PATH_ELT == "/usr/local/lib/texmf/fonts//tfm", the answer is yes. |
|
1694 |
|
1695 In practice, ls-R is only needed for lengthy subdirectory |
|
1696 comparisons, but there's no gain to checking PATH_ELT to see if it is |
|
1697 a subdir match, since the only way to do that is to do a string |
|
1698 search in it, which is all we do anyway. */ |
|
1699 |
|
1700 static bool |
|
1701 elt_in_db (const char *db_dir, const char *path_elt) |
|
1702 { |
|
1703 bool found = false; |
|
1704 |
|
1705 while (!found && FILECHARCASEEQ (*db_dir++, *path_elt++)) { |
|
1706 /* If we've matched the entire db directory, it's good. */ |
|
1707 if (*db_dir == 0) |
|
1708 found = true; |
|
1709 |
|
1710 /* If we've reached the end of PATH_ELT, but not the end of the db |
|
1711 directory, it's no good. */ |
|
1712 else if (*path_elt == 0) |
|
1713 break; |
|
1714 } |
|
1715 |
|
1716 return found; |
|
1717 } |
|
1718 |
|
1719 /* If ALIAS_FILENAME exists, read it into TABLE. */ |
|
1720 |
|
1721 static bool |
|
1722 alias_build (hash_table_type *table, const char *alias_filename) |
|
1723 { |
|
1724 char *line, *real, *alias; |
|
1725 unsigned count = 0; |
|
1726 FILE *alias_file = fopen (alias_filename, FOPEN_R_MODE); |
|
1727 |
|
1728 if (alias_file) { |
|
1729 while ((line = read_line (alias_file)) != NULL) { |
|
1730 /* comments or empty */ |
|
1731 if (*line == 0 || *line == '%' || *line == '#') { |
|
1732 ; |
|
1733 } else { |
|
1734 /* Each line should have two fields: realname aliasname. */ |
|
1735 real = line; |
|
1736 while (*real && ISSPACE (*real)) |
|
1737 real++; |
|
1738 alias = real; |
|
1739 while (*alias && !ISSPACE (*alias)) |
|
1740 alias++; |
|
1741 *alias++ = 0; |
|
1742 while (*alias && ISSPACE (*alias)) |
|
1743 alias++; |
|
1744 /* Is the check for errors strong enough? Should we warn the user |
|
1745 for potential errors? */ |
|
1746 if (strlen (real) != 0 && strlen (alias) != 0) { |
|
1747 hash_insert (table, xstrdup (alias), xstrdup (real)); |
|
1748 count++; |
|
1749 } |
|
1750 } |
|
1751 free (line); |
|
1752 } |
|
1753 |
|
1754 #ifdef KPSE_DEBUG |
|
1755 if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) { |
|
1756 /* As with ls-R above ... */ |
|
1757 bool hash_summary_only = true; |
|
1758 DEBUGF2 ("%s: %u aliases.\n", alias_filename, count); |
|
1759 DEBUGF ("alias hash table:"); |
|
1760 hash_print (*table, hash_summary_only); |
|
1761 fflush (stderr); |
|
1762 } |
|
1763 #endif /* KPSE_DEBUG */ |
|
1764 |
|
1765 xfclose (alias_file, alias_filename); |
|
1766 } |
|
1767 |
|
1768 return alias_file != NULL; |
|
1769 } |
|
1770 |
|
1771 /* Initialize the path for ls-R files, and read them all into the hash |
|
1772 table `db'. If no usable ls-R's are found, set db.buckets to NULL. */ |
|
1773 |
|
1774 void |
|
1775 kpse_init_db (void) |
|
1776 { |
|
1777 bool ok = false; |
|
1778 const char *db_path = kpse_init_format (); |
|
1779 char **db_files = kpse_all_path_search (db_path, DB_NAME); |
|
1780 char **orig_db_files = db_files; |
|
1781 |
|
1782 /* Must do this after the path searching (which ends up calling |
|
1783 kpse_db_search recursively), so db.buckets stays NULL. */ |
|
1784 db = hash_create (DB_HASH_SIZE); |
|
1785 |
|
1786 while (db_files && *db_files) { |
|
1787 if (db_build (&db, *db_files)) |
|
1788 ok = true; |
|
1789 free (*db_files); |
|
1790 db_files++; |
|
1791 } |
|
1792 |
|
1793 if (!ok) { |
|
1794 /* If db can't be built, leave `size' nonzero (so we don't |
|
1795 rebuild it), but clear `buckets' (so we don't look in it). */ |
|
1796 free (db.buckets); |
|
1797 db.buckets = NULL; |
|
1798 } |
|
1799 |
|
1800 free (orig_db_files); |
|
1801 |
|
1802 /* Add the content of any alias databases. There may exist more than |
|
1803 one alias file along DB_NAME files. This duplicates the above code |
|
1804 -- should be a function. */ |
|
1805 ok = false; |
|
1806 db_files = kpse_all_path_search (db_path, ALIAS_NAME); |
|
1807 orig_db_files = db_files; |
|
1808 |
|
1809 alias_db = hash_create (ALIAS_HASH_SIZE); |
|
1810 |
|
1811 while (db_files && *db_files) { |
|
1812 if (alias_build (&alias_db, *db_files)) |
|
1813 ok = true; |
|
1814 free (*db_files); |
|
1815 db_files++; |
|
1816 } |
|
1817 |
|
1818 if (!ok) { |
|
1819 free (alias_db.buckets); |
|
1820 alias_db.buckets = NULL; |
|
1821 } |
|
1822 |
|
1823 free (orig_db_files); |
|
1824 } |
|
1825 |
|
1826 /* Avoid doing anything if this PATH_ELT is irrelevant to the databases. */ |
|
1827 |
|
1828 str_list_type * |
|
1829 kpse_db_search (const char *name, const char *orig_path_elt, bool all) |
|
1830 { |
|
1831 char **db_dirs, **orig_dirs, **r; |
|
1832 const char *last_slash; |
|
1833 char *path_elt; |
|
1834 bool done; |
|
1835 str_list_type *ret = 0; |
|
1836 unsigned e; |
|
1837 char **aliases = NULL; |
|
1838 bool relevant = false; |
|
1839 |
|
1840 /* If we failed to build the database (or if this is the recursive |
|
1841 call to build the db path), quit. */ |
|
1842 if (db.buckets == NULL) |
|
1843 return NULL; |
|
1844 |
|
1845 /* When tex-glyph.c calls us looking for, e.g., dpi600/cmr10.pk, we |
|
1846 won't find it unless we change NAME to just `cmr10.pk' and append |
|
1847 `/dpi600' to PATH_ELT. We are justified in using a literal `/' |
|
1848 here, since that's what tex-glyph.c unconditionally uses in |
|
1849 DPI_BITMAP_SPEC. But don't do anything if the / begins NAME; that |
|
1850 should never happen. */ |
|
1851 last_slash = strrchr (name, '/'); |
|
1852 if (last_slash && last_slash != name) { |
|
1853 unsigned len = last_slash - name + 1; |
|
1854 char *dir_part = (char *) xmalloc (len); |
|
1855 strncpy (dir_part, name, len - 1); |
|
1856 dir_part[len - 1] = 0; |
|
1857 path_elt = concat3 (orig_path_elt, "/", dir_part); |
|
1858 name = last_slash + 1; |
|
1859 } else |
|
1860 path_elt = (char *) orig_path_elt; |
|
1861 |
|
1862 /* Don't bother doing any lookups if this `path_elt' isn't covered by |
|
1863 any of database directories. We do this not so much because the |
|
1864 extra couple of hash lookups matter -- they don't -- but rather |
|
1865 because we want to return NULL in this case, so path_search can |
|
1866 know to do a disk search. */ |
|
1867 for (e = 0; !relevant && e < STR_LIST_LENGTH (db_dir_list); e++) { |
|
1868 relevant = elt_in_db (STR_LIST_ELT (db_dir_list, e), path_elt); |
|
1869 } |
|
1870 if (!relevant) |
|
1871 return NULL; |
|
1872 |
|
1873 /* If we have aliases for this name, use them. */ |
|
1874 if (alias_db.buckets) |
|
1875 aliases = hash_lookup (alias_db, name); |
|
1876 |
|
1877 if (!aliases) { |
|
1878 aliases = XTALLOC1 (char *); |
|
1879 aliases[0] = NULL; |
|
1880 } |
|
1881 { /* Push aliases up by one and insert the original name at the front. */ |
|
1882 unsigned i; |
|
1883 unsigned len = 1; /* Have NULL element already allocated. */ |
|
1884 for (r = aliases; *r; r++) |
|
1885 len++; |
|
1886 XRETALLOC (aliases, len + 1, char *); |
|
1887 for (i = len; i > 0; i--) { |
|
1888 aliases[i] = aliases[i - 1]; |
|
1889 } |
|
1890 aliases[0] = (char *) name; |
|
1891 } |
|
1892 |
|
1893 done = false; |
|
1894 for (r = aliases; !done && *r; r++) { |
|
1895 char *atry = *r; |
|
1896 |
|
1897 /* We have an ls-R db. Look up `atry'. */ |
|
1898 orig_dirs = db_dirs = hash_lookup (db, atry); |
|
1899 |
|
1900 ret = XTALLOC1 (str_list_type); |
|
1901 *ret = str_list_init (); |
|
1902 |
|
1903 /* For each filename found, see if it matches the path element. For |
|
1904 example, if we have .../cx/cmr10.300pk and .../ricoh/cmr10.300pk, |
|
1905 and the path looks like .../cx, we don't want the ricoh file. */ |
|
1906 while (!done && db_dirs && *db_dirs) { |
|
1907 char *db_file = concat (*db_dirs, atry); |
|
1908 bool matched = match (db_file, path_elt); |
|
1909 |
|
1910 #ifdef KPSE_DEBUG |
|
1911 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) |
|
1912 DEBUGF3 ("db:match(%s,%s) = %d\n", db_file, path_elt, matched); |
|
1913 #endif |
|
1914 |
|
1915 /* We got a hit in the database. Now see if the file actually |
|
1916 exists, possibly under an alias. */ |
|
1917 if (matched) { |
|
1918 char *found = NULL; |
|
1919 if (kpse_readable_file (db_file)) { |
|
1920 found = db_file; |
|
1921 |
|
1922 } else { |
|
1923 char **a; |
|
1924 |
|
1925 free (db_file); /* `db_file' wasn't on disk. */ |
|
1926 |
|
1927 /* The hit in the DB doesn't exist in disk. Now try all its |
|
1928 aliases. For example, suppose we have a hierarchy on CD, |
|
1929 thus `mf.bas', but ls-R contains `mf.base'. Find it anyway. |
|
1930 Could probably work around this with aliases, but |
|
1931 this is pretty easy and shouldn't hurt. The upshot is that |
|
1932 if one of the aliases actually exists, we use that. */ |
|
1933 for (a = aliases + 1; *a && !found; a++) { |
|
1934 char *atry = concat (*db_dirs, *a); |
|
1935 if (kpse_readable_file (atry)) |
|
1936 found = atry; |
|
1937 else |
|
1938 free (atry); |
|
1939 } |
|
1940 } |
|
1941 |
|
1942 /* If we have a real file, add it to the list, maybe done. */ |
|
1943 if (found) { |
|
1944 str_list_add (ret, found); |
|
1945 if (!all && found) |
|
1946 done = true; |
|
1947 } |
|
1948 } else { /* no match in the db */ |
|
1949 free (db_file); |
|
1950 } |
|
1951 |
|
1952 |
|
1953 /* On to the next directory, if any. */ |
|
1954 db_dirs++; |
|
1955 } |
|
1956 |
|
1957 /* This is just the space for the pointers, not the strings. */ |
|
1958 if (orig_dirs && *orig_dirs) |
|
1959 free (orig_dirs); |
|
1960 } |
|
1961 |
|
1962 free (aliases); |
|
1963 |
|
1964 /* If we had to break up NAME, free the temporary PATH_ELT. */ |
|
1965 if (path_elt != orig_path_elt) |
|
1966 free (path_elt); |
|
1967 |
|
1968 return ret; |
|
1969 } |
|
1970 |
|
1971 /* kdefault.c: Expand extra colons. */ |
|
1972 |
|
1973 /* Check for leading colon first, then trailing, then doubled, since |
|
1974 that is fastest. Usually it will be leading or trailing. */ |
|
1975 |
|
1976 char * |
|
1977 kpse_expand_default (const char *path, const char *fallback) |
|
1978 { |
|
1979 unsigned path_length; |
|
1980 char *expansion; |
|
1981 |
|
1982 /* The default path better not be null. */ |
|
1983 assert (fallback); |
|
1984 |
|
1985 if (path == NULL) |
|
1986 expansion = xstrdup (fallback); |
|
1987 |
|
1988 /* Solitary or leading :? */ |
|
1989 else if (IS_ENV_SEP (*path)) |
|
1990 { |
|
1991 expansion = path[1] == 0 ? xstrdup (fallback) : concat (fallback, path); |
|
1992 } |
|
1993 |
|
1994 /* Sorry about the assignment in the middle of the expression, but |
|
1995 conventions were made to be flouted and all that. I don't see the |
|
1996 point of calling strlen twice or complicating the logic just to |
|
1997 avoid the assignment (especially now that I've pointed it out at |
|
1998 such great length). */ |
|
1999 else if (path[(path_length = strlen (path)) - 1] == ENV_SEP) |
|
2000 expansion = concat (path, fallback); |
|
2001 |
|
2002 /* OK, not leading or trailing. Check for doubled. */ |
|
2003 else |
|
2004 { |
|
2005 const char *loc; |
|
2006 |
|
2007 /* What we'll return if we find none. */ |
|
2008 expansion = xstrdup (path); |
|
2009 |
|
2010 for (loc = path; *loc; loc++) |
|
2011 { |
|
2012 if (IS_ENV_SEP (loc[0]) && IS_ENV_SEP (loc[1])) |
|
2013 { /* We have a doubled colon. */ |
|
2014 expansion = (char *) xmalloc (path_length + strlen (fallback) + 1); |
|
2015 |
|
2016 /* Copy stuff up to and including the first colon. */ |
|
2017 strncpy (expansion, path, loc - path + 1); |
|
2018 expansion[loc - path + 1] = 0; |
|
2019 |
|
2020 /* Copy in FALLBACK, and then the rest of PATH. */ |
|
2021 strcat (expansion, fallback); |
|
2022 strcat (expansion, loc + 1); |
|
2023 |
|
2024 break; |
|
2025 } |
|
2026 } |
|
2027 } |
|
2028 |
|
2029 return expansion; |
|
2030 } |
|
2031 |
|
2032 /* elt-dirs.c: Translate a path element to its corresponding |
|
2033 director{y,ies}. */ |
|
2034 |
|
2035 /* To avoid giving prototypes for all the routines and then their real |
|
2036 definitions, we give all the subroutines first. The entry point is |
|
2037 the last routine in the file. */ |
|
2038 |
|
2039 /* Make a copy of DIR (unless it's null) and save it in L. Ensure that |
|
2040 DIR ends with a DIR_SEP for the benefit of later searches. */ |
|
2041 |
|
2042 static void |
|
2043 dir_list_add (str_llist_type *l, const char *dir) |
|
2044 { |
|
2045 char last_char = dir[strlen (dir) - 1]; |
|
2046 char *saved_dir |
|
2047 = IS_DIR_SEP (last_char) || IS_DEVICE_SEP (last_char) |
|
2048 ? xstrdup (dir) |
|
2049 : concat (dir, DIR_SEP_STRING); |
|
2050 |
|
2051 str_llist_add (l, saved_dir); |
|
2052 } |
|
2053 |
|
2054 |
|
2055 /* If DIR is a directory, add it to the list L. */ |
|
2056 |
|
2057 static void |
|
2058 checked_dir_list_add (str_llist_type *l, const char *dir) |
|
2059 { |
|
2060 if (dir_p (dir)) |
|
2061 dir_list_add (l, dir); |
|
2062 } |
|
2063 |
|
2064 /* The cache. Typically, several paths have the same element; for |
|
2065 example, /usr/local/lib/texmf/fonts//. We don't want to compute the |
|
2066 expansion of such a thing more than once. Even though we also cache |
|
2067 the dir_links call, that's not enough -- without this path element |
|
2068 caching as well, the execution time doubles. */ |
|
2069 |
|
2070 typedef struct |
|
2071 { |
|
2072 const char *key; |
|
2073 str_llist_type *value; |
|
2074 } cache_entry; |
|
2075 |
|
2076 static cache_entry *the_cache = NULL; |
|
2077 static unsigned cache_length = 0; |
|
2078 |
|
2079 /* Associate KEY with VALUE. We implement the cache as a simple linear |
|
2080 list, since it's unlikely to ever be more than a dozen or so elements |
|
2081 long. We don't bother to check here if PATH has already been saved; |
|
2082 we always add it to our list. We copy KEY but not VALUE; not sure |
|
2083 that's right, but it seems to be all that's needed. */ |
|
2084 |
|
2085 static void |
|
2086 cache (const char *key, str_llist_type *value) |
|
2087 { |
|
2088 cache_length++; |
|
2089 XRETALLOC (the_cache, cache_length, cache_entry); |
|
2090 the_cache[cache_length - 1].key = xstrdup (key); |
|
2091 the_cache[cache_length - 1].value = value; |
|
2092 } |
|
2093 |
|
2094 |
|
2095 /* To retrieve, just check the list in order. */ |
|
2096 |
|
2097 static str_llist_type * |
|
2098 cached (const char *key) |
|
2099 { |
|
2100 unsigned p; |
|
2101 |
|
2102 for (p = 0; p < cache_length; p++) |
|
2103 { |
|
2104 if (FILESTRCASEEQ (the_cache[p].key, key)) |
|
2105 return the_cache[p].value; |
|
2106 } |
|
2107 |
|
2108 return NULL; |
|
2109 } |
|
2110 |
|
2111 /* Handle the magic path constructs. */ |
|
2112 |
|
2113 /* Declare recursively called routine. */ |
|
2114 static void expand_elt (str_llist_type *, const char *, unsigned); |
|
2115 |
|
2116 |
|
2117 /* POST is a pointer into the original element (which may no longer be |
|
2118 ELT) to just after the doubled DIR_SEP, perhaps to the null. Append |
|
2119 subdirectories of ELT (up to ELT_LENGTH, which must be a /) to |
|
2120 STR_LIST_PTR. */ |
|
2121 |
|
2122 #ifdef WIN32 |
|
2123 /* Shared across recursive calls, it acts like a stack. */ |
|
2124 static char dirname[MAX_PATH]; |
|
2125 #endif |
|
2126 |
|
2127 static void |
|
2128 do_subdir (str_llist_type *str_list_ptr, const char *elt, |
|
2129 unsigned elt_length, const char *post) |
|
2130 { |
|
2131 #ifdef WIN32 |
|
2132 WIN32_FIND_DATA find_file_data; |
|
2133 HANDLE hnd; |
|
2134 int proceed; |
|
2135 #else |
|
2136 DIR *dir; |
|
2137 struct dirent *e; |
|
2138 #endif /* not WIN32 */ |
|
2139 fn_type name; |
|
2140 |
|
2141 /* Some old compilers don't allow aggregate initialization. */ |
|
2142 name = fn_copy0 (elt, elt_length); |
|
2143 |
|
2144 assert (IS_DIR_SEP (elt[elt_length - 1]) |
|
2145 || IS_DEVICE_SEP (elt[elt_length - 1])); |
|
2146 |
|
2147 #if defined (WIN32) |
|
2148 strcpy(dirname, FN_STRING(name)); |
|
2149 strcat(dirname, "/*.*"); /* "*.*" or "*" -- seems equivalent. */ |
|
2150 hnd = FindFirstFile(dirname, &find_file_data); |
|
2151 |
|
2152 if (hnd == INVALID_HANDLE_VALUE) { |
|
2153 fn_free(&name); |
|
2154 return; |
|
2155 } |
|
2156 |
|
2157 /* Include top level before subdirectories, if nothing to match. */ |
|
2158 if (*post == 0) |
|
2159 dir_list_add (str_list_ptr, FN_STRING (name)); |
|
2160 else { |
|
2161 /* If we do have something to match, see if it exists. For |
|
2162 example, POST might be `pk/ljfour', and they might have a |
|
2163 directory `$TEXMF/fonts/pk/ljfour' that we should find. */ |
|
2164 fn_str_grow (&name, post); |
|
2165 expand_elt (str_list_ptr, FN_STRING (name), elt_length); |
|
2166 fn_shrink_to (&name, elt_length); |
|
2167 } |
|
2168 proceed = 1; |
|
2169 while (proceed) { |
|
2170 if (find_file_data.cFileName[0] != '.') { |
|
2171 /* Construct the potential subdirectory name. */ |
|
2172 fn_str_grow (&name, find_file_data.cFileName); |
|
2173 if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { |
|
2174 unsigned potential_len = FN_LENGTH (name); |
|
2175 |
|
2176 /* It's a directory, so append the separator. */ |
|
2177 fn_str_grow (&name, DIR_SEP_STRING); |
|
2178 |
|
2179 do_subdir (str_list_ptr, FN_STRING (name), |
|
2180 potential_len, post); |
|
2181 } |
|
2182 fn_shrink_to (&name, elt_length); |
|
2183 } |
|
2184 proceed = FindNextFile (hnd, &find_file_data); |
|
2185 } |
|
2186 fn_free (&name); |
|
2187 FindClose(hnd); |
|
2188 |
|
2189 #else /* not WIN32 */ |
|
2190 |
|
2191 /* If we can't open it, quit. */ |
|
2192 dir = opendir (FN_STRING (name)); |
|
2193 if (dir == NULL) |
|
2194 { |
|
2195 fn_free (&name); |
|
2196 return; |
|
2197 } |
|
2198 |
|
2199 /* Include top level before subdirectories, if nothing to match. */ |
|
2200 if (*post == 0) |
|
2201 dir_list_add (str_list_ptr, FN_STRING (name)); |
|
2202 else |
|
2203 { /* If we do have something to match, see if it exists. For |
|
2204 example, POST might be `pk/ljfour', and they might have a |
|
2205 directory `$TEXMF/fonts/pk/ljfour' that we should find. */ |
|
2206 fn_str_grow (&name, post); |
|
2207 expand_elt (str_list_ptr, FN_STRING (name), elt_length); |
|
2208 fn_shrink_to (&name, elt_length); |
|
2209 } |
|
2210 |
|
2211 while ((e = readdir (dir)) != NULL) |
|
2212 { /* If it begins with a `.', never mind. (This allows ``hidden'' |
|
2213 directories that the algorithm won't find.) */ |
|
2214 if (e->d_name[0] != '.') |
|
2215 { |
|
2216 int links; |
|
2217 |
|
2218 /* Construct the potential subdirectory name. */ |
|
2219 fn_str_grow (&name, e->d_name); |
|
2220 |
|
2221 /* If we can't stat it, or if it isn't a directory, continue. */ |
|
2222 links = dir_links (FN_STRING (name)); |
|
2223 |
|
2224 if (links >= 0) |
|
2225 { |
|
2226 unsigned potential_len = FN_LENGTH (name); |
|
2227 |
|
2228 /* It's a directory, so append the separator. */ |
|
2229 fn_str_grow (&name, DIR_SEP_STRING); |
|
2230 |
|
2231 /* Should we recurse? To see if the subdirectory is a |
|
2232 leaf, check if it has two links (one for . and one for |
|
2233 ..). This means that symbolic links to directories do |
|
2234 not affect the leaf-ness. This is arguably wrong, but |
|
2235 the only alternative I know of is to stat every entry |
|
2236 in the directory, and that is unacceptably slow. |
|
2237 |
|
2238 The #ifdef here makes all this configurable at |
|
2239 compile-time, so that if we're using VMS directories or |
|
2240 some such, we can still find subdirectories, even if it |
|
2241 is much slower. */ |
|
2242 #ifdef ST_NLINK_TRICK |
|
2243 #ifdef AMIGA |
|
2244 /* With SAS/C++ 6.55 on the Amiga, `stat' sets the `st_nlink' |
|
2245 field to -1 for a file, or to 1 for a directory. */ |
|
2246 if (links == 1) |
|
2247 #else |
|
2248 if (links > 2) |
|
2249 #endif /* not AMIGA */ |
|
2250 #endif /* not ST_NLINK_TRICK */ |
|
2251 /* All criteria are met; find subdirectories. */ |
|
2252 do_subdir (str_list_ptr, FN_STRING (name), |
|
2253 potential_len, post); |
|
2254 #ifdef ST_NLINK_TRICK |
|
2255 else if (*post == 0) |
|
2256 /* Nothing to match, no recursive subdirectories to |
|
2257 look for: we're done with this branch. Add it. */ |
|
2258 dir_list_add (str_list_ptr, FN_STRING (name)); |
|
2259 #endif |
|
2260 } |
|
2261 |
|
2262 /* Remove the directory entry we just checked from `name'. */ |
|
2263 fn_shrink_to (&name, elt_length); |
|
2264 } |
|
2265 } |
|
2266 |
|
2267 fn_free (&name); |
|
2268 xclosedir (dir); |
|
2269 #endif /* not WIN32 */ |
|
2270 } |
|
2271 |
|
2272 |
|
2273 /* Assume ELT is non-empty and non-NULL. Return list of corresponding |
|
2274 directories (with no terminating NULL entry) in STR_LIST_PTR. Start |
|
2275 looking for magic constructs at START. */ |
|
2276 |
|
2277 static void |
|
2278 expand_elt (str_llist_type *str_list_ptr, const char *elt, unsigned start) |
|
2279 { |
|
2280 const char *dir = elt + start; |
|
2281 const char *post; |
|
2282 |
|
2283 while (*dir != 0) |
|
2284 { |
|
2285 if (IS_DIR_SEP (*dir)) |
|
2286 { |
|
2287 /* If two or more consecutive /'s, find subdirectories. */ |
|
2288 if (IS_DIR_SEP (dir[1])) |
|
2289 { |
|
2290 for (post = dir + 1; IS_DIR_SEP (*post); post++) ; |
|
2291 do_subdir (str_list_ptr, elt, dir - elt + 1, post); |
|
2292 return; |
|
2293 } |
|
2294 |
|
2295 /* No special stuff at this slash. Keep going. */ |
|
2296 } |
|
2297 |
|
2298 dir++; |
|
2299 } |
|
2300 |
|
2301 /* When we reach the end of ELT, it will be a normal filename. */ |
|
2302 checked_dir_list_add (str_list_ptr, elt); |
|
2303 } |
|
2304 |
|
2305 /* Here is the entry point. Returns directory list for ELT. */ |
|
2306 |
|
2307 str_llist_type * |
|
2308 kpse_element_dirs (const char *elt) |
|
2309 { |
|
2310 str_llist_type *ret; |
|
2311 |
|
2312 /* If given nothing, return nothing. */ |
|
2313 if (!elt || !*elt) |
|
2314 return NULL; |
|
2315 |
|
2316 /* If we've already cached the answer for ELT, return it. */ |
|
2317 ret = cached (elt); |
|
2318 if (ret) |
|
2319 return ret; |
|
2320 |
|
2321 /* We're going to have a real directory list to return. */ |
|
2322 ret = XTALLOC1 (str_llist_type); |
|
2323 *ret = NULL; |
|
2324 |
|
2325 /* We handle the hard case in a subroutine. */ |
|
2326 expand_elt (ret, elt, 0); |
|
2327 |
|
2328 /* Remember the directory list we just found, in case future calls are |
|
2329 made with the same ELT. */ |
|
2330 cache (elt, ret); |
|
2331 |
|
2332 #ifdef KPSE_DEBUG |
|
2333 if (KPSE_DEBUG_P (KPSE_DEBUG_EXPAND)) |
|
2334 { |
|
2335 DEBUGF1 ("path element %s =>", elt); |
|
2336 if (ret) |
|
2337 { |
|
2338 str_llist_elt_type *e; |
|
2339 for (e = *ret; e; e = STR_LLIST_NEXT (*e)) |
|
2340 fprintf (stderr, " %s", STR_LLIST (*e)); |
|
2341 } |
|
2342 putc ('\n', stderr); |
|
2343 fflush (stderr); |
|
2344 } |
|
2345 #endif /* KPSE_DEBUG */ |
|
2346 |
|
2347 return ret; |
|
2348 } |
|
2349 |
|
2350 /* path-elt.c: Return the stuff between colons. */ |
|
2351 |
|
2352 /* The static (but dynamically allocated) area we return the answer in, |
|
2353 and how much we've currently allocated for it. */ |
|
2354 static char *elt = NULL; |
|
2355 static unsigned elt_alloc = 0; |
|
2356 |
|
2357 /* The path we're currently working on. */ |
|
2358 static const char *path = NULL; |
|
2359 |
|
2360 /* Upon entry, the static `path' is at the first (and perhaps last) |
|
2361 character of the return value, or else NULL if we're at the end (or |
|
2362 haven't been called). I make no provision for caching the results; |
|
2363 thus, we parse the same path over and over, on every lookup. If that |
|
2364 turns out to be a significant lose, it can be fixed, but I'm guessing |
|
2365 disk accesses overwhelm everything else. If ENV_P is true, use |
|
2366 IS_ENV_SEP; else use IS_DIR_SEP. */ |
|
2367 |
|
2368 static char * |
|
2369 element (const char *passed_path, bool env_p) |
|
2370 { |
|
2371 const char *p; |
|
2372 char *ret; |
|
2373 int brace_level; |
|
2374 unsigned len; |
|
2375 |
|
2376 if (passed_path) |
|
2377 path = passed_path; |
|
2378 /* Check if called with NULL, and no previous path (perhaps we reached |
|
2379 the end). */ |
|
2380 else if (!path) |
|
2381 return NULL; |
|
2382 |
|
2383 /* OK, we have a non-null `path' if we get here. */ |
|
2384 assert (path); |
|
2385 p = path; |
|
2386 |
|
2387 /* Find the next colon not enclosed by braces (or the end of the path). */ |
|
2388 brace_level = 0; |
|
2389 while (*p != 0 && !(brace_level == 0 |
|
2390 && (env_p ? IS_ENV_SEP (*p) : IS_DIR_SEP (*p)))) { |
|
2391 if (*p == '{') ++brace_level; |
|
2392 else if (*p == '}') --brace_level; |
|
2393 ++p; |
|
2394 } |
|
2395 |
|
2396 /* Return the substring starting at `path'. */ |
|
2397 len = p - path; |
|
2398 |
|
2399 /* Make sure we have enough space (including the null byte). */ |
|
2400 if (len + 1 > elt_alloc) |
|
2401 { |
|
2402 elt_alloc = len + 1; |
|
2403 elt = (char *) xrealloc (elt, elt_alloc); |
|
2404 } |
|
2405 |
|
2406 strncpy (elt, path, len); |
|
2407 elt[len] = 0; |
|
2408 ret = elt; |
|
2409 |
|
2410 /* If we are at the end, return NULL next time. */ |
|
2411 if (path[len] == 0) |
|
2412 path = NULL; |
|
2413 else |
|
2414 path += len + 1; |
|
2415 |
|
2416 return ret; |
|
2417 } |
|
2418 |
|
2419 char * |
|
2420 kpse_path_element (const char *p) |
|
2421 { |
|
2422 return element (p, true); |
|
2423 } |
|
2424 |
|
2425 char * |
|
2426 kpse_filename_component (const char *p) |
|
2427 { |
|
2428 return element (p, false); |
|
2429 } |
|
2430 |