4 * Wildcard pattern matching functions.
8 * Copyright (C) 2013, 2015 Eric Biggers
10 * This file is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU Lesser General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option) any
15 * This file is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this file; if not, see https://www.gnu.org/licenses/.
30 #include "wimlib/dentry.h"
31 #include "wimlib/encoding.h"
32 #include "wimlib/paths.h"
33 #include "wimlib/pattern.h"
36 string_matches_pattern(const tchar *string, const tchar * const string_end,
37 const tchar *pattern, const tchar * const pattern_end)
39 for (; string != string_end; string++, pattern++) {
40 if (pattern == pattern_end)
42 if (*pattern == T('*')) {
43 return string_matches_pattern(string, string_end,
44 pattern + 1, pattern_end) ||
45 string_matches_pattern(string + 1, string_end,
46 pattern, pattern_end);
48 if (*string != *pattern && *pattern != T('?') &&
49 !(default_ignore_case &&
50 totlower(*string) == totlower(*pattern)))
54 while (pattern != pattern_end && *pattern == T('*'))
56 return pattern == pattern_end;
59 /* Advance past zero or more path separators. */
61 advance_to_next_component(const tchar *p)
63 while (*p == WIM_PATH_SEPARATOR)
68 /* Advance past a nonempty path component. */
70 advance_through_component(const tchar *p)
74 } while (*p && *p != WIM_PATH_SEPARATOR);
79 * Determine whether a path matches a wildcard pattern.
82 * The null-terminated path string to match.
84 * The null-terminated wildcard pattern to match. It can contain the
85 * wildcard characters '*' (which matches zero or more characters) and '?'
86 * (which matches any single character). If there is no leading path
87 * separator, then the match is attempted with the filename component of
88 * @path only; otherwise, the match is attempted with the entire @path.
90 * MATCH_* flags, see the flag definitions.
92 * @path and @pattern can both contain path separators (character
93 * WIM_PATH_SEPARATOR). Leading and trailing path separators are not
94 * significant, except when determining whether to match only the filename
95 * component as noted above. The lengths of interior path separator sequences
96 * are not significant. The '*' and '?' characters act within a single path
97 * component only (they do not match path separators).
99 * Matching is done with the default case sensitivity behavior.
101 * Returns %true iff the path matched the pattern.
104 match_path(const tchar *path, const tchar *pattern, int match_flags)
107 if (*pattern != WIM_PATH_SEPARATOR)
108 path = path_basename(path);
111 const tchar *path_component_end;
112 const tchar *pattern_component_end;
114 path = advance_to_next_component(path);
115 pattern = advance_to_next_component(pattern);
117 /* Is the pattern exhausted? */
119 return !*path || (match_flags & MATCH_RECURSIVELY);
121 /* Is the path exhausted (but not the pattern)? */
123 return (match_flags & MATCH_ANCESTORS);
125 path_component_end = advance_through_component(path);
126 pattern_component_end = advance_through_component(pattern);
128 /* Do the components match? */
129 if (!string_matches_pattern(path, path_component_end,
130 pattern, pattern_component_end))
133 path = path_component_end;
134 pattern = pattern_component_end;
139 * Expand a path pattern in an in-memory tree of dentries.
142 * The root of the directory tree in which to expand the pattern.
144 * The path pattern to expand, which may contain the '*' and '?' wildcard
145 * characters. Path separators must be WIM_PATH_SEPARATOR. Leading and
146 * trailing path separators are ignored. The default case sensitivity
149 * A callback function which will receive each matched directory entry.
151 * Opaque context argument for @consume_dentry.
153 * @return 0 on success; a positive error code on failure; or the first nonzero
154 * value returned by @consume_dentry.
157 expand_path_pattern(struct wim_dentry *root, const tchar *pattern,
158 int (*consume_dentry)(struct wim_dentry *, void *),
161 const tchar *pattern_component_end;
162 struct wim_dentry *child;
167 pattern = advance_to_next_component(pattern);
169 /* If there are no more components, then 'root' is matched. */
171 return (*consume_dentry)(root, ctx);
173 pattern_component_end = advance_through_component(pattern);
175 /* For each child dentry that matches the current pattern component,
176 * recurse with the remainder of the pattern. */
177 for_dentry_child(child, root) {
182 ret = utf16le_get_tstr(child->d_name, child->d_name_nbytes,
183 &name, &name_nbytes);
187 if (string_matches_pattern(name, &name[name_nbytes / sizeof(tchar)],
188 pattern, pattern_component_end))
189 ret = expand_path_pattern(child, pattern_component_end,
190 consume_dentry, ctx);
191 utf16le_put_tstr(name);