GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-f22b1278f8
ls_filter.c
Go to the documentation of this file.
1 /*!
2  * \file lib/gis/ls_filter.c
3  *
4  * \brief GIS Library - Filename filter functions
5  *
6  * (C) 2010 by Glynn Clements and the GRASS Development Team
7  *
8  * This program is free software under the GNU General Public License
9  * (>=v2). Read the file COPYING that comes with GRASS for details.
10  *
11  * \author Original author Glynn Clements
12  */
13 
14 #include <grass/config.h>
15 #include <grass/gis.h>
16 #ifdef HAVE_REGEX_H
17 #include <regex.h>
18 #endif
19 
20 #ifdef HAVE_PCRE_H
21 #include <string.h>
22 #include <pcre.h>
23 #endif
24 
25 struct buffer {
26  char *buf;
27  size_t len;
28  size_t alloc;
29 };
30 
31 static void init(struct buffer *buf)
32 {
33  buf->buf = NULL;
34  buf->len = 0;
35  buf->alloc = 0;
36 }
37 
38 static void add(struct buffer *buf, char c)
39 {
40  if (buf->len >= buf->alloc) {
41  buf->alloc += 50;
42  buf->buf = G_realloc(buf->buf, buf->alloc);
43  }
44 
45  buf->buf[buf->len++] = c;
46 }
47 
48 static void fini(struct buffer *buf)
49 {
50  G_free(buf->buf);
51 }
52 
53 static const char *do_set(struct buffer *buf, const char *p)
54 {
55  add(buf, '[');
56 
57  if (*p == '!') {
58  add(buf, '^');
59  p++;
60  }
61 
62  if (*p == ']') {
63  add(buf, ']');
64  p++;
65  }
66 
67  for (; *p && *p != ']'; p++)
68  add(buf, *p);
69 
70  if (!*p)
71  return NULL;
72 
73  add(buf, ']');
74 
75  return p;
76 }
77 
78 static int wc2regex(struct buffer *buf, const char *pat)
79 {
80  const char *p;
81  int in_brace = 0;
82 
83  init(buf);
84 
85  add(buf, '^');
86 
87  for (p = pat; p && *p; p++) {
88  switch (*p) {
89  case '\\':
90  add(buf, '\\');
91  if (!*++p)
92  return 0;
93  add(buf, *p);
94  break;
95  case '.':
96  case '|':
97  case '(':
98  case ')':
99  case '+':
100  add(buf, '\\');
101  add(buf, *p);
102  break;
103  case '*':
104  add(buf, '.');
105  add(buf, '*');
106  break;
107  case '?':
108  add(buf, '.');
109  break;
110  case '{':
111  in_brace++;
112  add(buf, '(');
113  break;
114  case '}':
115  if (!in_brace)
116  return 0;
117  in_brace--;
118  add(buf, ')');
119  break;
120  case ',':
121  if (in_brace)
122  add(buf, '|');
123  else
124  add(buf, ',');
125  break;
126  case '[':
127  if (!(p = do_set(buf, p)))
128  return 0;
129  break;
130  default:
131  add(buf, *p);
132  break;
133  }
134  }
135 
136  if (!p)
137  return 0;
138 
139  if (in_brace)
140  return 0;
141 
142  add(buf, '$');
143  add(buf, '\0');
144 
145  return 1;
146 }
147 
148 static int re_filter(const char *filename, void *closure)
149 {
150 #ifdef HAVE_REGEX_H
151  regex_t *regex = closure;
152 
153  return filename[0] != '.' && regexec(regex, filename, 0, NULL, 0) == 0;
154 #endif
155 #ifdef HAVE_PCRE_H
156  const char *pcreErrorStr;
157  pcre_extra *pcreExtra;
158  int pcreExecRet;
159  pcre *pcre_regex = closure;
160 
161  /* Optimize the regex */
162  pcreExtra = pcre_study(pcre_regex, 0, &pcreErrorStr);
163  pcreExecRet = pcre_exec(pcre_regex, pcreExtra, filename,
164  strlen(filename), /* length of string */
165  0, /* Start looking at this point */
166  0, /* OPTIONS */
167  NULL, 0); /* Length of subStrVec */
168 
169  return filename[0] != '.' && pcreExecRet == 0;
170 #endif
171 }
172 
173 void *G_ls_regex_filter(const char *pat, int exclude, int extended,
174  int ignorecase)
175 {
176 #ifdef HAVE_REGEX_H
177  regex_t *regex = G_malloc(sizeof(regex_t));
178 
179  if (regcomp(regex, pat,
180  REG_NOSUB | (extended ? REG_EXTENDED : 0) |
181  (ignorecase ? REG_ICASE : 0)) != 0) {
182  G_free(regex);
183  return NULL;
184  }
185 
186  if (exclude)
187  G_set_ls_exclude_filter(re_filter, regex);
188  else
189  G_set_ls_filter(re_filter, regex);
190 
191  return regex;
192 #endif
193 
194 #ifdef HAVE_PCRE_H
195  pcre *pcre_regex;
196  const char *pcreErrorStr;
197  int pcreErrorOffset;
198 
199  /* First, the regex string must be compiled */
200  pcre_regex = pcre_compile(pat, 0, &pcreErrorStr, &pcreErrorOffset, NULL);
201  /*
202  if (regcomp(regex, pat, REG_NOSUB |
203  (extended ? REG_EXTENDED : 0) |
204  (ignorecase ? REG_ICASE : 0)) != 0) {
205  pcre_free(pcre_regex);
206  return NULL;
207  }
208  */
209  if (exclude)
210  G_set_ls_exclude_filter(re_filter, pcre_regex);
211  else
212  G_set_ls_filter(re_filter, pcre_regex);
213 
214  /* First, the regex string must be compiled */
215  pcre_regex = pcre_compile(pat, 0, &pcreErrorStr, &pcreErrorOffset, NULL);
216  /*
217  if (regcomp(regex, pat, REG_NOSUB |
218  (extended ? REG_EXTENDED : 0) |
219  (ignorecase ? REG_ICASE : 0)) != 0) {
220  pcre_free(pcre_regex);
221  return NULL;
222  }
223  */
224  if (exclude)
225  G_set_ls_exclude_filter(re_filter, pcre_regex);
226  else
227  G_set_ls_filter(re_filter, pcre_regex);
228 
229  return pcre_regex;
230 #endif
231 }
232 
233 void *G_ls_glob_filter(const char *pat, int exclude, int ignorecase)
234 {
235  struct buffer buf;
236 
237 #ifdef HAVE_REGEX_H
238  regex_t *regex;
239 #endif
240 #ifdef HAVE_PCRE_H
241  pcre *pcre_regex;
242 #endif
243 
244  init(&buf);
245 
246  if (!wc2regex(&buf, pat)) {
247  fini(&buf);
248  return NULL;
249  }
250 #ifdef HAVE_REGEX_H
251  regex = G_ls_regex_filter(buf.buf, exclude, 1, ignorecase);
252 #endif
253 #ifdef HAVE_PCRE_H
254  pcre_regex = G_ls_regex_filter(buf.buf, exclude, 1, ignorecase);
255 #endif
256 
257  fini(&buf);
258 
259 #ifdef HAVE_REGEX_H
260  return regex;
261 #endif
262 #ifdef HAVE_PCRE_H
263  return pcre_regex;
264 #endif
265 }
266 
267 void G_free_ls_filter(void *regex)
268 {
269  if (!regex)
270  return;
271 #ifdef HAVE_REGEX_H
272  regfree(regex);
273 #endif
274 #ifdef HAVE_PCRE_H
275  pcre_free(regex);
276 #endif
277 }
void init(double work[])
Definition: as177.c:61
#define NULL
Definition: ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
#define G_malloc(n)
Definition: defs/gis.h:94
void G_set_ls_exclude_filter(int(*)(const char *, void *), void *)
void G_set_ls_filter(int(*)(const char *, void *), void *)
void * G_ls_glob_filter(const char *pat, int exclude, int ignorecase)
Definition: ls_filter.c:233
void * G_ls_regex_filter(const char *pat, int exclude, int extended, int ignorecase)
Definition: ls_filter.c:173
void G_free_ls_filter(void *regex)
Definition: ls_filter.c:267