1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23: #include <config.h>
24:
25: #include <stdbool.h>
26:
27: #include <ctype.h>
28: #include <errno.h>
29: #include <stddef.h>
30: #include <stdio.h>
31: #include <stdlib.h>
32: #include <string.h>
33:
34: #include "exclude.h"
35: #include "fnmatch.h"
36: #include "xalloc.h"
37: #include "verify.h"
38:
39: #if USE_UNLOCKED_IO
40: # include "unlocked-io.h"
41: #endif
42:
43:
44: #ifndef FNM_CASEFOLD
45: # define FNM_CASEFOLD 0
46: #endif
47: #ifndef FNM_EXTMATCH
48: # define FNM_EXTMATCH 0
49: #endif
50: #ifndef FNM_LEADING_DIR
51: # define FNM_LEADING_DIR 0
52: #endif
53:
54: verify (((EXCLUDE_ANCHORED | EXCLUDE_INCLUDE | EXCLUDE_WILDCARDS)
55: & (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR
56: | FNM_CASEFOLD | FNM_EXTMATCH))
57: == 0);
58:
59:
60:
61:
62: struct patopts
63: {
64: char const *pattern;
65: int options;
66: };
67:
68:
69:
70: struct exclude
71: {
72: struct patopts *exclude;
73: size_t exclude_alloc;
74: size_t exclude_count;
75: };
76:
77:
78:
79: struct exclude *
80: new_exclude (void)
81: {
82: return xzalloc (sizeof *new_exclude ());
83: }
84:
85:
86:
87: void
88: free_exclude (struct exclude *ex)
89: {
90: free (ex->exclude);
91: free (ex);
92: }
93:
94:
95:
96:
97: static int
98: fnmatch_no_wildcards (char const *pattern, char const *f, int options)
99: {
100: if (! (options & FNM_LEADING_DIR))
101: return ((options & FNM_CASEFOLD)
102: ? mbscasecmp (pattern, f)
103: : strcmp (pattern, f));
104: else if (! (options & FNM_CASEFOLD))
105: {
106: size_t patlen = strlen (pattern);
107: int r = strncmp (pattern, f, patlen);
108: if (! r)
109: {
110: r = f[patlen];
111: if (r == '/')
112: r = 0;
113: }
114: return r;
115: }
116: else
117: {
118:
119:
120:
121:
122:
123:
124:
125: char *fcopy = xstrdup (f);
126: char *p;
127: int r;
128: for (p = fcopy; ; *p++ = '/')
129: {
130: p = strchr (p, '/');
131: if (p)
132: *p = '\0';
133: r = mbscasecmp (pattern, fcopy);
134: if (!p || r <= 0)
135: break;
136: }
137: free (fcopy);
138: return r;
139: }
140: }
141:
142: bool
143: exclude_fnmatch (char const *pattern, char const *f, int options)
144: {
145: int (*matcher) (char const *, char const *, int) =
146: (options & EXCLUDE_WILDCARDS
147: ? fnmatch
148: : fnmatch_no_wildcards);
149: bool matched = ((*matcher) (pattern, f, options) == 0);
150: char const *p;
151:
152: if (! (options & EXCLUDE_ANCHORED))
153: for (p = f; *p && ! matched; p++)
154: if (*p == '/' && p[1] != '/')
155: matched = ((*matcher) (pattern, p + 1, options) == 0);
156:
157: return matched;
158: }
159:
160:
161:
162: bool
163: excluded_file_name (struct exclude const *ex, char const *f)
164: {
165: size_t exclude_count = ex->exclude_count;
166:
167:
168: if (exclude_count == 0)
169: return false;
170: else
171: {
172: struct patopts const *exclude = ex->exclude;
173: size_t i;
174:
175:
176: bool excluded = !! (exclude[0].options & EXCLUDE_INCLUDE);
177:
178:
179:
180: for (i = 0; i < exclude_count; i++)
181: {
182: char const *pattern = exclude[i].pattern;
183: int options = exclude[i].options;
184: if (excluded == !! (options & EXCLUDE_INCLUDE))
185: excluded ^= exclude_fnmatch (pattern, f, options);
186: }
187:
188: return excluded;
189: }
190: }
191:
192:
193:
194: void
195: add_exclude (struct exclude *ex, char const *pattern, int options)
196: {
197: struct patopts *patopts;
198:
199: if (ex->exclude_count == ex->exclude_alloc)
200: ex->exclude = x2nrealloc (ex->exclude, &ex->exclude_alloc,
201: sizeof *ex->exclude);
202:
203: patopts = &ex->exclude[ex->exclude_count++];
204: patopts->pattern = pattern;
205: patopts->options = options;
206: }
207:
208:
209:
210:
211:
212:
213: int
214: add_exclude_file (void (*add_func) (struct exclude *, char const *, int),
215: struct exclude *ex, char const *file_name, int options,
216: char line_end)
217: {
218: bool use_stdin = file_name[0] == '-' && !file_name[1];
219: FILE *in;
220: char *buf = NULL;
221: char *p;
222: char const *pattern;
223: char const *lim;
224: size_t buf_alloc = 0;
225: size_t buf_count = 0;
226: int c;
227: int e = 0;
228:
229: if (use_stdin)
230: in = stdin;
231: else if (! (in = fopen (file_name, "r")))
232: return -1;
233:
234: while ((c = getc (in)) != EOF)
235: {
236: if (buf_count == buf_alloc)
237: buf = x2realloc (buf, &buf_alloc);
238: buf[buf_count++] = c;
239: }
240:
241: if (ferror (in))
242: e = errno;
243:
244: if (!use_stdin && fclose (in) != 0)
245: e = errno;
246:
247: buf = xrealloc (buf, buf_count + 1);
248: buf[buf_count] = line_end;
249: lim = buf + buf_count + ! (buf_count == 0 || buf[buf_count - 1] == line_end);
250: pattern = buf;
251:
252: for (p = buf; p < lim; p++)
253: if (*p == line_end)
254: {
255: char *pattern_end = p;
256:
257: if (isspace ((unsigned char) line_end))
258: {
259: for (; ; pattern_end--)
260: if (pattern_end == pattern)
261: goto next_pattern;
262: else if (! isspace ((unsigned char) pattern_end[-1]))
263: break;
264: }
265:
266: *pattern_end = '\0';
267: (*add_func) (ex, pattern, options);
268:
269: next_pattern:
270: pattern = p + 1;
271: }
272:
273: errno = e;
274: return e ? -1 : 0;
275: }