Remove call to gnutls_global_init. tcpip_init already does it
[yaz-moved-to-github.git] / src / file_glob.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 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 <stdlib.h>
18 #include <assert.h>
19 #include <yaz/wrbuf.h>
20 #include <yaz/tpath.h>
21 #include <yaz/log.h>
22 #include <yaz/dirent.h>
23 #include <yaz/nmem.h>
24 #include <yaz/file_glob.h>
25 #include <yaz/match_glob.h>
26
27 struct res_entry {
28     struct res_entry *next;
29     char *file;
30 };
31
32 struct glob_res {
33     NMEM nmem;
34     unsigned flags;
35     size_t number_of_entries;
36     struct res_entry **last_entry;
37     struct res_entry *entries;
38 };
39
40 static void add_entry(yaz_glob_res_t res, const char *str)
41 {
42     struct res_entry *ent =
43         nmem_malloc(res->nmem, sizeof(*ent));
44     ent->file = nmem_strdup(res->nmem, str);
45     ent->next = 0;
46     *res->last_entry = ent;
47     res->last_entry = &ent->next;
48     res->number_of_entries++;
49 }
50
51 static void glob_r(yaz_glob_res_t res, const char *pattern, size_t off,
52                    char *prefix)
53 {
54     size_t prefix_len = strlen(prefix);
55     int is_pattern = 0;
56     size_t i = off;
57     while (pattern[i] && !strchr("/\\", pattern[i]))
58     {
59         if (strchr("?*", pattern[i]))
60             is_pattern = 1;
61         i++;
62     }
63
64     if (!is_pattern && pattern[i]) /* no pattern and directory part */
65     {
66         i++; /* skip dir sep */
67         memcpy(prefix + prefix_len, pattern + off, i - off);
68         prefix[prefix_len + i - off] = '\0';
69         glob_r(res, pattern, i, prefix);
70         prefix[prefix_len] = '\0';
71     }
72     else if ((res->flags & YAZ_FILE_GLOB_FAIL_NOTEXIST) &&
73              !is_pattern && !pattern[i])
74     {
75         strcpy(prefix + prefix_len, pattern + off);
76         add_entry(res, prefix);
77     }
78     else
79     {
80         DIR * dir = opendir(*prefix ? prefix : "." );
81
82         if (dir)
83         {
84             struct dirent *ent;
85
86             while ((ent = readdir(dir)))
87             {
88                 int r;
89                 memcpy(prefix + prefix_len, pattern + off, i - off);
90                 prefix[prefix_len + i - off] = '\0';
91                 r = yaz_match_glob(prefix + prefix_len, ent->d_name);
92                 prefix[prefix_len] = '\0';
93
94                 if (r)
95                 {
96                     strcpy(prefix + prefix_len, ent->d_name);
97                     if (pattern[i])
98                     {
99                         glob_r(res, pattern, i, prefix);
100                     }
101                     else
102                     {
103                         add_entry(res, prefix);
104                     }
105                     prefix[prefix_len] = '\0';
106                 }
107             }
108             closedir(dir);
109         }
110     }
111 }
112
113 static int cmp_entry(const void *a, const void *b)
114 {
115     struct res_entry *ent_a = *(struct res_entry **) a;
116     struct res_entry *ent_b = *(struct res_entry **) b;
117     return strcmp(ent_a->file, ent_b->file);
118 }
119
120 static void sort_them(yaz_glob_res_t res)
121 {
122     size_t i;
123     struct res_entry **ent_p;
124     struct res_entry **ent = nmem_malloc(res->nmem, sizeof(*ent) * res->number_of_entries);
125     struct res_entry *ent_i = res->entries;
126     for (i = 0; i < res->number_of_entries; i++)
127     {
128         ent[i] = ent_i;
129         ent_i = ent_i->next;
130     }
131     qsort(ent, res->number_of_entries, sizeof(*ent), cmp_entry);
132     ent_p = &res->entries;
133     for (i = 0; i < res->number_of_entries; i++)
134     {
135         *ent_p = ent[i];
136         ent_p = &ent[i]->next;
137     }
138     *ent_p = 0;
139 }
140
141 int yaz_file_glob(const char *pattern, yaz_glob_res_t *res)
142 {
143     return yaz_file_glob2(pattern, res, 0);
144 }
145
146 int yaz_file_glob2(const char *pattern, yaz_glob_res_t *res, unsigned flags)
147 {
148     char prefix[FILENAME_MAX+1];
149     NMEM nmem = nmem_create();
150
151     *prefix = '\0';
152     *res = nmem_malloc(nmem, sizeof(**res));
153     (*res)->flags = flags;
154     (*res)->number_of_entries = 0;
155     (*res)->nmem = nmem;
156     (*res)->entries = 0;
157     (*res)->last_entry = &(*res)->entries;
158     glob_r(*res, pattern, 0, prefix);
159     sort_them(*res);
160     return 0;
161 }
162
163 void yaz_file_globfree(yaz_glob_res_t *res)
164 {
165     if (*res)
166     {
167         /* must free entries as well */
168         nmem_destroy((*res)->nmem);
169         *res = 0;
170     }
171 }
172
173 const char *yaz_file_glob_get_file(yaz_glob_res_t res, size_t idx)
174 {
175     struct res_entry *ent = res->entries;
176     while (idx && ent)
177     {
178         ent = ent->next;
179         idx--;
180     }
181     if (!ent)
182         return 0;
183     return ent->file;
184 }
185
186 size_t yaz_file_glob_get_num(yaz_glob_res_t res)
187 {
188     return res->number_of_entries;
189 }
190
191 /*
192  * Local variables:
193  * c-basic-offset: 4
194  * c-file-style: "Stroustrup"
195  * indent-tabs-mode: nil
196  * End:
197  * vim: shiftwidth=4 tabstop=8 expandtab
198  */
199