YAZ  5.23.1
file_glob.c
Go to the documentation of this file.
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 
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 {
34  unsigned flags;
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 
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 
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 
struct res_entry ** last_entry
Definition: file_glob.c:36
static void glob_r(yaz_glob_res_t res, const char *pattern, size_t off, char *prefix)
Definition: file_glob.c:51
File globbing (ala POSIX glob, but simpler)
size_t yaz_file_glob_get_num(yaz_glob_res_t res)
return number of matching files
Definition: file_glob.c:186
int yaz_file_glob2(const char *pattern, yaz_glob_res_t *res, unsigned flags)
perform glob (with flags)
Definition: file_glob.c:146
Header for WRBUF (growing buffer)
struct res_entry * entries
Definition: file_glob.c:37
void nmem_destroy(NMEM n)
destroys NMEM handle and memory associated with it
Definition: nmem.c:204
size_t number_of_entries
Definition: file_glob.c:35
int yaz_match_glob(const char *glob, const char *text)
matches a glob expression against text
Definition: match_glob.c:21
void * nmem_malloc(NMEM n, size_t size)
allocates memory block on NMEM handle
Definition: nmem.c:145
wrapper for dirent.h or our own for Windows
#define YAZ_FILE_GLOB_FAIL_NOTEXIST
Definition: file_glob.h:43
char * file
Definition: file_glob.c:29
struct res_entry * next
Definition: file_glob.c:28
File Path utilities.
char * nmem_strdup(NMEM mem, const char *src)
allocates string on NMEM handle (similar strdup)
Definition: nmemsdup.c:18
int yaz_file_glob(const char *pattern, yaz_glob_res_t *res)
perform glob
Definition: file_glob.c:141
NMEM nmem
Definition: file_glob.c:33
Glob expression matcher.
unsigned flags
Definition: file_glob.c:34
Header for Nibble Memory functions.
NMEM nmem_create(void)
returns new NMEM handle
Definition: nmem.c:181
static void sort_them(yaz_glob_res_t res)
Definition: file_glob.c:120
static void add_entry(yaz_glob_res_t res, const char *str)
Definition: file_glob.c:40
void yaz_file_globfree(yaz_glob_res_t *res)
release glob result
Definition: file_glob.c:163
const char * yaz_file_glob_get_file(yaz_glob_res_t res, size_t idx)
return resulting matching file
Definition: file_glob.c:173
Logging utility.
static int cmp_entry(const void *a, const void *b)
Definition: file_glob.c:113
Definition: file_glob.c:27