Add yaz_parse_facet_list with helper functions
[yaz-moved-to-github.git] / src / file_glob.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2010 Index Data
3  * See the file LICENSE for details.
4  */
5
6 /** \file 
7     \brief File globbing (ala POSIX glob, but simpler)
8 */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <assert.h>
18 #include <yaz/wrbuf.h>
19 #include <yaz/tpath.h>
20 #include <yaz/log.h>
21 #include <yaz/dirent.h>
22 #include <yaz/nmem.h>
23 #include <yaz/file_glob.h>
24 #include <yaz/match_glob.h>
25
26 struct res_entry {
27     struct res_entry *next;
28     char *file;
29 };
30
31 struct glob_res {
32     NMEM nmem;
33     size_t number_of_entries;
34     struct res_entry **last_entry;
35     struct res_entry *entries;
36 };
37
38 static void glob_r(yaz_glob_res_t res, const char *pattern, size_t off,
39                    char *prefix)
40 {
41     size_t prefix_len = strlen(prefix);
42     int is_pattern = 0;
43     size_t i = off;
44     while (pattern[i] && !strchr("/\\", pattern[i]))
45     {
46         if (strchr("?*", pattern[i]))
47             is_pattern = 1;
48         i++;
49     }
50     
51     if (!is_pattern && pattern[i]) /* no pattern and directory part */
52     {
53         i++; /* skip dir sep */
54         memcpy(prefix + prefix_len, pattern + off, i - off);
55         prefix[prefix_len + i - off] = '\0';
56         glob_r(res, pattern, i, prefix);
57         prefix[prefix_len] = '\0';
58     }
59     else
60     {
61         DIR * dir = opendir(*prefix ? prefix : "." );
62
63         if (dir)
64         {
65             struct dirent *ent;
66
67             while ((ent = readdir(dir)))
68             {
69                 int r;
70                 memcpy(prefix + prefix_len, pattern + off, i - off);
71                 prefix[prefix_len + i - off] = '\0';
72                 r = yaz_match_glob(prefix + prefix_len, ent->d_name);
73                 prefix[prefix_len] = '\0';
74
75                 if (r)
76                 {
77                     strcpy(prefix + prefix_len, ent->d_name);
78                     if (pattern[i])
79                     {
80                         glob_r(res, pattern, i, prefix);
81                     }
82                     else
83                     {
84                         struct res_entry *ent =
85                             nmem_malloc(res->nmem, sizeof(*ent));
86                         ent->file = nmem_strdup(res->nmem, prefix);
87                         ent->next = 0;
88                         *res->last_entry = ent;
89                         res->last_entry = &ent->next;
90                         res->number_of_entries++;
91                     }
92                     prefix[prefix_len] = '\0';
93                 }
94             }
95             closedir(dir);
96         }
97     }
98 }
99
100 int yaz_file_glob(const char *pattern, yaz_glob_res_t *res)
101 {
102     char prefix[FILENAME_MAX+1];
103     NMEM nmem = nmem_create();
104
105     *prefix = '\0';
106     *res = nmem_malloc(nmem, sizeof(**res));
107     (*res)->number_of_entries = 0;
108     (*res)->nmem = nmem;
109     (*res)->entries = 0;
110     (*res)->last_entry = &(*res)->entries;
111     glob_r(*res, pattern, 0, prefix);
112     return 0;
113 }
114
115 void yaz_file_globfree(yaz_glob_res_t *res)
116 {
117     if (*res)
118     {
119         /* must free entries as well */
120         nmem_destroy((*res)->nmem);
121         *res = 0;
122     }
123 }
124
125 const char *yaz_file_glob_get_file(yaz_glob_res_t res, size_t idx)
126 {
127     struct res_entry *ent = res->entries;
128     while (idx && ent)
129     {
130         ent = ent->next;
131         idx--;
132     }
133     if (!ent)
134         return 0;
135     return ent->file;
136 }
137
138 size_t yaz_file_glob_get_num(yaz_glob_res_t res)
139 {
140     return res->number_of_entries;
141 }
142
143 /*
144  * Local variables:
145  * c-basic-offset: 4
146  * c-file-style: "Stroustrup"
147  * indent-tabs-mode: nil
148  * End:
149  * vim: shiftwidth=4 tabstop=8 expandtab
150  */
151