src/fsearch.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- NAMLENGTH
- NAMLENGTH
- vf_kpathsea_init
- vf_add_uncompresser_alist
- vf_open_uncompress_stream
- vf_close_uncompress_stream
- vf_search_file
- search_in_fdb
- search_fdb_fp
- vf_find_file_in_directory
- search_file_kpathsea
- search_file
- ext2uncprog
- vf_tex_make_glyph
- search_file_recursive
- search_file_recursive
- traverse_directory
- dtr_elem_alloc
- dtr_elem_free
- dtr_alloc
- dtr_free
- dtr_get_path
- dtr_add_subdir
- dtr_go_subdir
- dtr_go_updir
- dtr_subdir_list
- dtr_next_subdir
- dtr_add_name
- dtr_del_name
- recursive_searcher
- recursive_searcher_found
1 /*
2 * fsearch.c - search a file
3 * by Hirotsugu Kakugawa
4 *
5 * 28 May 1997 Added recursive file searching feature.
6 * 24 Dec 1998 Added searching in "VFlib.fdb" file that contain file list
7 * 21 Sep 1999 Added a feature to generate PK & GF files on the fly.
8 *
9 */
10 /*
11 * Copyright (C) 1996-1999 Hirotsugu Kakugawa.
12 * All rights reserved.
13 *
14 * This file is part of the VFlib Library. This library is free
15 * software; you can redistribute it and/or modify it under the terms of
16 * the GNU Library General Public License as published by the Free
17 * Software Foundation; either version 2 of the License, or (at your
18 * option) any later version. This library is distributed in the hope
19 * that it will be useful, but WITHOUT ANY WARRANTY; without even the
20 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
21 * PURPOSE. See the GNU Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 #include "config.h"
28 #include "with.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
35 #include <sys/types.h>
36 #include <sys/param.h>
37
38 #ifdef HAVE_DIRENT_H
39
40 # include <dirent.h>
41 # define NAMLENGTH(dirent) strlen((dirent)->d_name)
/* [<][>][^][v][top][bottom][index][help] */
42
43 #else /* not DIRENT */
44
45 # define dirent direct
46 # define NAMLENGTH(dirent) ((dirent)->d_namlen)
/* [<][>][^][v][top][bottom][index][help] */
47
48 #ifdef HAVE_SYS_NDIR_H
49 # include <sys/ndir.h>
50 #endif
51
52 #ifdef HAVE_SYS_DIR_H
53 # include <sys/dir.h>
54 #endif
55
56 #ifdef HAVE_NDIR_H
57 # include <ndir.h>
58 #endif
59
60 #endif /* not DIRENT */
61
62 #ifdef HAVE_SYS_STAT_H
63 # ifdef __linux__
64 # define __USE_BSD
65 # endif
66 # include <sys/stat.h>
67 #endif
68
69 #include "VFlib-3_6.h"
70 #include "VFsys.h"
71 #include "consts.h"
72 #include "fsearch.h"
73 #include "texfonts.h"
74 #include "sexp.h"
75 #include "path.h"
76 #include "str.h"
77
78 #ifdef WITH_KPATHSEA
79 # include "kpathsea/kpathsea.h"
80 #endif
81
82
83 #ifdef HAVE_DIRENT_H
84 # ifdef HAVE_SYS_STAT_H
85 # ifdef HAVE_OPENDIR
86 # define RECURSIVE_FILE_SEARCH
87 # endif
88 # endif
89 #endif
90
91
92
93
94 /**
95 ** kpathsea
96 **/
97 Private int kps_switch = DEFAULT_KPS_SWITCH;
98 Private char *kps_mode = DEFAULT_KPS_MODE;
99 Private int kps_dpi = DEFAULT_KPS_DPI;
100 #ifdef WITH_KPATHSEA
101 Private char *kps_path = DEFAULT_KPS_PROGRAM_PATH;
102 #endif
103 Private char *kps_prog = DEFAULT_KPS_PROGRAM_NAME;
104
105
106 Glocal void
107 vf_kpathsea_init(char *prog, char *mode, int dpi, int kps_sw)
/* [<][>][^][v][top][bottom][index][help] */
108 {
109 #ifdef WITH_KPATHSEA
110 static int inited_prog = 0;
111 int f;
112 #endif
113
114 kps_switch = kps_sw;
115 kps_dpi = dpi;
116 if (mode != NULL)
117 kps_mode = mode;
118 if (prog != NULL)
119 kps_prog = prog;
120
121 #ifdef WITH_KPATHSEA
122 if (inited_prog == 1)
123 return;
124
125 inited_prog = 1;
126
127 if (vf_dbg_kpathsea == 1){
128 if (kps_switch == TRUE)
129 printf(">>Kpathsea: enabled\n");
130 else
131 printf(">>Kpathsea: disabled\n");
132 }
133
134 if (vf_dbg_kpathsea == 1)
135 printf(">>Kpathsea: mode=%s, dpi=%d program=%s\n",
136 kps_mode, kps_dpi, kps_prog);
137
138 kpse_set_program_name(kps_path, kps_prog);
139 kpse_init_prog(kps_prog, kps_dpi, kps_mode, NULL);
140 for (f = 0; f < kpse_last_format; f++) {
141 kpse_init_format(f);
142 }
143 #else
144 if (vf_dbg_kpathsea == 1)
145 printf(">>Kpathsea: disabled by configure\n");
146 #endif
147 }
148
149
150
151 /**
152 ** VF_AddUncompresser()
153 **/
154
155 Private SEXP_ALIST vf_uncompresser_alist = NULL;
156
157 Public int
158 vf_add_uncompresser_alist(SEXP_ALIST alist)
/* [<][>][^][v][top][bottom][index][help] */
159 {
160 SEXP t;
161
162 if (alist == NULL)
163 return 0;
164
165 if (!vf_sexp_alistp(alist)){
166 fprintf(stderr, "VFlib Error [fsearch.c:VF_AddUncompresser]: %s\n",
167 "Not an alist.");
168 return -1;
169 }
170
171 t = vf_uncompresser_alist;
172 vf_sexp_nconc(alist, t);
173 vf_uncompresser_alist = alist;
174
175 return 0;
176 }
177
178
179 Glocal FILE*
180 vf_open_uncompress_stream(char *compressed_file, char *uncompress_prog)
/* [<][>][^][v][top][bottom][index][help] */
181 {
182 #ifndef HAVE_POPEN
183
184 return NULL;
185
186 #else
187
188 FILE *fp;
189 char *cmdline;
190
191 cmdline = malloc(strlen(uncompress_prog) + strlen(compressed_file) + 16);
192 if (cmdline == NULL)
193 return NULL;
194 sprintf(cmdline, "%s %s", uncompress_prog, compressed_file);
195 fp = popen(cmdline, "r");
196 vf_free(cmdline);
197
198 return fp;
199
200 #endif /* HAVE_POPEN */
201 }
202
203 Glocal int
204 vf_close_uncompress_stream(FILE* fp)
/* [<][>][^][v][top][bottom][index][help] */
205 {
206 #ifdef HAVE_POPEN
207
208 if (fp != NULL){
209 pclose(fp);
210 }
211
212 #endif
213
214 return 0;
215 }
216
217
218
219 /**
220 ** Search a File
221 **/
222
223 Private char *search_in_fdb(char *name, char *dir,
224 SEXP_LIST compressed_ext_list,
225 char **p_uncompr_prog, int *ret_val);
226 Private int search_fdb_fp(FILE *fp, char *d, char *f,
227 char *ret_path, int ret_path_size);
228 Private char *search_file_kpathsea(char*,int,char*,int);
229 Private char *search_file(char*,char*,SEXP_LIST,char**);
230 Private char *search_file_recursive(char*, char*,SEXP_LIST,char**);
231 Private int ext2uncprog(char *ext, SEXP_LIST compressed_ext_list,
232 char **p_uncompr_prog);
233
234
235
236 Glocal char*
237 vf_search_file(char *name, int opt_arg1, char *opt_arg2,
/* [<][>][^][v][top][bottom][index][help] */
238 int use_kpathsea, int kpathsea_file_format,
239 SEXP_LIST dir_list,
240 SEXP_LIST compressed_ext_list, char **p_uncompr_prog)
241 /* NOTE: CALLER OF THIS FUNCTION *SHOULD* RELEASE RETURN VALUE.
242 (STRING RETURNED BY P_UNCOMPR_PROG SHOULD NOT BE RELEASED.) */
243 {
244 SEXP d;
245 char *path, *dir;
246 int v;
247
248 if (name == NULL)
249 return NULL;
250
251 if (vf_dbg_font_search == 1){
252 printf(">> File search: %s\n", name);
253 }
254
255 if (p_uncompr_prog != NULL)
256 *p_uncompr_prog = NULL;
257
258 if (vf_path_absolute(name)){
259 if (vf_path_file_read_ok(name)){
260 if (vf_dbg_font_search == 1)
261 printf(">> File search: Found %s\n", name);
262 return vf_strdup(name);
263 }
264 if (vf_dbg_font_search == 1)
265 printf(">> File search: Not found (no such absolute path)\n");
266 return NULL;
267 }
268
269 if ((dir_list == NULL) || (!vf_sexp_listp(dir_list))){
270 if (vf_dbg_font_search == 1)
271 printf(">> File search: Not found (empty dir list)\n");
272 return NULL;
273 }
274
275 path = NULL;
276 for (d = dir_list; vf_sexp_consp(d); d = vf_sexp_cdr(d)){
277 dir = vf_sexp_get_cstring(vf_sexp_car(d));
278 if (dir == NULL)
279 continue;
280 if ((vf_strcmp_ci(dir, "TEXMF") == 0)
281 || (vf_strcmp_ci(dir, "KPATHSEA") == 0)){
282 /* Search by 'KPATHSEA' */
283 if (use_kpathsea == FALSE){
284 fprintf(stderr,
285 "VFlib Warning: Unsupported file format by kpathsea.\n");
286 continue;
287 }
288 if (kps_switch == FALSE)
289 continue;
290 path = search_file_kpathsea(name, opt_arg1, opt_arg2,
291 kpathsea_file_format);
292 } else {
293 /* check font file hint db */
294 path = search_in_fdb(name, dir, compressed_ext_list, p_uncompr_prog, &v);
295 if (v == -2){
296 if (vf_path_terminated_by_2delims(dir) == FALSE){
297 /* Search under dir */
298 path = search_file(name, dir, compressed_ext_list, p_uncompr_prog);
299 } else {
300 /* Recursive search under dir */
301 path = search_file_recursive(name, dir,
302 compressed_ext_list, p_uncompr_prog);
303 }
304 }
305 }
306
307 if (path != NULL)
308 break;
309 }
310
311 if (vf_dbg_font_search == 1){
312 if (path != NULL){
313 printf(">> File search: Found %s\n", path);
314 } else {
315 printf(">> File search: Not found\n");
316 }
317 }
318
319 if (path == NULL)
320 return NULL;
321
322 return path;
323 }
324
325
326 Private char*
327 search_in_fdb(char *name, char *dir,
/* [<][>][^][v][top][bottom][index][help] */
328 SEXP_LIST compressed_ext_list, char **p_uncompr_prog,
329 int *p_ret_val)
330 /* NOTE: CALLER OF THIS FUNCTION *SHOULD* RELEASE RETURN VALUE. */
331 {
332 char fdb[MAXPATHLEN], name_ext[MAXPATHLEN], *path;
333 int pathsize;
334 FILE *fp;
335 SEXP s;
336 char *ext;
337
338 if (dir == NULL){
339 *p_ret_val = -2;
340 return NULL;
341 }
342
343 if ((vf_path_cons_path(fdb, sizeof(fdb), dir, VF_FONT_FILE_HINT_DB) < 0)
344 || (! vf_path_file_read_ok(fdb))
345 || ((fp = fopen(fdb, FOPEN_RD_MODE_TEXT)) == NULL)){
346 if (vf_dbg_font_search == 1)
347 printf(">> No font hint db file: %s\n", fdb);
348 *p_ret_val = -2; /* hint db not found */
349 return NULL;
350 }
351
352 if (vf_dbg_font_search == 1)
353 printf(">> Reading hint db file: %s\n", fdb);
354
355 pathsize = MAXPATHLEN;
356 ALLOCN_IF_ERR(path, char, pathsize){
357 *p_ret_val = -2; /* hint db not found */
358 fclose(fp);
359 return NULL;
360 }
361
362 /* look for font without compression */
363 if (search_fdb_fp(fp, dir, name, path, pathsize) >= 0){ /* found */
364 *p_ret_val = 0; /* found */
365 goto end;
366 }
367
368 /* look for font with compression */
369 *p_ret_val = -1;
370 for (s = compressed_ext_list; vf_sexp_consp(s); s = vf_sexp_cdr(s)){
371 ext = vf_sexp_get_cstring(vf_sexp_car(s));
372 strncpy(name_ext, name, sizeof(name_ext));
373 strncat(name_ext, ext, sizeof(name_ext) - strlen(name));
374 fseek(fp, 0, SEEK_SET);
375 if ((search_fdb_fp(fp, dir, name_ext, path, pathsize) >= 0)
376 && (ext2uncprog(ext, compressed_ext_list, p_uncompr_prog) >= 0)){
377 *p_ret_val = 0; /* found */
378 break;
379 }
380 }
381
382 end:
383 fclose(fp);
384 if (*p_ret_val != 0){
385 vf_free(path);
386 path = NULL;
387 }
388
389 if (vf_dbg_font_search == 1){
390 if (path != NULL)
391 printf(">> Found in db file: %s\n", path);
392 else
393 printf(">> Not found in db file\n");
394 }
395
396 return path;
397 }
398
399 Private int
400 search_fdb_fp(FILE *fp, char *d, char *f, char *ret_path, int ret_path_size)
/* [<][>][^][v][top][bottom][index][help] */
401 {
402 char linebuff[MAXPATHLEN], *p;
403 int flen, dlen, i;
404
405 if ((fp == NULL) || (d == NULL) || (f == NULL) || (ret_path == NULL))
406 return -1;
407
408 dlen = strlen(d);
409 flen = strlen(f);
410 while (fgets(linebuff, sizeof(linebuff), fp) != NULL){
411 if ((strncmp(f, linebuff, flen) == 0) && isspace((int)linebuff[flen])){
412 for (p = &linebuff[flen]; (*p != '\0') && isspace((int)*p); p++)
413 ;
414 if (*p == '\0')
415 break;
416 for (i = 0; p[i] != '\0'; i++){
417 if (isspace((int)p[i])){
418 p[i] = '\0';
419 break;
420 }
421 }
422 vf_path_cons_path(ret_path, ret_path_size, d, p);
423 return 0;
424 }
425 }
426
427 return -1;
428 }
429
430
431
432 Glocal char*
433 vf_find_file_in_directory(char *name, char *dir)
/* [<][>][^][v][top][bottom][index][help] */
434 /* NOTE: CALLER OF THIS FUNCTION *SHOULD* RELEASE RETURN VALUE. */
435 {
436 return search_file(name, dir, NULL, NULL);
437 }
438
439
440 Private char*
441 search_file_kpathsea(char *name, int dpi, char *name2, int file_format)
/* [<][>][^][v][top][bottom][index][help] */
442 /* NOTE: CALLER OF THIS FUNCTION *SHOULD* RELEASE RETURN VALUE. */
443 {
444 #ifndef WITH_KPATHSEA
445
446 return NULL;
447
448 #else
449
450 char *s;
451 kpse_glyph_file_type g_ret;
452
453 #if 0
454 printf("search_file_kpathsea(%s, %s, %d, %d)\n",
455 name, name2, dpi, file_format);
456 #endif
457
458 if (kps_switch == FALSE)
459 return NULL;
460
461 if (vf_dbg_kpathsea == 1)
462 printf(">> Kpathsea: Search %s\n", name);
463
464 s = NULL;
465
466 switch (file_format){
467 case FSEARCH_FORMAT_TYPE_GF:
468 s = kpse_find_gf(name2, dpi, &g_ret);
469 break;
470 case FSEARCH_FORMAT_TYPE_PK:
471 s = kpse_find_pk(name2, dpi, &g_ret);
472 break;
473 case FSEARCH_FORMAT_TYPE_VF:
474 s = kpse_find_vf(name);
475 if (s == NULL)
476 s = kpse_find_ovf(name);
477 break;
478 case FSEARCH_FORMAT_TYPE_TFM:
479 s = kpse_find_tfm(name);
480 if (s == NULL)
481 s = kpse_find_ofm(name);
482 break;
483 case FSEARCH_FORMAT_TYPE_OVF:
484 s = kpse_find_ovf(name);
485 break;
486 case FSEARCH_FORMAT_TYPE_OFM:
487 s = kpse_find_ofm(name);
488 break;
489 case FSEARCH_FORMAT_TYPE_TTF:
490 s = kpse_find_file(name, kpse_truetype_format, 0);
491 break;
492 case FSEARCH_FORMAT_TYPE_TYPE1:
493 s = kpse_find_file(name, kpse_type1_format, 0);
494 break;
495 case FSEARCH_FORMAT_TYPE_TYPE42:
496 s = kpse_find_file(name, kpse_type42_format, 0);
497 break;
498 case FSEARCH_FORMAT_TYPE_AFM:
499 s = kpse_find_file(name, kpse_afm_format, 0);
500 break;
501 case FSEARCH_FORMAT_TYPE_PSHEADER:
502 s = kpse_find_file(name, kpse_tex_ps_header_format, 0);
503 break;
504 default:
505 s = NULL;
506 break;
507 }
508
509 if (vf_dbg_kpathsea == 1){
510 if (s != NULL){
511 printf(">> Kpathsea: Found %s\n", s);
512 } else {
513 printf(">> Kpathsea: Not found\n");
514 }
515 }
516
517 if (s == NULL)
518 return NULL;
519
520 #if 0
521 return vf_strdup(s);
522 #else
523 return s;
524 #endif
525
526 #endif
527 }
528
529 Private char*
530 search_file(char *name, char *dir,
/* [<][>][^][v][top][bottom][index][help] */
531 SEXP_LIST compressed_ext_list, char **p_uncompr_prog)
532 /* NOTE: CALLER OF THIS FUNCTION *SHOULD* RELEASE RETURN VALUE. */
533 {
534 char *path;
535 char *ext = NULL;
536 int path_len, found;
537 SEXP s;
538
539 if ((dir != NULL) && (vf_path_directory_read_ok(dir) == FALSE))
540 return NULL;
541
542 if (dir == NULL)
543 dir = "";
544
545 path_len = strlen(dir) + strlen(name) + 64;
546 /* +64 for compressed extensions. Their lengths must be less 64. */
547 ALLOCN_IF_ERR(path, char, path_len){
548 vf_error = VF_ERR_NO_MEMORY;
549 return NULL;
550 }
551
552 /* search non-compressed file */
553 vf_path_cons_path(path, path_len, dir, name);
554 if (vf_path_file_read_ok(path))
555 return path;
556
557 if (compressed_ext_list == NULL){
558 vf_free(path);
559 return NULL;
560 }
561
562 /* search compressed file */
563 found = 0;
564 for (s = compressed_ext_list; vf_sexp_consp(s); s = vf_sexp_cdr(s)){
565 ext = vf_sexp_get_cstring(vf_sexp_car(s));
566 vf_path_cons_path2(path, path_len, dir, name, ext);
567 if (vf_path_file_read_ok(path) == TRUE){
568 found = 1;
569 break;
570 }
571 }
572 if (found == 0){
573 vf_free(path);
574 return NULL;
575 }
576
577 if (ext2uncprog(ext, compressed_ext_list, p_uncompr_prog) < 0){
578 vf_free(path);
579 path = NULL;
580 }
581
582 return path;
583 }
584
585
586 /* Obtain uncompression program name from extension */
587 Private int
588 ext2uncprog(char *ext, SEXP_LIST compressed_ext_list, char **p_uncompr_prog)
/* [<][>][^][v][top][bottom][index][help] */
589 /* NOTE: CALLER OF THIS FUNCTION *SHOULD NOT* RELEASE
590 RETURN VALUE IN P_UNCOMPR_PROG. */
591 {
592 char *uncext;
593 SEXP p, q;
594
595 if (p_uncompr_prog == NULL)
596 return -1;
597
598 *p_uncompr_prog = NULL;
599 for (q = vf_uncompresser_alist; vf_sexp_consp(q); q = vf_sexp_cdr(q)){
600 p = vf_sexp_car(q);
601 uncext = vf_sexp_get_cstring(vf_sexp_car(p));
602 if (strcmp(uncext, ext) == 0){
603 *p_uncompr_prog = vf_sexp_get_cstring(vf_sexp_cadr(p));
604 break;
605 }
606 }
607 if (*p_uncompr_prog == NULL){
608 fprintf(stderr, "VFlib Warning: %s %s\n",
609 "Undefined uncompression program for file extension", ext);
610 return -1;
611 }
612 if (vf_dbg_font_search == 1)
613 printf(">> Uncompression program: %s\n", *p_uncompr_prog);
614 return 0;
615 }
616
617
618 Glocal int
619 vf_tex_make_glyph(int type, char *font_name, int dpi, double mag)
/* [<][>][^][v][top][bottom][index][help] */
620 {
621
622 #ifndef WITH_KPATHSEA
623
624 return -1;
625
626 #else
627
628 char *name, *filename;
629 char *ext;
630 int kp_fmt;
631 kpse_glyph_file_type file_ret;
632
633 name = NULL;
634
635 switch (type){
636 case FSEARCH_FORMAT_TYPE_PK:
637 ext = "pk";
638 kp_fmt = kpse_pk_format;
639 break;
640 default:
641 return -1;
642 }
643
644 if ((name = vf_path_base_core(font_name)) == NULL)
645 return -1;
646
647 fprintf(stderr, "Generating %s.%d%s (dpi=%d, mag=%.3f)...\n",
648 name, (unsigned)(dpi*mag+0.5), ext, dpi, mag);
649 fflush(stderr);
650
651 kpse_set_program_enabled(kp_fmt, MAKE_TEX_PK_BY_DEFAULT, kpse_src_compile);
652
653 filename = kpse_find_glyph(name, (unsigned)(dpi*mag+0.5), kp_fmt, &file_ret);
654 if (filename == NULL){
655 fprintf(stderr, "\nFailed.\n");
656 vf_free(name);
657 return -1;
658 }
659
660 fprintf(stderr, "Done.\n");
661
662 vf_free(name);
663 return 0;
664
665 #endif /*WITH_KPATHSEA*/
666 }
667
668
669
670
671 #ifndef RECURSIVE_FILE_SEARCH
672
673 Private char*
674 search_file_recursive(char *name, char *dir,
/* [<][>][^][v][top][bottom][index][help] */
675 SEXP_LIST compressed_ext_list, char **p_uncompr_prog)
676 {
677 char *d, *path;
678 int len;
679
680 if (dir == NULL)
681 return NULL;
682
683 len = strlen(dir) + 1;
684 ALLOCN_IF_ERR(d, char, len){
685 vf_error = VF_ERR_NO_MEMORY;
686 return NULL;
687 }
688 strcpy(d, dir);
689
690 vf_path_del_terminating_2delims(d);
691 if (vf_path_directory_read_ok(d) == FALSE){
692 vf_free(d);
693 return NULL;
694 }
695 path = search_file(name, d, compressed_ext_list, p_uncompr_prog);
696
697 vf_free(d);
698 return path;
699 }
700
701 #else /*RECURSIVE_FILE_SEARCH*/
702
703 struct s_dtr_list {
704 char *name;
705 struct stat st;
706 struct s_dtr_list *prev;
707 struct s_dtr_list *next;
708 };
709 struct s_dtr_elem {
710 int path_index;
711 dev_t dev;
712 ino_t ino;
713 struct s_dtr_elem *next;
714 struct s_dtr_elem *prev;
715 struct s_dtr_list subdirs;
716 };
717 struct s_dtr {
718 char path[MAXPATHLEN];
719 struct s_dtr_elem *direc_head;
720 struct s_dtr_elem *direc_tail;
721 };
722
723 typedef struct s_dtr_list *DTR_LIST;
724 typedef struct s_dtr_elem *DTR_ELEM;
725 typedef struct s_dtr *DTR;
726
727 Private DTR dtr_alloc(char*);
728 Private void dtr_free(DTR);
729 Private char* dtr_get_path(DTR);
730 Private int dtr_add_name(DTR, char*, int);
731 Private void dtr_del_name(DTR);
732 Private int dtr_add_subdir(DTR, struct dirent*, struct stat*);
733 Private DTR_LIST dtr_subdir_list(DTR);
734 Private DTR_LIST dtr_next_subdir(DTR, DTR_LIST);
735 Private int dtr_go_subdir(DTR, DTR_LIST);
736 Private int dtr_go_updir(DTR);
737
738 Private char *traverse_directory(DTR, char*, SEXP_LIST, char**);
739
740
741 Private char*
742 search_file_recursive(char *name, char *dir,
/* [<][>][^][v][top][bottom][index][help] */
743 SEXP_LIST compressed_ext_list, char **p_uncompr_prog)
744 {
745 char *d, *path;
746 int len;
747 DTR dtr;
748
749 if (dir == NULL)
750 return NULL;
751
752 len = strlen(dir) + 1;
753 ALLOCN_IF_ERR(d, char, len){
754 vf_error = VF_ERR_NO_MEMORY;
755 return NULL;
756 }
757 strcpy(d, dir);
758 vf_path_del_terminating_2delims(d);
759
760 if (vf_path_directory_read_ok(d) == FALSE){
761 vf_free(d);
762 return NULL;
763 }
764
765 if (vf_dbg_font_search == 1)
766 printf(">> Search Recursively in: %s\n", d);
767
768 if ((dtr = dtr_alloc(d)) == NULL){
769 vf_free(d);
770 return NULL;
771 }
772
773 path = traverse_directory(dtr, name, compressed_ext_list, p_uncompr_prog);
774
775 dtr_free(dtr);
776 vf_free(d);
777
778 return path;
779 }
780
781 Private char*
782 traverse_directory(DTR dtr, char *name,
/* [<][>][^][v][top][bottom][index][help] */
783 SEXP_LIST compressed_ext_list, char **p_uncompr_prog)
784 {
785 char *path;
786 int v;
787 DIR *dir;
788 DTR_LIST sd;
789 struct dirent *ent;
790 struct stat st;
791
792 if (vf_dbg_font_search == 1)
793 printf(">> Searching in: %s\n", dtr_get_path(dtr));
794
795 /* search a file in a directory */
796 path = search_file(name, dtr_get_path(dtr),
797 compressed_ext_list, p_uncompr_prog);
798 if (path != NULL)
799 return path;
800
801 /* obtain a set of subdirectories in a directory */
802 if ((dir = opendir(dtr_get_path(dtr))) == NULL)
803 return NULL;
804 while ((ent = readdir(dir)) != NULL){
805 if ((NAMLENGTH(ent) == 1) && (strcmp(ent->d_name, ".") == 0))
806 continue;
807 if ((NAMLENGTH(ent) == 2) && (strcmp(ent->d_name, "..") == 0))
808 continue;
809
810 dtr_add_name(dtr, ent->d_name, NAMLENGTH(ent));
811 v = stat(dtr_get_path(dtr), &st);
812 dtr_del_name(dtr);
813 if (v < 0)
814 continue;
815 if ((st.st_mode & S_IFMT) == S_IFDIR){
816 dtr_add_subdir(dtr, ent, &st);
817 }
818 }
819 closedir(dir);
820
821 /* search a file under subdirectories */
822 path = NULL;
823 for (sd = dtr_subdir_list(dtr); sd != NULL; sd = dtr_next_subdir(dtr, sd)){
824 if (dtr_go_subdir(dtr, sd) >= 0){
825 path = traverse_directory(dtr, name,
826 compressed_ext_list, p_uncompr_prog);
827 if (path != NULL)
828 break;
829 dtr_go_updir(dtr);
830 }
831 }
832
833 return path;
834 }
835
836
837 Private DTR_ELEM
838 dtr_elem_alloc()
/* [<][>][^][v][top][bottom][index][help] */
839 {
840 DTR_ELEM dtr_elem;
841
842 if ((dtr_elem = (DTR_ELEM)malloc(sizeof(struct s_dtr_elem))) == NULL)
843 return NULL;
844
845 dtr_elem->path_index = 0;
846 dtr_elem->dev = 0;
847 dtr_elem->ino = 0;
848 dtr_elem->next = NULL;
849 dtr_elem->prev = NULL;
850 dtr_elem->subdirs.name = NULL;
851 dtr_elem->subdirs.prev = &dtr_elem->subdirs;
852 dtr_elem->subdirs.next = &dtr_elem->subdirs;
853 return dtr_elem;
854 }
855
856 Private void
857 dtr_elem_free(DTR_ELEM dtr_elem)
/* [<][>][^][v][top][bottom][index][help] */
858 {
859 DTR_LIST dl, dl_next;
860
861 dl = dtr_elem->subdirs.next;
862 while (dl != &dtr_elem->subdirs){
863 dl_next = dl->next;
864 vf_free(dl->name);
865 vf_free(dl);
866 dl = dl_next;
867 }
868 vf_free(dtr_elem);
869 }
870
871
872 Private DTR
873 dtr_alloc(char *topdir)
/* [<][>][^][v][top][bottom][index][help] */
874 {
875 DTR dtr;
876 DTR_ELEM dtr_elem;
877 struct stat st;
878
879 if ((dtr = (DTR)malloc(sizeof(struct s_dtr))) == NULL)
880 return NULL;
881 dtr->direc_head = NULL;
882 dtr->direc_tail = NULL;
883 strcpy(dtr->path, topdir);
884 vf_path_del_terminating_2delims(dtr->path);
885 if (stat(dtr->path, &st) < 0)
886 goto Error;
887
888 if ((dtr_elem = dtr_elem_alloc()) == NULL)
889 goto Error;
890 dtr->direc_head = dtr_elem;
891 dtr->direc_tail = dtr_elem;
892 dtr_elem->path_index = strlen(dtr->path);
893 dtr_elem->dev = st.st_dev;
894 dtr_elem->ino = st.st_ino;
895 return dtr;
896
897 Error:
898 dtr_free(dtr);
899 return NULL;
900 }
901
902 Private void
903 dtr_free(DTR dtr)
/* [<][>][^][v][top][bottom][index][help] */
904 {
905 DTR_ELEM dtr_elem, dtr_elem_next;
906
907 if (dtr == NULL)
908 return;
909 dtr_elem = dtr->direc_head;
910 while (dtr_elem != NULL){
911 dtr_elem_next = dtr_elem->next;
912 dtr_elem_free(dtr_elem);
913 dtr_elem = dtr_elem_next;
914 }
915 vf_free(dtr);
916 }
917
918 Private char*
919 dtr_get_path(DTR dtr)
/* [<][>][^][v][top][bottom][index][help] */
920 {
921 return dtr->path;
922 }
923
924 Private int
925 dtr_add_subdir(DTR dtr, struct dirent *ent, struct stat* st)
/* [<][>][^][v][top][bottom][index][help] */
926 {
927 DTR_LIST dl_new, dl_0, dl_1;
928
929 if ((dl_new = (DTR_LIST)malloc(sizeof(struct s_dtr_list))) == NULL)
930 return -1;
931 if ((dl_new->name = (char*)malloc(NAMLENGTH(ent)+1)) == NULL){
932 vf_free(dl_new);
933 return -1;
934 }
935
936 memcpy(dl_new->name, ent->d_name, NAMLENGTH(ent));
937 dl_new->name[NAMLENGTH(ent)] = '\0';
938 memcpy(&dl_new->st, st, sizeof(struct stat));
939
940 dl_0 = &dtr->direc_tail->subdirs;
941 dl_1 = dl_0->next;
942 dl_new->next = dl_1;
943 dl_new->prev = dl_0;
944 dl_0->next = dl_new;
945 dl_1->prev = dl_new;
946
947 return 0;
948 }
949
950 Private int
951 dtr_go_subdir(DTR dtr, DTR_LIST sd)
/* [<][>][^][v][top][bottom][index][help] */
952 {
953 DTR_ELEM dtr_elem, elem;
954
955 if (dtr_add_name(dtr, sd->name, strlen(sd->name)) < 0)
956 return -1;
957
958 for (elem = dtr->direc_head; elem != NULL; elem = elem->next){
959 if ((elem->dev == sd->st.st_dev) && (elem->ino == sd->st.st_ino)){
960 /* LOOP! */
961 dtr_del_name(dtr);
962 return -1;
963 }
964 }
965
966 if ((dtr_elem = dtr_elem_alloc()) == NULL){
967 dtr_del_name(dtr);
968 return -1;
969 }
970
971 dtr_elem->path_index = strlen(dtr->path);
972 dtr_elem->dev = sd->st.st_dev;
973 dtr_elem->ino = sd->st.st_ino;
974 dtr_elem->prev = dtr->direc_tail;
975 dtr->direc_tail->next = dtr_elem;
976 dtr->direc_tail = dtr_elem;
977
978 return 0;
979 }
980
981 Private int
982 dtr_go_updir(DTR dtr)
/* [<][>][^][v][top][bottom][index][help] */
983 {
984 DTR_ELEM tail_elem;
985
986 tail_elem = dtr->direc_tail;
987 if (tail_elem == NULL){
988 fprintf(stderr, "FATAL: CANNOT HAPPEN --- in dtr_go_updir().\n");
989 exit(1);
990 }
991 tail_elem->prev->next = NULL;
992 dtr->direc_tail = tail_elem->prev;
993 dtr_elem_free(tail_elem);
994
995 dtr_del_name(dtr);
996
997 return 0;
998 }
999
1000
1001 Private DTR_LIST
1002 dtr_subdir_list(DTR dtr)
/* [<][>][^][v][top][bottom][index][help] */
1003 {
1004 DTR_LIST sd;
1005 #if 0
1006 DTR_LIST ss;
1007
1008 ss = dtr->direc_tail->subdirs.prev;
1009 printf(" ");
1010 while (ss != &dtr->direc_tail->subdirs){
1011 printf("%s, ", ss->name);
1012 ss = ss->prev;
1013 }
1014 printf("\n");
1015 #endif
1016
1017 if ((sd = dtr->direc_tail->subdirs.prev) == &dtr->direc_tail->subdirs)
1018 return NULL;
1019
1020 return sd;
1021 }
1022
1023 Private DTR_LIST
1024 dtr_next_subdir(DTR dtr, DTR_LIST sd)
/* [<][>][^][v][top][bottom][index][help] */
1025 {
1026 DTR_LIST next;
1027
1028 if ((next = sd->prev) == &dtr->direc_tail->subdirs)
1029 return NULL;
1030 return next;
1031 }
1032
1033
1034 Private int
1035 dtr_add_name(DTR dtr, char *name, int len)
/* [<][>][^][v][top][bottom][index][help] */
1036 {
1037 char *p;
1038 int index;
1039
1040 index = dtr->direc_tail->path_index;
1041
1042 for (p = vf_directory_delimiter; *p != '\0'; p++){
1043 dtr->path[index++] = *p;
1044 }
1045 while (len > 0){
1046 dtr->path[index++] = *(name++);
1047 --len;
1048 }
1049 dtr->path[index] = '\0';
1050
1051 return 0;
1052 }
1053
1054 Private void
1055 dtr_del_name(DTR dtr)
/* [<][>][^][v][top][bottom][index][help] */
1056 {
1057 dtr->path[dtr->direc_tail->path_index] = '\0';
1058 }
1059
1060 #endif /* RECURSIVE_FILE_SEARCH */
1061
1062
1063
1064
1065 #if 0
1066
1067 Private int
1068 recursive_searcher(char *path, struct dirent *ent, struct stat *st)
/* [<][>][^][v][top][bottom][index][help] */
1069 {
1070 SEXP_ALIST iter, q, s;
1071 char *ext, *uncext, *uncprog;
1072 int ext_len;
1073
1074 if (rec_target_file_len > NAMLENGTH(ent))
1075 return -1;
1076 if (strncmp(ent->d_name, rec_target_file, rec_target_file_len) != 0)
1077 return -1;
1078
1079 if ((rec_target_file_len == NAMLENGTH(ent))
1080 && (strncmp(rec_target_file, ent->d_name, NAMLENGTH(ent)) == 0)){
1081 recursive_searcher_found(path);
1082 return 1;
1083 }
1084
1085 if (rec_compressed_ext != NULL){
1086 for (iter = rec_compressed_ext;
1087 vf_sexp_consp(iter);
1088 iter = vf_sexp_cdr(iter)){
1089 ext = vf_sexp_get_cstring(vf_sexp_car(iter));
1090 if ((ext == NULL) || (strcmp(ext, "") == 0))
1091 continue;
1092 ext_len = strlen(ext);
1093 if ((ext_len == (NAMLENGTH(ent) - rec_target_file_len))
1094 && (strncmp(&ent->d_name[rec_target_file_len], ext, ext_len) == 0)){
1095 uncprog = NULL;
1096 for (s = vf_uncompresser_alist; vf_sexp_consp(s); s = vf_sexp_cdr(s)){
1097 q = vf_sexp_car(s);
1098 uncext = vf_sexp_get_cstring(vf_sexp_car(q));
1099 if (strcmp(uncext, ext) == 0){
1100 uncprog = vf_sexp_get_cstring(vf_sexp_cadr(q));
1101 break;
1102 }
1103 }
1104 if (rec_p_uncompression_program != NULL)
1105 *rec_p_uncompression_program = uncprog;
1106 if (uncprog == NULL){
1107 fprintf(stderr, "VFlib Warning: %s %s\n",
1108 "Undefined compression program for file extension", ext);
1109 return -1;
1110 }
1111 if (vf_dbg_font_search == 1)
1112 printf(">> Uncompression program: %s\n", uncprog);
1113 recursive_searcher_found(path);
1114 return 1;
1115 }
1116 }
1117 }
1118
1119 return -1;
1120 }
1121
1122 Private void
1123 recursive_searcher_found(char *path)
/* [<][>][^][v][top][bottom][index][help] */
1124 {
1125 int len;
1126
1127 if ((len = strlen(file_path) + 32) > file_path_length){
1128 vf_free(file_path);
1129 file_path_length = len;
1130 ALLOCN_IF_ERR(file_path, char, file_path_length){
1131 file_path_length = 0;
1132 vf_error = VF_ERR_NO_MEMORY;
1133 return;
1134 }
1135 }
1136 strcpy(file_path, path);
1137 rec_found_file = file_path;
1138 }
1139
1140 #endif
1141
1142 /*EOF*/