| @@ -1,1056 +1,1071 @@ | | | @@ -1,1056 +1,1071 @@ |
1 | /* $NetBSD: glob.c,v 1.23.4.1 2010/07/19 18:14:08 riz Exp $ */ | | 1 | /* $NetBSD: glob.c,v 1.23.4.1.2.1 2011/04/24 15:41:23 riz Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1989, 1993 | | 4 | * Copyright (c) 1989, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Guido van Rossum. | | 8 | * Guido van Rossum. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors | | 18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software | | 19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. | | 20 | * without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. | | 32 | * SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | #if defined(LIBC_SCCS) && !defined(lint) | | 36 | #if defined(LIBC_SCCS) && !defined(lint) |
37 | #if 0 | | 37 | #if 0 |
38 | static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; | | 38 | static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; |
39 | #else | | 39 | #else |
40 | __RCSID("$NetBSD: glob.c,v 1.23.4.1 2010/07/19 18:14:08 riz Exp $"); | | 40 | __RCSID("$NetBSD: glob.c,v 1.23.4.1.2.1 2011/04/24 15:41:23 riz Exp $"); |
41 | #endif | | 41 | #endif |
42 | #endif /* LIBC_SCCS and not lint */ | | 42 | #endif /* LIBC_SCCS and not lint */ |
43 | | | 43 | |
44 | /* | | 44 | /* |
45 | * glob(3) -- a superset of the one defined in POSIX 1003.2. | | 45 | * glob(3) -- a superset of the one defined in POSIX 1003.2. |
46 | * | | 46 | * |
47 | * The [!...] convention to negate a range is supported (SysV, Posix, ksh). | | 47 | * The [!...] convention to negate a range is supported (SysV, Posix, ksh). |
48 | * | | 48 | * |
49 | * Optional extra services, controlled by flags not defined by POSIX: | | 49 | * Optional extra services, controlled by flags not defined by POSIX: |
50 | * | | 50 | * |
51 | * GLOB_MAGCHAR: | | 51 | * GLOB_MAGCHAR: |
52 | * Set in gl_flags if pattern contained a globbing character. | | 52 | * Set in gl_flags if pattern contained a globbing character. |
53 | * GLOB_NOMAGIC: | | 53 | * GLOB_NOMAGIC: |
54 | * Same as GLOB_NOCHECK, but it will only append pattern if it did | | 54 | * Same as GLOB_NOCHECK, but it will only append pattern if it did |
55 | * not contain any magic characters. [Used in csh style globbing] | | 55 | * not contain any magic characters. [Used in csh style globbing] |
56 | * GLOB_ALTDIRFUNC: | | 56 | * GLOB_ALTDIRFUNC: |
57 | * Use alternately specified directory access functions. | | 57 | * Use alternately specified directory access functions. |
58 | * GLOB_TILDE: | | 58 | * GLOB_TILDE: |
59 | * expand ~user/foo to the /home/dir/of/user/foo | | 59 | * expand ~user/foo to the /home/dir/of/user/foo |
60 | * GLOB_BRACE: | | 60 | * GLOB_BRACE: |
61 | * expand {1,2}{a,b} to 1a 1b 2a 2b | | 61 | * expand {1,2}{a,b} to 1a 1b 2a 2b |
62 | * GLOB_PERIOD: | | 62 | * GLOB_PERIOD: |
63 | * allow metacharacters to match leading dots in filenames. | | 63 | * allow metacharacters to match leading dots in filenames. |
64 | * GLOB_NO_DOTDIRS: | | 64 | * GLOB_NO_DOTDIRS: |
65 | * . and .. are hidden from wildcards, even if GLOB_PERIOD is set. | | 65 | * . and .. are hidden from wildcards, even if GLOB_PERIOD is set. |
66 | * gl_matchc: | | 66 | * gl_matchc: |
67 | * Number of matches in the current invocation of glob. | | 67 | * Number of matches in the current invocation of glob. |
68 | */ | | 68 | */ |
69 | | | 69 | |
70 | #include "namespace.h" | | 70 | #include "namespace.h" |
71 | #include <sys/param.h> | | 71 | #include <sys/param.h> |
72 | #include <sys/stat.h> | | 72 | #include <sys/stat.h> |
73 | | | 73 | |
74 | #include <assert.h> | | 74 | #include <assert.h> |
75 | #include <ctype.h> | | 75 | #include <ctype.h> |
76 | #include <dirent.h> | | 76 | #include <dirent.h> |
77 | #include <errno.h> | | 77 | #include <errno.h> |
78 | #include <glob.h> | | 78 | #include <glob.h> |
79 | #include <pwd.h> | | 79 | #include <pwd.h> |
80 | #include <stdio.h> | | 80 | #include <stdio.h> |
81 | #include <stddef.h> | | 81 | #include <stddef.h> |
82 | #include <stdlib.h> | | 82 | #include <stdlib.h> |
83 | #include <string.h> | | 83 | #include <string.h> |
84 | #include <unistd.h> | | 84 | #include <unistd.h> |
85 | | | 85 | |
86 | #ifdef HAVE_NBTOOL_CONFIG_H | | 86 | #ifdef HAVE_NBTOOL_CONFIG_H |
87 | #define NO_GETPW_R | | 87 | #define NO_GETPW_R |
88 | #endif | | 88 | #endif |
89 | | | 89 | |
90 | #define GLOB_LIMIT_MALLOC 65536 | | 90 | #define GLOB_LIMIT_STRING 65536 /* number of readdirs */ |
91 | #define GLOB_LIMIT_STAT 128 | | 91 | #define GLOB_LIMIT_STAT 128 /* number of stat system calls */ |
92 | #define GLOB_LIMIT_READDIR 16384 | | 92 | #define GLOB_LIMIT_READDIR 16384 /* total buffer size of path strings */ |
93 | | | 93 | #define GLOB_LIMIT_PATH 1024 /* number of path elements */ |
94 | #define GLOB_INDEX_MALLOC 0 | | 94 | #define GLOB_LIMIT_BRACE 128 /* Number of brace calls */ |
95 | #define GLOB_INDEX_STAT 1 | | 95 | |
96 | #define GLOB_INDEX_READDIR 2 | | 96 | struct glob_limit { |
| | | 97 | size_t l_string; |
| | | 98 | size_t l_stat; |
| | | 99 | size_t l_readdir; |
| | | 100 | size_t l_brace; |
| | | 101 | }; |
97 | | | 102 | |
98 | /* | | 103 | /* |
99 | * XXX: For NetBSD 1.4.x compatibility. (kill me l8r) | | 104 | * XXX: For NetBSD 1.4.x compatibility. (kill me l8r) |
100 | */ | | 105 | */ |
101 | #ifndef _DIAGASSERT | | 106 | #ifndef _DIAGASSERT |
102 | #define _DIAGASSERT(a) | | 107 | #define _DIAGASSERT(a) |
103 | #endif | | 108 | #endif |
104 | | | 109 | |
105 | #define DOLLAR '$' | | 110 | #define DOLLAR '$' |
106 | #define DOT '.' | | 111 | #define DOT '.' |
107 | #define EOS '\0' | | 112 | #define EOS '\0' |
108 | #define LBRACKET '[' | | 113 | #define LBRACKET '[' |
109 | #define NOT '!' | | 114 | #define NOT '!' |
110 | #define QUESTION '?' | | 115 | #define QUESTION '?' |
111 | #define QUOTE '\\' | | 116 | #define QUOTE '\\' |
112 | #define RANGE '-' | | 117 | #define RANGE '-' |
113 | #define RBRACKET ']' | | 118 | #define RBRACKET ']' |
114 | #define SEP '/' | | 119 | #define SEP '/' |
115 | #define STAR '*' | | 120 | #define STAR '*' |
116 | #define TILDE '~' | | 121 | #define TILDE '~' |
117 | #define UNDERSCORE '_' | | 122 | #define UNDERSCORE '_' |
118 | #define LBRACE '{' | | 123 | #define LBRACE '{' |
119 | #define RBRACE '}' | | 124 | #define RBRACE '}' |
120 | #define SLASH '/' | | 125 | #define SLASH '/' |
121 | #define COMMA ',' | | 126 | #define COMMA ',' |
122 | | | 127 | |
123 | #ifndef USE_8BIT_CHARS | | 128 | #ifndef USE_8BIT_CHARS |
124 | | | 129 | |
125 | #define M_QUOTE 0x8000 | | 130 | #define M_QUOTE 0x8000 |
126 | #define M_PROTECT 0x4000 | | 131 | #define M_PROTECT 0x4000 |
127 | #define M_MASK 0xffff | | 132 | #define M_MASK 0xffff |
128 | #define M_ASCII 0x00ff | | 133 | #define M_ASCII 0x00ff |
129 | | | 134 | |
130 | typedef u_short Char; | | 135 | typedef u_short Char; |
131 | | | 136 | |
132 | #else | | 137 | #else |
133 | | | 138 | |
134 | #define M_QUOTE (Char)0x80 | | 139 | #define M_QUOTE (Char)0x80 |
135 | #define M_PROTECT (Char)0x40 | | 140 | #define M_PROTECT (Char)0x40 |
136 | #define M_MASK (Char)0xff | | 141 | #define M_MASK (Char)0xff |
137 | #define M_ASCII (Char)0x7f | | 142 | #define M_ASCII (Char)0x7f |
138 | | | 143 | |
139 | typedef char Char; | | 144 | typedef char Char; |
140 | | | 145 | |
141 | #endif | | 146 | #endif |
142 | | | 147 | |
143 | | | 148 | |
144 | #define CHAR(c) ((Char)((c)&M_ASCII)) | | 149 | #define CHAR(c) ((Char)((c)&M_ASCII)) |
145 | #define META(c) ((Char)((c)|M_QUOTE)) | | 150 | #define META(c) ((Char)((c)|M_QUOTE)) |
146 | #define M_ALL META('*') | | 151 | #define M_ALL META('*') |
147 | #define M_END META(']') | | 152 | #define M_END META(']') |
148 | #define M_NOT META('!') | | 153 | #define M_NOT META('!') |
149 | #define M_ONE META('?') | | 154 | #define M_ONE META('?') |
150 | #define M_RNG META('-') | | 155 | #define M_RNG META('-') |
151 | #define M_SET META('[') | | 156 | #define M_SET META('[') |
152 | #define ismeta(c) (((c)&M_QUOTE) != 0) | | 157 | #define ismeta(c) (((c)&M_QUOTE) != 0) |
153 | | | 158 | |
154 | | | 159 | |
155 | static int compare(const void *, const void *); | | 160 | static int compare(const void *, const void *); |
156 | static int g_Ctoc(const Char *, char *, size_t); | | 161 | static int g_Ctoc(const Char *, char *, size_t); |
157 | static int g_lstat(Char *, __gl_stat_t *, glob_t *); | | 162 | static int g_lstat(Char *, __gl_stat_t *, glob_t *); |
158 | static DIR *g_opendir(Char *, glob_t *); | | 163 | static DIR *g_opendir(Char *, glob_t *); |
159 | static Char *g_strchr(const Char *, int); | | 164 | static Char *g_strchr(const Char *, int); |
160 | static int g_stat(Char *, __gl_stat_t *, glob_t *); | | 165 | static int g_stat(Char *, __gl_stat_t *, glob_t *); |
161 | static int glob0(const Char *, glob_t *, size_t *); | | 166 | static int glob0(const Char *, glob_t *, struct glob_limit *); |
162 | static int glob1(Char *, glob_t *, size_t *); | | 167 | static int glob1(Char *, glob_t *, struct glob_limit *); |
163 | static int glob2(Char *, Char *, Char *, Char *, glob_t *, | | 168 | static int glob2(Char *, Char *, Char *, const Char *, glob_t *, |
164 | size_t *); | | 169 | struct glob_limit *); |
165 | static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, | | 170 | static int glob3(Char *, Char *, Char *, const Char *, const Char *, |
166 | size_t *); | | 171 | glob_t *, struct glob_limit *); |
167 | static int globextend(const Char *, glob_t *, size_t *); | | 172 | static int globextend(const Char *, glob_t *, struct glob_limit *); |
168 | static const Char *globtilde(const Char *, Char *, size_t, glob_t *); | | 173 | static const Char *globtilde(const Char *, Char *, size_t, glob_t *); |
169 | static int globexp1(const Char *, glob_t *, size_t *); | | 174 | static int globexp1(const Char *, glob_t *, struct glob_limit *); |
170 | static int globexp2(const Char *, const Char *, glob_t *, int *, | | 175 | static int globexp2(const Char *, const Char *, glob_t *, int *, |
171 | size_t *); | | 176 | struct glob_limit *); |
172 | static int match(Char *, Char *, Char *); | | 177 | static int match(const Char *, const Char *, const Char *); |
173 | #ifdef DEBUG | | 178 | #ifdef DEBUG |
174 | static void qprintf(const char *, Char *); | | 179 | static void qprintf(const char *, Char *); |
175 | #endif | | 180 | #endif |
176 | | | 181 | |
177 | int | | 182 | int |
178 | glob(const char *pattern, int flags, int (*errfunc)(const char *, int), | | 183 | glob(const char *pattern, int flags, int (*errfunc)(const char *, int), |
179 | glob_t *pglob) | | 184 | glob_t *pglob) |
180 | { | | 185 | { |
181 | const u_char *patnext; | | 186 | const u_char *patnext; |
182 | int c; | | 187 | int c; |
183 | Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; | | 188 | Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; |
184 | /* 0 = malloc(), 1 = stat(), 2 = readdir() */ | | 189 | struct glob_limit limit = { 0, 0, 0, 0 }; |
185 | size_t limit[] = { 0, 0, 0 }; | | | |
186 | | | 190 | |
187 | _DIAGASSERT(pattern != NULL); | | 191 | _DIAGASSERT(pattern != NULL); |
188 | | | 192 | |
189 | patnext = (const u_char *) pattern; | | 193 | patnext = (const u_char *) pattern; |
190 | if (!(flags & GLOB_APPEND)) { | | 194 | if (!(flags & GLOB_APPEND)) { |
191 | pglob->gl_pathc = 0; | | 195 | pglob->gl_pathc = 0; |
192 | pglob->gl_pathv = NULL; | | 196 | pglob->gl_pathv = NULL; |
193 | if (!(flags & GLOB_DOOFFS)) | | 197 | if (!(flags & GLOB_DOOFFS)) |
194 | pglob->gl_offs = 0; | | 198 | pglob->gl_offs = 0; |
195 | } | | 199 | } |
196 | pglob->gl_flags = flags & ~GLOB_MAGCHAR; | | 200 | pglob->gl_flags = flags & ~GLOB_MAGCHAR; |
197 | pglob->gl_errfunc = errfunc; | | 201 | pglob->gl_errfunc = errfunc; |
198 | pglob->gl_matchc = 0; | | 202 | pglob->gl_matchc = 0; |
199 | | | 203 | |
200 | bufnext = patbuf; | | 204 | bufnext = patbuf; |
201 | bufend = bufnext + MAXPATHLEN; | | 205 | bufend = bufnext + MAXPATHLEN; |
202 | if (flags & GLOB_NOESCAPE) { | | 206 | if (flags & GLOB_NOESCAPE) { |
203 | while (bufnext < bufend && (c = *patnext++) != EOS) | | 207 | while (bufnext < bufend && (c = *patnext++) != EOS) |
204 | *bufnext++ = c; | | 208 | *bufnext++ = c; |
205 | } else { | | 209 | } else { |
206 | /* Protect the quoted characters. */ | | 210 | /* Protect the quoted characters. */ |
207 | while (bufnext < bufend && (c = *patnext++) != EOS) | | 211 | while (bufnext < bufend && (c = *patnext++) != EOS) |
208 | if (c == QUOTE) { | | 212 | if (c == QUOTE) { |
209 | if ((c = *patnext++) == EOS) { | | 213 | if ((c = *patnext++) == EOS) { |
210 | c = QUOTE; | | 214 | c = QUOTE; |
211 | --patnext; | | 215 | --patnext; |
212 | } | | 216 | } |
213 | *bufnext++ = c | M_PROTECT; | | 217 | *bufnext++ = c | M_PROTECT; |
214 | } | | 218 | } |
215 | else | | 219 | else |
216 | *bufnext++ = c; | | 220 | *bufnext++ = c; |
217 | } | | 221 | } |
218 | *bufnext = EOS; | | 222 | *bufnext = EOS; |
219 | | | 223 | |
220 | if (flags & GLOB_BRACE) | | 224 | if (flags & GLOB_BRACE) |
221 | return globexp1(patbuf, pglob, limit); | | 225 | return globexp1(patbuf, pglob, &limit); |
222 | else | | 226 | else |
223 | return glob0(patbuf, pglob, limit); | | 227 | return glob0(patbuf, pglob, &limit); |
224 | } | | 228 | } |
225 | | | 229 | |
226 | /* | | 230 | /* |
227 | * Expand recursively a glob {} pattern. When there is no more expansion | | 231 | * Expand recursively a glob {} pattern. When there is no more expansion |
228 | * invoke the standard globbing routine to glob the rest of the magic | | 232 | * invoke the standard globbing routine to glob the rest of the magic |
229 | * characters | | 233 | * characters |
230 | */ | | 234 | */ |
231 | static int | | 235 | static int |
232 | globexp1(const Char *pattern, glob_t *pglob, size_t *limit) | | 236 | globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit) |
233 | { | | 237 | { |
234 | const Char* ptr = pattern; | | 238 | const Char* ptr = pattern; |
235 | int rv; | | 239 | int rv; |
236 | | | 240 | |
237 | _DIAGASSERT(pattern != NULL); | | 241 | _DIAGASSERT(pattern != NULL); |
238 | _DIAGASSERT(pglob != NULL); | | 242 | _DIAGASSERT(pglob != NULL); |
239 | | | 243 | |
| | | 244 | if ((pglob->gl_flags & GLOB_LIMIT) && |
| | | 245 | limit->l_brace++ >= GLOB_LIMIT_BRACE) { |
| | | 246 | errno = 0; |
| | | 247 | return GLOB_NOSPACE; |
| | | 248 | } |
| | | 249 | |
240 | /* Protect a single {}, for find(1), like csh */ | | 250 | /* Protect a single {}, for find(1), like csh */ |
241 | if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) | | 251 | if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) |
242 | return glob0(pattern, pglob, limit); | | 252 | return glob0(pattern, pglob, limit); |
243 | | | 253 | |
244 | while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL) | | 254 | while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL) |
245 | if (!globexp2(ptr, pattern, pglob, &rv, limit)) | | 255 | if (!globexp2(ptr, pattern, pglob, &rv, limit)) |
246 | return rv; | | 256 | return rv; |
247 | | | 257 | |
248 | return glob0(pattern, pglob, limit); | | 258 | return glob0(pattern, pglob, limit); |
249 | } | | 259 | } |
250 | | | 260 | |
251 | | | 261 | |
252 | /* | | 262 | /* |
253 | * Recursive brace globbing helper. Tries to expand a single brace. | | 263 | * Recursive brace globbing helper. Tries to expand a single brace. |
254 | * If it succeeds then it invokes globexp1 with the new pattern. | | 264 | * If it succeeds then it invokes globexp1 with the new pattern. |
255 | * If it fails then it tries to glob the rest of the pattern and returns. | | 265 | * If it fails then it tries to glob the rest of the pattern and returns. |
256 | */ | | 266 | */ |
257 | static int | | 267 | static int |
258 | globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, | | 268 | globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, |
259 | size_t *limit) | | 269 | struct glob_limit *limit) |
260 | { | | 270 | { |
261 | int i; | | 271 | int i; |
262 | Char *lm, *ls; | | 272 | Char *lm, *ls; |
263 | const Char *pe, *pm, *pl; | | 273 | const Char *pe, *pm, *pl; |
264 | Char patbuf[MAXPATHLEN + 1]; | | 274 | Char patbuf[MAXPATHLEN + 1]; |
265 | | | 275 | |
266 | _DIAGASSERT(ptr != NULL); | | 276 | _DIAGASSERT(ptr != NULL); |
267 | _DIAGASSERT(pattern != NULL); | | 277 | _DIAGASSERT(pattern != NULL); |
268 | _DIAGASSERT(pglob != NULL); | | 278 | _DIAGASSERT(pglob != NULL); |
269 | _DIAGASSERT(rv != NULL); | | 279 | _DIAGASSERT(rv != NULL); |
270 | | | 280 | |
271 | /* copy part up to the brace */ | | 281 | /* copy part up to the brace */ |
272 | for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) | | 282 | for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) |
273 | continue; | | 283 | continue; |
274 | ls = lm; | | 284 | ls = lm; |
275 | | | 285 | |
276 | /* Find the balanced brace */ | | 286 | /* Find the balanced brace */ |
277 | for (i = 0, pe = ++ptr; *pe; pe++) | | 287 | for (i = 0, pe = ++ptr; *pe; pe++) |
278 | if (*pe == LBRACKET) { | | 288 | if (*pe == LBRACKET) { |
279 | /* Ignore everything between [] */ | | 289 | /* Ignore everything between [] */ |
280 | for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) | | 290 | for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) |
281 | continue; | | 291 | continue; |
282 | if (*pe == EOS) { | | 292 | if (*pe == EOS) { |
283 | /* | | 293 | /* |
284 | * We could not find a matching RBRACKET. | | 294 | * We could not find a matching RBRACKET. |
285 | * Ignore and just look for RBRACE | | 295 | * Ignore and just look for RBRACE |
286 | */ | | 296 | */ |
287 | pe = pm; | | 297 | pe = pm; |
288 | } | | 298 | } |
289 | } | | 299 | } |
290 | else if (*pe == LBRACE) | | 300 | else if (*pe == LBRACE) |
291 | i++; | | 301 | i++; |
292 | else if (*pe == RBRACE) { | | 302 | else if (*pe == RBRACE) { |
293 | if (i == 0) | | 303 | if (i == 0) |
294 | break; | | 304 | break; |
295 | i--; | | 305 | i--; |
296 | } | | 306 | } |
297 | | | 307 | |
298 | /* Non matching braces; just glob the pattern */ | | 308 | /* Non matching braces; just glob the pattern */ |
299 | if (i != 0 || *pe == EOS) { | | 309 | if (i != 0 || *pe == EOS) { |
300 | /* | | 310 | /* |
301 | * we use `pattern', not `patbuf' here so that that | | 311 | * we use `pattern', not `patbuf' here so that that |
302 | * unbalanced braces are passed to the match | | 312 | * unbalanced braces are passed to the match |
303 | */ | | 313 | */ |
304 | *rv = glob0(pattern, pglob, limit); | | 314 | *rv = glob0(pattern, pglob, limit); |
305 | return 0; | | 315 | return 0; |
306 | } | | 316 | } |
307 | | | 317 | |
308 | for (i = 0, pl = pm = ptr; pm <= pe; pm++) { | | 318 | for (i = 0, pl = pm = ptr; pm <= pe; pm++) { |
309 | switch (*pm) { | | 319 | switch (*pm) { |
310 | case LBRACKET: | | 320 | case LBRACKET: |
311 | /* Ignore everything between [] */ | | 321 | /* Ignore everything between [] */ |
312 | for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) | | 322 | for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) |
313 | continue; | | 323 | continue; |
314 | if (*pm == EOS) { | | 324 | if (*pm == EOS) { |
315 | /* | | 325 | /* |
316 | * We could not find a matching RBRACKET. | | 326 | * We could not find a matching RBRACKET. |
317 | * Ignore and just look for RBRACE | | 327 | * Ignore and just look for RBRACE |
318 | */ | | 328 | */ |
319 | pm = pl; | | 329 | pm = pl; |
320 | } | | 330 | } |
321 | break; | | 331 | break; |
322 | | | 332 | |
323 | case LBRACE: | | 333 | case LBRACE: |
324 | i++; | | 334 | i++; |
325 | break; | | 335 | break; |
326 | | | 336 | |
327 | case RBRACE: | | 337 | case RBRACE: |
328 | if (i) { | | 338 | if (i) { |
329 | i--; | | 339 | i--; |
330 | break; | | 340 | break; |
331 | } | | 341 | } |
332 | /* FALLTHROUGH */ | | 342 | /* FALLTHROUGH */ |
333 | case COMMA: | | 343 | case COMMA: |
334 | if (i && *pm == COMMA) | | 344 | if (i && *pm == COMMA) |
335 | break; | | 345 | break; |
336 | else { | | 346 | else { |
337 | /* Append the current string */ | | 347 | /* Append the current string */ |
338 | for (lm = ls; (pl < pm); *lm++ = *pl++) | | 348 | for (lm = ls; (pl < pm); *lm++ = *pl++) |
339 | continue; | | 349 | continue; |
340 | /* | | 350 | /* |
341 | * Append the rest of the pattern after the | | 351 | * Append the rest of the pattern after the |
342 | * closing brace | | 352 | * closing brace |
343 | */ | | 353 | */ |
344 | for (pl = pe + 1; (*lm++ = *pl++) != EOS;) | | 354 | for (pl = pe + 1; (*lm++ = *pl++) != EOS;) |
345 | continue; | | 355 | continue; |
346 | | | 356 | |
347 | /* Expand the current pattern */ | | 357 | /* Expand the current pattern */ |
348 | #ifdef DEBUG | | 358 | #ifdef DEBUG |
349 | qprintf("globexp2:", patbuf); | | 359 | qprintf("globexp2:", patbuf); |
350 | #endif | | 360 | #endif |
351 | *rv = globexp1(patbuf, pglob, limit); | | 361 | *rv = globexp1(patbuf, pglob, limit); |
352 | | | 362 | |
353 | /* move after the comma, to the next string */ | | 363 | /* move after the comma, to the next string */ |
354 | pl = pm + 1; | | 364 | pl = pm + 1; |
355 | } | | 365 | } |
356 | break; | | 366 | break; |
357 | | | 367 | |
358 | default: | | 368 | default: |
359 | break; | | 369 | break; |
360 | } | | 370 | } |
361 | } | | 371 | } |
362 | *rv = 0; | | 372 | *rv = 0; |
363 | return 0; | | 373 | return 0; |
364 | } | | 374 | } |
365 | | | 375 | |
366 | | | 376 | |
367 | | | 377 | |
368 | /* | | 378 | /* |
369 | * expand tilde from the passwd file. | | 379 | * expand tilde from the passwd file. |
370 | */ | | 380 | */ |
371 | static const Char * | | 381 | static const Char * |
372 | globtilde(const Char *pattern, Char *patbuf, size_t patsize, glob_t *pglob) | | 382 | globtilde(const Char *pattern, Char *patbuf, size_t patsize, glob_t *pglob) |
373 | { | | 383 | { |
374 | struct passwd *pwd; | | 384 | struct passwd *pwd; |
375 | const char *h; | | 385 | const char *h; |
376 | const Char *p; | | 386 | const Char *p; |
377 | Char *b; | | 387 | Char *b; |
378 | char *d; | | 388 | char *d; |
379 | Char *pend = &patbuf[patsize / sizeof(Char)]; | | 389 | Char *pend = &patbuf[patsize / sizeof(Char)]; |
380 | #ifndef NO_GETPW_R | | 390 | #ifndef NO_GETPW_R |
381 | struct passwd pwres; | | 391 | struct passwd pwres; |
382 | char pwbuf[1024]; | | 392 | char pwbuf[1024]; |
383 | #endif | | 393 | #endif |
384 | | | 394 | |
385 | pend--; | | 395 | pend--; |
386 | | | 396 | |
387 | _DIAGASSERT(pattern != NULL); | | 397 | _DIAGASSERT(pattern != NULL); |
388 | _DIAGASSERT(patbuf != NULL); | | 398 | _DIAGASSERT(patbuf != NULL); |
389 | _DIAGASSERT(pglob != NULL); | | 399 | _DIAGASSERT(pglob != NULL); |
390 | | | 400 | |
391 | if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) | | 401 | if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) |
392 | return pattern; | | 402 | return pattern; |
393 | | | 403 | |
394 | /* Copy up to the end of the string or / */ | | 404 | /* Copy up to the end of the string or / */ |
395 | for (p = pattern + 1, d = (char *)(void *)patbuf; | | 405 | for (p = pattern + 1, d = (char *)(void *)patbuf; |
396 | d < (char *)(void *)pend && *p && *p != SLASH; | | 406 | d < (char *)(void *)pend && *p && *p != SLASH; |
397 | *d++ = *p++) | | 407 | *d++ = *p++) |
398 | continue; | | 408 | continue; |
399 | | | 409 | |
400 | if (d == (char *)(void *)pend) | | 410 | if (d == (char *)(void *)pend) |
401 | return NULL; | | 411 | return NULL; |
402 | | | 412 | |
403 | *d = EOS; | | 413 | *d = EOS; |
404 | d = (char *)(void *)patbuf; | | 414 | d = (char *)(void *)patbuf; |
405 | | | 415 | |
406 | if (*d == EOS) { | | 416 | if (*d == EOS) { |
407 | /* | | 417 | /* |
408 | * handle a plain ~ or ~/ by expanding $HOME | | 418 | * handle a plain ~ or ~/ by expanding $HOME |
409 | * first and then trying the password file | | 419 | * first and then trying the password file |
410 | */ | | 420 | */ |
411 | if ((h = getenv("HOME")) == NULL) { | | 421 | if ((h = getenv("HOME")) == NULL) { |
412 | #ifdef NO_GETPW_R | | 422 | #ifdef NO_GETPW_R |
413 | if ((pwd = getpwuid(getuid())) == NULL) | | 423 | if ((pwd = getpwuid(getuid())) == NULL) |
414 | #else | | 424 | #else |
415 | if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), | | 425 | if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), |
416 | &pwd) != 0 || pwd == NULL) | | 426 | &pwd) != 0 || pwd == NULL) |
417 | #endif | | 427 | #endif |
418 | return pattern; | | 428 | return pattern; |
419 | else | | 429 | else |
420 | h = pwd->pw_dir; | | 430 | h = pwd->pw_dir; |
421 | } | | 431 | } |
422 | } | | 432 | } |
423 | else { | | 433 | else { |
424 | /* | | 434 | /* |
425 | * Expand a ~user | | 435 | * Expand a ~user |
426 | */ | | 436 | */ |
427 | #ifdef NO_GETPW_R | | 437 | #ifdef NO_GETPW_R |
428 | if ((pwd = getpwnam(d)) == NULL) | | 438 | if ((pwd = getpwnam(d)) == NULL) |
429 | #else | | 439 | #else |
430 | if (getpwnam_r(d, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 || | | 440 | if (getpwnam_r(d, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 || |
431 | pwd == NULL) | | 441 | pwd == NULL) |
432 | #endif | | 442 | #endif |
433 | return pattern; | | 443 | return pattern; |
434 | else | | 444 | else |
435 | h = pwd->pw_dir; | | 445 | h = pwd->pw_dir; |
436 | } | | 446 | } |
437 | | | 447 | |
438 | /* Copy the home directory */ | | 448 | /* Copy the home directory */ |
439 | for (b = patbuf; b < pend && *h; *b++ = *h++) | | 449 | for (b = patbuf; b < pend && *h; *b++ = *h++) |
440 | continue; | | 450 | continue; |
441 | | | 451 | |
442 | if (b == pend) | | 452 | if (b == pend) |
443 | return NULL; | | 453 | return NULL; |
444 | | | 454 | |
445 | /* Append the rest of the pattern */ | | 455 | /* Append the rest of the pattern */ |
446 | while (b < pend && (*b++ = *p++) != EOS) | | 456 | while (b < pend && (*b++ = *p++) != EOS) |
447 | continue; | | 457 | continue; |
448 | | | 458 | |
449 | if (b == pend) | | 459 | if (b == pend) |
450 | return NULL; | | 460 | return NULL; |
451 | | | 461 | |
452 | return patbuf; | | 462 | return patbuf; |
453 | } | | 463 | } |
454 | | | 464 | |
455 | | | 465 | |
456 | /* | | 466 | /* |
457 | * The main glob() routine: compiles the pattern (optionally processing | | 467 | * The main glob() routine: compiles the pattern (optionally processing |
458 | * quotes), calls glob1() to do the real pattern matching, and finally | | 468 | * quotes), calls glob1() to do the real pattern matching, and finally |
459 | * sorts the list (unless unsorted operation is requested). Returns 0 | | 469 | * sorts the list (unless unsorted operation is requested). Returns 0 |
460 | * if things went well, nonzero if errors occurred. It is not an error | | 470 | * if things went well, nonzero if errors occurred. It is not an error |
461 | * to find no matches. | | 471 | * to find no matches. |
462 | */ | | 472 | */ |
463 | static int | | 473 | static int |
464 | glob0(const Char *pattern, glob_t *pglob, size_t *limit) | | 474 | glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit) |
465 | { | | 475 | { |
466 | const Char *qpatnext; | | 476 | const Char *qpatnext; |
467 | int c, error; | | 477 | int c, error; |
468 | __gl_size_t oldpathc; | | 478 | __gl_size_t oldpathc; |
469 | Char *bufnext, patbuf[MAXPATHLEN+1]; | | 479 | Char *bufnext, patbuf[MAXPATHLEN+1]; |
470 | | | 480 | |
471 | _DIAGASSERT(pattern != NULL); | | 481 | _DIAGASSERT(pattern != NULL); |
472 | _DIAGASSERT(pglob != NULL); | | 482 | _DIAGASSERT(pglob != NULL); |
473 | | | 483 | |
474 | if ((qpatnext = globtilde(pattern, patbuf, sizeof(patbuf), | | 484 | if ((qpatnext = globtilde(pattern, patbuf, sizeof(patbuf), |
475 | pglob)) == NULL) | | 485 | pglob)) == NULL) |
476 | return GLOB_ABEND; | | 486 | return GLOB_ABEND; |
477 | oldpathc = pglob->gl_pathc; | | 487 | oldpathc = pglob->gl_pathc; |
478 | bufnext = patbuf; | | 488 | bufnext = patbuf; |
479 | | | 489 | |
480 | /* We don't need to check for buffer overflow any more. */ | | 490 | /* We don't need to check for buffer overflow any more. */ |
481 | while ((c = *qpatnext++) != EOS) { | | 491 | while ((c = *qpatnext++) != EOS) { |
482 | switch (c) { | | 492 | switch (c) { |
483 | case LBRACKET: | | 493 | case LBRACKET: |
484 | c = *qpatnext; | | 494 | c = *qpatnext; |
485 | if (c == NOT) | | 495 | if (c == NOT) |
486 | ++qpatnext; | | 496 | ++qpatnext; |
487 | if (*qpatnext == EOS || | | 497 | if (*qpatnext == EOS || |
488 | g_strchr(qpatnext+1, RBRACKET) == NULL) { | | 498 | g_strchr(qpatnext+1, RBRACKET) == NULL) { |
489 | *bufnext++ = LBRACKET; | | 499 | *bufnext++ = LBRACKET; |
490 | if (c == NOT) | | 500 | if (c == NOT) |
491 | --qpatnext; | | 501 | --qpatnext; |
492 | break; | | 502 | break; |
493 | } | | 503 | } |
494 | *bufnext++ = M_SET; | | 504 | *bufnext++ = M_SET; |
495 | if (c == NOT) | | 505 | if (c == NOT) |
496 | *bufnext++ = M_NOT; | | 506 | *bufnext++ = M_NOT; |
497 | c = *qpatnext++; | | 507 | c = *qpatnext++; |
498 | do { | | 508 | do { |
499 | *bufnext++ = CHAR(c); | | 509 | *bufnext++ = CHAR(c); |
500 | if (*qpatnext == RANGE && | | 510 | if (*qpatnext == RANGE && |
501 | (c = qpatnext[1]) != RBRACKET) { | | 511 | (c = qpatnext[1]) != RBRACKET) { |
502 | *bufnext++ = M_RNG; | | 512 | *bufnext++ = M_RNG; |
503 | *bufnext++ = CHAR(c); | | 513 | *bufnext++ = CHAR(c); |
504 | qpatnext += 2; | | 514 | qpatnext += 2; |
505 | } | | 515 | } |
506 | } while ((c = *qpatnext++) != RBRACKET); | | 516 | } while ((c = *qpatnext++) != RBRACKET); |
507 | pglob->gl_flags |= GLOB_MAGCHAR; | | 517 | pglob->gl_flags |= GLOB_MAGCHAR; |
508 | *bufnext++ = M_END; | | 518 | *bufnext++ = M_END; |
509 | break; | | 519 | break; |
510 | case QUESTION: | | 520 | case QUESTION: |
511 | pglob->gl_flags |= GLOB_MAGCHAR; | | 521 | pglob->gl_flags |= GLOB_MAGCHAR; |
512 | *bufnext++ = M_ONE; | | 522 | *bufnext++ = M_ONE; |
513 | break; | | 523 | break; |
514 | case STAR: | | 524 | case STAR: |
515 | pglob->gl_flags |= GLOB_MAGCHAR; | | 525 | pglob->gl_flags |= GLOB_MAGCHAR; |
516 | /* collapse adjacent stars to one, | | 526 | /* collapse adjacent stars to one, |
517 | * to avoid exponential behavior | | 527 | * to avoid exponential behavior |
518 | */ | | 528 | */ |
519 | if (bufnext == patbuf || bufnext[-1] != M_ALL) | | 529 | if (bufnext == patbuf || bufnext[-1] != M_ALL) |
520 | *bufnext++ = M_ALL; | | 530 | *bufnext++ = M_ALL; |
521 | break; | | 531 | break; |
522 | default: | | 532 | default: |
523 | *bufnext++ = CHAR(c); | | 533 | *bufnext++ = CHAR(c); |
524 | break; | | 534 | break; |
525 | } | | 535 | } |
526 | } | | 536 | } |
527 | *bufnext = EOS; | | 537 | *bufnext = EOS; |
528 | #ifdef DEBUG | | 538 | #ifdef DEBUG |
529 | qprintf("glob0:", patbuf); | | 539 | qprintf("glob0:", patbuf); |
530 | #endif | | 540 | #endif |
531 | | | 541 | |
532 | if ((error = glob1(patbuf, pglob, limit)) != 0) | | 542 | if ((error = glob1(patbuf, pglob, limit)) != 0) |
533 | return error; | | 543 | return error; |
534 | | | 544 | |
535 | if (pglob->gl_pathc == oldpathc) { | | 545 | if (pglob->gl_pathc == oldpathc) { |
536 | /* | | 546 | /* |
537 | * If there was no match we are going to append the pattern | | 547 | * If there was no match we are going to append the pattern |
538 | * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was | | 548 | * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was |
539 | * specified and the pattern did not contain any magic | | 549 | * specified and the pattern did not contain any magic |
540 | * characters GLOB_NOMAGIC is there just for compatibility | | 550 | * characters GLOB_NOMAGIC is there just for compatibility |
541 | * with csh. | | 551 | * with csh. |
542 | */ | | 552 | */ |
543 | if ((pglob->gl_flags & GLOB_NOCHECK) || | | 553 | if ((pglob->gl_flags & GLOB_NOCHECK) || |
544 | ((pglob->gl_flags & (GLOB_NOMAGIC|GLOB_MAGCHAR)) | | 554 | ((pglob->gl_flags & (GLOB_NOMAGIC|GLOB_MAGCHAR)) |
545 | == GLOB_NOMAGIC)) { | | 555 | == GLOB_NOMAGIC)) { |
546 | return globextend(pattern, pglob, limit); | | 556 | return globextend(pattern, pglob, limit); |
547 | } else { | | 557 | } else { |
548 | return GLOB_NOMATCH; | | 558 | return GLOB_NOMATCH; |
549 | } | | 559 | } |
550 | } else if (!(pglob->gl_flags & GLOB_NOSORT)) { | | 560 | } else if (!(pglob->gl_flags & GLOB_NOSORT)) { |
551 | qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, | | 561 | qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, |
552 | (size_t)pglob->gl_pathc - oldpathc, sizeof(char *), | | 562 | (size_t)pglob->gl_pathc - oldpathc, sizeof(char *), |
553 | compare); | | 563 | compare); |
554 | } | | 564 | } |
555 | | | 565 | |
556 | return 0; | | 566 | return 0; |
557 | } | | 567 | } |
558 | | | 568 | |
559 | static int | | 569 | static int |
560 | compare(const void *p, const void *q) | | 570 | compare(const void *p, const void *q) |
561 | { | | 571 | { |
562 | | | 572 | |
563 | _DIAGASSERT(p != NULL); | | 573 | _DIAGASSERT(p != NULL); |
564 | _DIAGASSERT(q != NULL); | | 574 | _DIAGASSERT(q != NULL); |
565 | | | 575 | |
566 | return strcoll(*(const char * const *)p, *(const char * const *)q); | | 576 | return strcoll(*(const char * const *)p, *(const char * const *)q); |
567 | } | | 577 | } |
568 | | | 578 | |
569 | static int | | 579 | static int |
570 | glob1(Char *pattern, glob_t *pglob, size_t *limit) | | 580 | glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit) |
571 | { | | 581 | { |
572 | Char pathbuf[MAXPATHLEN+1]; | | 582 | Char pathbuf[MAXPATHLEN+1]; |
573 | | | 583 | |
574 | _DIAGASSERT(pattern != NULL); | | 584 | _DIAGASSERT(pattern != NULL); |
575 | _DIAGASSERT(pglob != NULL); | | 585 | _DIAGASSERT(pglob != NULL); |
576 | | | 586 | |
577 | /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ | | 587 | /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ |
578 | if (*pattern == EOS) | | 588 | if (*pattern == EOS) |
579 | return 0; | | 589 | return 0; |
580 | /* | | 590 | /* |
581 | * we save one character so that we can use ptr >= limit, | | 591 | * we save one character so that we can use ptr >= limit, |
582 | * in the general case when we are appending non nul chars only. | | 592 | * in the general case when we are appending non nul chars only. |
583 | */ | | 593 | */ |
584 | return glob2(pathbuf, pathbuf, | | 594 | return glob2(pathbuf, pathbuf, |
585 | pathbuf + (sizeof(pathbuf) / sizeof(*pathbuf)) - 1, pattern, | | 595 | pathbuf + (sizeof(pathbuf) / sizeof(*pathbuf)) - 1, pattern, |
586 | pglob, limit); | | 596 | pglob, limit); |
587 | } | | 597 | } |
588 | | | 598 | |
589 | /* | | 599 | /* |
590 | * The functions glob2 and glob3 are mutually recursive; there is one level | | 600 | * The functions glob2 and glob3 are mutually recursive; there is one level |
591 | * of recursion for each segment in the pattern that contains one or more | | 601 | * of recursion for each segment in the pattern that contains one or more |
592 | * meta characters. | | 602 | * meta characters. |
593 | */ | | 603 | */ |
594 | static int | | 604 | static int |
595 | glob2(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, glob_t *pglob, | | 605 | glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern, |
596 | size_t *limit) | | 606 | glob_t *pglob, struct glob_limit *limit) |
597 | { | | 607 | { |
598 | __gl_stat_t sb; | | 608 | __gl_stat_t sb; |
599 | Char *p, *q; | | 609 | const Char *p; |
| | | 610 | Char *q; |
600 | int anymeta; | | 611 | int anymeta; |
601 | Char *pend; | | 612 | Char *pend; |
602 | ptrdiff_t diff; | | 613 | ptrdiff_t diff; |
603 | | | 614 | |
604 | _DIAGASSERT(pathbuf != NULL); | | 615 | _DIAGASSERT(pathbuf != NULL); |
605 | _DIAGASSERT(pathend != NULL); | | 616 | _DIAGASSERT(pathend != NULL); |
606 | _DIAGASSERT(pattern != NULL); | | 617 | _DIAGASSERT(pattern != NULL); |
607 | _DIAGASSERT(pglob != NULL); | | 618 | _DIAGASSERT(pglob != NULL); |
608 | | | 619 | |
609 | /* | | 620 | /* |
610 | * Loop over pattern segments until end of pattern or until | | 621 | * Loop over pattern segments until end of pattern or until |
611 | * segment with meta character found. | | 622 | * segment with meta character found. |
612 | */ | | 623 | */ |
613 | for (anymeta = 0;;) { | | 624 | for (anymeta = 0;;) { |
614 | if (*pattern == EOS) { /* End of pattern? */ | | 625 | if (*pattern == EOS) { /* End of pattern? */ |
615 | *pathend = EOS; | | 626 | *pathend = EOS; |
616 | if (g_lstat(pathbuf, &sb, pglob)) | | 627 | if (g_lstat(pathbuf, &sb, pglob)) |
617 | return 0; | | 628 | return 0; |
618 | | | 629 | |
619 | if ((pglob->gl_flags & GLOB_LIMIT) && | | 630 | if ((pglob->gl_flags & GLOB_LIMIT) && |
620 | limit[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT) { | | 631 | limit->l_stat++ >= GLOB_LIMIT_STAT) { |
621 | errno = 0; | | 632 | errno = 0; |
622 | *pathend++ = SEP; | | 633 | *pathend++ = SEP; |
623 | *pathend = EOS; | | 634 | *pathend = EOS; |
624 | return GLOB_NOSPACE; | | 635 | return GLOB_NOSPACE; |
625 | } | | 636 | } |
626 | if (((pglob->gl_flags & GLOB_MARK) && | | 637 | if (((pglob->gl_flags & GLOB_MARK) && |
627 | pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) || | | 638 | pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) || |
628 | (S_ISLNK(sb.st_mode) && | | 639 | (S_ISLNK(sb.st_mode) && |
629 | (g_stat(pathbuf, &sb, pglob) == 0) && | | 640 | (g_stat(pathbuf, &sb, pglob) == 0) && |
630 | S_ISDIR(sb.st_mode)))) { | | 641 | S_ISDIR(sb.st_mode)))) { |
631 | if (pathend >= pathlim) | | 642 | if (pathend >= pathlim) |
632 | return GLOB_ABORTED; | | 643 | return GLOB_ABORTED; |
633 | *pathend++ = SEP; | | 644 | *pathend++ = SEP; |
634 | *pathend = EOS; | | 645 | *pathend = EOS; |
635 | } | | 646 | } |
636 | ++pglob->gl_matchc; | | 647 | ++pglob->gl_matchc; |
637 | return globextend(pathbuf, pglob, limit); | | 648 | return globextend(pathbuf, pglob, limit); |
638 | } | | 649 | } |
639 | | | 650 | |
640 | /* Find end of next segment, copy tentatively to pathend. */ | | 651 | /* Find end of next segment, copy tentatively to pathend. */ |
641 | q = pathend; | | 652 | q = pathend; |
642 | p = pattern; | | 653 | p = pattern; |
643 | while (*p != EOS && *p != SEP) { | | 654 | while (*p != EOS && *p != SEP) { |
644 | if (ismeta(*p)) | | 655 | if (ismeta(*p)) |
645 | anymeta = 1; | | 656 | anymeta = 1; |
646 | if (q >= pathlim) | | 657 | if (q >= pathlim) |
647 | return GLOB_ABORTED; | | 658 | return GLOB_ABORTED; |
648 | *q++ = *p++; | | 659 | *q++ = *p++; |
649 | } | | 660 | } |
650 | | | 661 | |
651 | /* | | 662 | /* |
652 | * No expansion, or path ends in slash-dot shash-dot-dot, | | 663 | * No expansion, or path ends in slash-dot shash-dot-dot, |
653 | * do next segment. | | 664 | * do next segment. |
654 | */ | | 665 | */ |
655 | if (pglob->gl_flags & GLOB_PERIOD) { | | 666 | if (pglob->gl_flags & GLOB_PERIOD) { |
656 | for (pend = pathend; pend > pathbuf && pend[-1] == '/'; | | 667 | for (pend = pathend; pend > pathbuf && pend[-1] == '/'; |
657 | pend--) | | 668 | pend--) |
658 | continue; | | 669 | continue; |
659 | diff = pend - pathbuf; | | 670 | diff = pend - pathbuf; |
660 | } else { | | 671 | } else { |
661 | /* XXX: GCC */ | | 672 | /* XXX: GCC */ |
662 | diff = 0; | | 673 | diff = 0; |
663 | pend = pathend; | | 674 | pend = pathend; |
664 | } | | 675 | } |
665 | | | 676 | |
666 | if ((!anymeta) || | | 677 | if ((!anymeta) || |
667 | ((pglob->gl_flags & GLOB_PERIOD) && | | 678 | ((pglob->gl_flags & GLOB_PERIOD) && |
668 | (diff >= 1 && pend[-1] == DOT) && | | 679 | (diff >= 1 && pend[-1] == DOT) && |
669 | (diff >= 2 && (pend[-2] == SLASH || pend[-2] == DOT)) && | | 680 | (diff >= 2 && (pend[-2] == SLASH || pend[-2] == DOT)) && |
670 | (diff < 3 || pend[-3] == SLASH))) { | | 681 | (diff < 3 || pend[-3] == SLASH))) { |
671 | pathend = q; | | 682 | pathend = q; |
672 | pattern = p; | | 683 | pattern = p; |
673 | while (*pattern == SEP) { | | 684 | while (*pattern == SEP) { |
674 | if (pathend >= pathlim) | | 685 | if (pathend >= pathlim) |
675 | return GLOB_ABORTED; | | 686 | return GLOB_ABORTED; |
676 | *pathend++ = *pattern++; | | 687 | *pathend++ = *pattern++; |
677 | } | | 688 | } |
678 | } else /* Need expansion, recurse. */ | | 689 | } else /* Need expansion, recurse. */ |
679 | return glob3(pathbuf, pathend, pathlim, pattern, p, | | 690 | return glob3(pathbuf, pathend, pathlim, pattern, p, |
680 | pglob, limit); | | 691 | pglob, limit); |
681 | } | | 692 | } |
682 | /* NOTREACHED */ | | 693 | /* NOTREACHED */ |
683 | } | | 694 | } |
684 | | | 695 | |
685 | static int | | 696 | static int |
686 | glob3(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, | | 697 | glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern, |
687 | Char *restpattern, glob_t *pglob, size_t *limit) | | 698 | const Char *restpattern, glob_t *pglob, struct glob_limit *limit) |
688 | { | | 699 | { |
689 | struct dirent *dp; | | 700 | struct dirent *dp; |
690 | DIR *dirp; | | 701 | DIR *dirp; |
691 | int error; | | 702 | int error; |
692 | char buf[MAXPATHLEN]; | | 703 | char buf[MAXPATHLEN]; |
693 | | | 704 | |
694 | /* | | 705 | /* |
695 | * The readdirfunc declaration can't be prototyped, because it is | | 706 | * The readdirfunc declaration can't be prototyped, because it is |
696 | * assigned, below, to two functions which are prototyped in glob.h | | 707 | * assigned, below, to two functions which are prototyped in glob.h |
697 | * and dirent.h as taking pointers to differently typed opaque | | 708 | * and dirent.h as taking pointers to differently typed opaque |
698 | * structures. | | 709 | * structures. |
699 | */ | | 710 | */ |
700 | struct dirent *(*readdirfunc)(void *); | | 711 | struct dirent *(*readdirfunc)(void *); |
701 | | | 712 | |
702 | _DIAGASSERT(pathbuf != NULL); | | 713 | _DIAGASSERT(pathbuf != NULL); |
703 | _DIAGASSERT(pathend != NULL); | | 714 | _DIAGASSERT(pathend != NULL); |
704 | _DIAGASSERT(pattern != NULL); | | 715 | _DIAGASSERT(pattern != NULL); |
705 | _DIAGASSERT(restpattern != NULL); | | 716 | _DIAGASSERT(restpattern != NULL); |
706 | _DIAGASSERT(pglob != NULL); | | 717 | _DIAGASSERT(pglob != NULL); |
707 | | | 718 | |
708 | *pathend = EOS; | | 719 | *pathend = EOS; |
709 | errno = 0; | | 720 | errno = 0; |
710 | | | 721 | |
711 | if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { | | 722 | if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { |
712 | if (pglob->gl_errfunc) { | | 723 | if (pglob->gl_errfunc) { |
713 | if (g_Ctoc(pathbuf, buf, sizeof(buf))) | | 724 | if (g_Ctoc(pathbuf, buf, sizeof(buf))) |
714 | return GLOB_ABORTED; | | 725 | return GLOB_ABORTED; |
715 | if (pglob->gl_errfunc(buf, errno) || | | 726 | if (pglob->gl_errfunc(buf, errno) || |
716 | pglob->gl_flags & GLOB_ERR) | | 727 | pglob->gl_flags & GLOB_ERR) |
717 | return GLOB_ABORTED; | | 728 | return GLOB_ABORTED; |
718 | } | | 729 | } |
719 | /* | | 730 | /* |
720 | * Posix/XOpen: glob should return when it encounters a | | 731 | * Posix/XOpen: glob should return when it encounters a |
721 | * directory that it cannot open or read | | 732 | * directory that it cannot open or read |
722 | * XXX: Should we ignore ENOTDIR and ENOENT though? | | 733 | * XXX: Should we ignore ENOTDIR and ENOENT though? |
723 | * I think that Posix had in mind EPERM... | | 734 | * I think that Posix had in mind EPERM... |
724 | */ | | 735 | */ |
725 | if (pglob->gl_flags & GLOB_ERR) | | 736 | if (pglob->gl_flags & GLOB_ERR) |
726 | return GLOB_ABORTED; | | 737 | return GLOB_ABORTED; |
727 | | | 738 | |
728 | return 0; | | 739 | return 0; |
729 | } | | 740 | } |
730 | | | 741 | |
731 | error = 0; | | 742 | error = 0; |
732 | | | 743 | |
733 | /* Search directory for matching names. */ | | 744 | /* Search directory for matching names. */ |
734 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | | 745 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) |
735 | readdirfunc = pglob->gl_readdir; | | 746 | readdirfunc = pglob->gl_readdir; |
736 | else | | 747 | else |
737 | readdirfunc = (struct dirent *(*)__P((void *))) readdir; | | 748 | readdirfunc = (struct dirent *(*)__P((void *))) readdir; |
738 | while ((dp = (*readdirfunc)(dirp)) != NULL) { | | 749 | while ((dp = (*readdirfunc)(dirp)) != NULL) { |
739 | u_char *sc; | | 750 | u_char *sc; |
740 | Char *dc; | | 751 | Char *dc; |
741 | | | 752 | |
742 | if ((pglob->gl_flags & GLOB_LIMIT) && | | 753 | if ((pglob->gl_flags & GLOB_LIMIT) && |
743 | limit[GLOB_INDEX_READDIR]++ >= GLOB_LIMIT_READDIR) { | | 754 | limit->l_readdir++ >= GLOB_LIMIT_READDIR) { |
744 | errno = 0; | | 755 | errno = 0; |
745 | *pathend++ = SEP; | | 756 | *pathend++ = SEP; |
746 | *pathend = EOS; | | 757 | *pathend = EOS; |
747 | return GLOB_NOSPACE; | | 758 | return GLOB_NOSPACE; |
748 | } | | 759 | } |
749 | | | 760 | |
750 | /* | | 761 | /* |
751 | * Initial DOT must be matched literally, unless we have | | 762 | * Initial DOT must be matched literally, unless we have |
752 | * GLOB_PERIOD set. | | 763 | * GLOB_PERIOD set. |
753 | */ | | 764 | */ |
754 | if ((pglob->gl_flags & GLOB_PERIOD) == 0) | | 765 | if ((pglob->gl_flags & GLOB_PERIOD) == 0) |
755 | if (dp->d_name[0] == DOT && *pattern != DOT) | | 766 | if (dp->d_name[0] == DOT && *pattern != DOT) |
756 | continue; | | 767 | continue; |
757 | /* | | 768 | /* |
758 | * If GLOB_NO_DOTDIRS is set, . and .. vanish. | | 769 | * If GLOB_NO_DOTDIRS is set, . and .. vanish. |
759 | */ | | 770 | */ |
760 | if ((pglob->gl_flags & GLOB_NO_DOTDIRS) && | | 771 | if ((pglob->gl_flags & GLOB_NO_DOTDIRS) && |
761 | (dp->d_name[0] == DOT) && | | 772 | (dp->d_name[0] == DOT) && |
762 | ((dp->d_name[1] == EOS) || | | 773 | ((dp->d_name[1] == EOS) || |
763 | ((dp->d_name[1] == DOT) && (dp->d_name[2] == EOS)))) | | 774 | ((dp->d_name[1] == DOT) && (dp->d_name[2] == EOS)))) |
764 | continue; | | 775 | continue; |
765 | /* | | 776 | /* |
766 | * The resulting string contains EOS, so we can | | 777 | * The resulting string contains EOS, so we can |
767 | * use the pathlim character, if it is the nul | | 778 | * use the pathlim character, if it is the nul |
768 | */ | | 779 | */ |
769 | for (sc = (u_char *) dp->d_name, dc = pathend; | | 780 | for (sc = (u_char *) dp->d_name, dc = pathend; |
770 | dc <= pathlim && (*dc++ = *sc++) != EOS;) | | 781 | dc <= pathlim && (*dc++ = *sc++) != EOS;) |
771 | continue; | | 782 | continue; |
772 | | | 783 | |
773 | /* | | 784 | /* |
774 | * Have we filled the buffer without seeing EOS? | | 785 | * Have we filled the buffer without seeing EOS? |
775 | */ | | 786 | */ |
776 | if (dc > pathlim && *pathlim != EOS) { | | 787 | if (dc > pathlim && *pathlim != EOS) { |
777 | /* | | 788 | /* |
778 | * Abort when requested by caller, otherwise | | 789 | * Abort when requested by caller, otherwise |
779 | * reset pathend back to last SEP and continue | | 790 | * reset pathend back to last SEP and continue |
780 | * with next dir entry. | | 791 | * with next dir entry. |
781 | */ | | 792 | */ |
782 | if (pglob->gl_flags & GLOB_ERR) { | | 793 | if (pglob->gl_flags & GLOB_ERR) { |
783 | error = GLOB_ABORTED; | | 794 | error = GLOB_ABORTED; |
784 | break; | | 795 | break; |
785 | } | | 796 | } |
786 | else { | | 797 | else { |
787 | *pathend = EOS; | | 798 | *pathend = EOS; |
788 | continue; | | 799 | continue; |
789 | } | | 800 | } |
790 | } | | 801 | } |
791 | | | 802 | |
792 | if (!match(pathend, pattern, restpattern)) { | | 803 | if (!match(pathend, pattern, restpattern)) { |
793 | *pathend = EOS; | | 804 | *pathend = EOS; |
794 | continue; | | 805 | continue; |
795 | } | | 806 | } |
796 | error = glob2(pathbuf, --dc, pathlim, restpattern, pglob, | | 807 | error = glob2(pathbuf, --dc, pathlim, restpattern, pglob, |
797 | limit); | | 808 | limit); |
798 | if (error) | | 809 | if (error) |
799 | break; | | 810 | break; |
800 | } | | 811 | } |
801 | | | 812 | |
802 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | | 813 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) |
803 | (*pglob->gl_closedir)(dirp); | | 814 | (*pglob->gl_closedir)(dirp); |
804 | else | | 815 | else |
805 | closedir(dirp); | | 816 | closedir(dirp); |
806 | | | 817 | |
807 | /* | | 818 | /* |
808 | * Again Posix X/Open issue with regards to error handling. | | 819 | * Again Posix X/Open issue with regards to error handling. |
809 | */ | | 820 | */ |
810 | if ((error || errno) && (pglob->gl_flags & GLOB_ERR)) | | 821 | if ((error || errno) && (pglob->gl_flags & GLOB_ERR)) |
811 | return GLOB_ABORTED; | | 822 | return GLOB_ABORTED; |
812 | | | 823 | |
813 | return error; | | 824 | return error; |
814 | } | | 825 | } |
815 | | | 826 | |
816 | | | 827 | |
817 | /* | | 828 | /* |
818 | * Extend the gl_pathv member of a glob_t structure to accommodate a new item, | | 829 | * Extend the gl_pathv member of a glob_t structure to accommodate a new item, |
819 | * add the new item, and update gl_pathc. | | 830 | * add the new item, and update gl_pathc. |
820 | * | | 831 | * |
821 | * This assumes the BSD realloc, which only copies the block when its size | | 832 | * This assumes the BSD realloc, which only copies the block when its size |
822 | * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic | | 833 | * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic |
823 | * behavior. | | 834 | * behavior. |
824 | * | | 835 | * |
825 | * Return 0 if new item added, error code if memory couldn't be allocated. | | 836 | * Return 0 if new item added, error code if memory couldn't be allocated. |
826 | * | | 837 | * |
827 | * Invariant of the glob_t structure: | | 838 | * Invariant of the glob_t structure: |
828 | * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and | | 839 | * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and |
829 | * gl_pathv points to (gl_offs + gl_pathc + 1) items. | | 840 | * gl_pathv points to (gl_offs + gl_pathc + 1) items. |
830 | */ | | 841 | */ |
831 | static int | | 842 | static int |
832 | globextend(const Char *path, glob_t *pglob, size_t *limit) | | 843 | globextend(const Char *path, glob_t *pglob, struct glob_limit *limit) |
833 | { | | 844 | { |
834 | char **pathv; | | 845 | char **pathv; |
835 | size_t i, newsize, len; | | 846 | size_t i, newsize, len; |
836 | char *copy; | | 847 | char *copy; |
837 | const Char *p; | | 848 | const Char *p; |
838 | | | 849 | |
839 | _DIAGASSERT(path != NULL); | | 850 | _DIAGASSERT(path != NULL); |
840 | _DIAGASSERT(pglob != NULL); | | 851 | _DIAGASSERT(pglob != NULL); |
841 | | | 852 | |
842 | newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); | | 853 | newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); |
| | | 854 | if ((pglob->gl_flags & GLOB_LIMIT) && |
| | | 855 | newsize > GLOB_LIMIT_PATH * sizeof(*pathv)) |
| | | 856 | goto nospace; |
843 | pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) : | | 857 | pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) : |
844 | malloc(newsize); | | 858 | malloc(newsize); |
845 | if (pathv == NULL) | | 859 | if (pathv == NULL) |
846 | return GLOB_NOSPACE; | | 860 | return GLOB_NOSPACE; |
847 | | | 861 | |
848 | if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { | | 862 | if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { |
849 | /* first time around -- clear initial gl_offs items */ | | 863 | /* first time around -- clear initial gl_offs items */ |
850 | pathv += pglob->gl_offs; | | 864 | pathv += pglob->gl_offs; |
851 | for (i = pglob->gl_offs + 1; --i > 0; ) | | 865 | for (i = pglob->gl_offs + 1; --i > 0; ) |
852 | *--pathv = NULL; | | 866 | *--pathv = NULL; |
853 | } | | 867 | } |
854 | pglob->gl_pathv = pathv; | | 868 | pglob->gl_pathv = pathv; |
855 | | | 869 | |
856 | for (p = path; *p++;) | | 870 | for (p = path; *p++;) |
857 | continue; | | 871 | continue; |
858 | len = (size_t)(p - path); | | 872 | len = (size_t)(p - path); |
859 | limit[GLOB_INDEX_MALLOC] += len; | | 873 | limit->l_string += len; |
860 | if ((copy = malloc(len)) != NULL) { | | 874 | if ((copy = malloc(len)) != NULL) { |
861 | if (g_Ctoc(path, copy, len)) { | | 875 | if (g_Ctoc(path, copy, len)) { |
862 | free(copy); | | 876 | free(copy); |
863 | return GLOB_ABORTED; | | 877 | return GLOB_ABORTED; |
864 | } | | 878 | } |
865 | pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; | | 879 | pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; |
866 | } | | 880 | } |
867 | pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; | | 881 | pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; |
868 | | | 882 | |
869 | if ((pglob->gl_flags & GLOB_LIMIT) && | | 883 | if ((pglob->gl_flags & GLOB_LIMIT) && |
870 | (newsize + limit[GLOB_INDEX_MALLOC]) >= GLOB_LIMIT_MALLOC) { | | 884 | (newsize + limit->l_string) >= GLOB_LIMIT_STRING) |
871 | errno = 0; | | 885 | goto nospace; |
872 | return GLOB_NOSPACE; | | | |
873 | } | | | |
874 | | | 886 | |
875 | return copy == NULL ? GLOB_NOSPACE : 0; | | 887 | return copy == NULL ? GLOB_NOSPACE : 0; |
| | | 888 | nospace: |
| | | 889 | errno = 0; |
| | | 890 | return GLOB_NOSPACE; |
876 | } | | 891 | } |
877 | | | 892 | |
878 | | | 893 | |
879 | /* | | 894 | /* |
880 | * pattern matching function for filenames. Each occurrence of the * | | 895 | * pattern matching function for filenames. Each occurrence of the * |
881 | * pattern causes a recursion level. | | 896 | * pattern causes a recursion level. |
882 | */ | | 897 | */ |
883 | static int | | 898 | static int |
884 | match(Char *name, Char *pat, Char *patend) | | 899 | match(const Char *name, const Char *pat, const Char *patend) |
885 | { | | 900 | { |
886 | int ok, negate_range; | | 901 | int ok, negate_range; |
887 | Char c, k; | | 902 | Char c, k; |
888 | | | 903 | |
889 | _DIAGASSERT(name != NULL); | | 904 | _DIAGASSERT(name != NULL); |
890 | _DIAGASSERT(pat != NULL); | | 905 | _DIAGASSERT(pat != NULL); |
891 | _DIAGASSERT(patend != NULL); | | 906 | _DIAGASSERT(patend != NULL); |
892 | | | 907 | |
893 | while (pat < patend) { | | 908 | while (pat < patend) { |
894 | c = *pat++; | | 909 | c = *pat++; |
895 | switch (c & M_MASK) { | | 910 | switch (c & M_MASK) { |
896 | case M_ALL: | | 911 | case M_ALL: |
897 | if (pat == patend) | | 912 | if (pat == patend) |
898 | return 1; | | 913 | return 1; |
899 | do | | 914 | do |
900 | if (match(name, pat, patend)) | | 915 | if (match(name, pat, patend)) |
901 | return 1; | | 916 | return 1; |
902 | while (*name++ != EOS); | | 917 | while (*name++ != EOS); |
903 | return 0; | | 918 | return 0; |
904 | case M_ONE: | | 919 | case M_ONE: |
905 | if (*name++ == EOS) | | 920 | if (*name++ == EOS) |
906 | return 0; | | 921 | return 0; |
907 | break; | | 922 | break; |
908 | case M_SET: | | 923 | case M_SET: |
909 | ok = 0; | | 924 | ok = 0; |
910 | if ((k = *name++) == EOS) | | 925 | if ((k = *name++) == EOS) |
911 | return 0; | | 926 | return 0; |
912 | if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) | | 927 | if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) |
913 | ++pat; | | 928 | ++pat; |
914 | while (((c = *pat++) & M_MASK) != M_END) | | 929 | while (((c = *pat++) & M_MASK) != M_END) |
915 | if ((*pat & M_MASK) == M_RNG) { | | 930 | if ((*pat & M_MASK) == M_RNG) { |
916 | if (c <= k && k <= pat[1]) | | 931 | if (c <= k && k <= pat[1]) |
917 | ok = 1; | | 932 | ok = 1; |
918 | pat += 2; | | 933 | pat += 2; |
919 | } else if (c == k) | | 934 | } else if (c == k) |
920 | ok = 1; | | 935 | ok = 1; |
921 | if (ok == negate_range) | | 936 | if (ok == negate_range) |
922 | return 0; | | 937 | return 0; |
923 | break; | | 938 | break; |
924 | default: | | 939 | default: |
925 | if (*name++ != c) | | 940 | if (*name++ != c) |
926 | return 0; | | 941 | return 0; |
927 | break; | | 942 | break; |
928 | } | | 943 | } |
929 | } | | 944 | } |
930 | return *name == EOS; | | 945 | return *name == EOS; |
931 | } | | 946 | } |
932 | | | 947 | |
933 | /* Free allocated data belonging to a glob_t structure. */ | | 948 | /* Free allocated data belonging to a glob_t structure. */ |
934 | void | | 949 | void |
935 | globfree(glob_t *pglob) | | 950 | globfree(glob_t *pglob) |
936 | { | | 951 | { |
937 | size_t i; | | 952 | size_t i; |
938 | char **pp; | | 953 | char **pp; |
939 | | | 954 | |
940 | _DIAGASSERT(pglob != NULL); | | 955 | _DIAGASSERT(pglob != NULL); |
941 | | | 956 | |
942 | if (pglob->gl_pathv != NULL) { | | 957 | if (pglob->gl_pathv != NULL) { |
943 | pp = pglob->gl_pathv + pglob->gl_offs; | | 958 | pp = pglob->gl_pathv + pglob->gl_offs; |
944 | for (i = pglob->gl_pathc; i--; ++pp) | | 959 | for (i = pglob->gl_pathc; i--; ++pp) |
945 | if (*pp) | | 960 | if (*pp) |
946 | free(*pp); | | 961 | free(*pp); |
947 | free(pglob->gl_pathv); | | 962 | free(pglob->gl_pathv); |
948 | pglob->gl_pathv = NULL; | | 963 | pglob->gl_pathv = NULL; |
949 | pglob->gl_pathc = 0; | | 964 | pglob->gl_pathc = 0; |
950 | } | | 965 | } |
951 | } | | 966 | } |
952 | | | 967 | |
953 | static DIR * | | 968 | static DIR * |
954 | g_opendir(Char *str, glob_t *pglob) | | 969 | g_opendir(Char *str, glob_t *pglob) |
955 | { | | 970 | { |
956 | char buf[MAXPATHLEN]; | | 971 | char buf[MAXPATHLEN]; |
957 | | | 972 | |
958 | _DIAGASSERT(str != NULL); | | 973 | _DIAGASSERT(str != NULL); |
959 | _DIAGASSERT(pglob != NULL); | | 974 | _DIAGASSERT(pglob != NULL); |
960 | | | 975 | |
961 | if (!*str) | | 976 | if (!*str) |
962 | (void)strlcpy(buf, ".", sizeof(buf)); | | 977 | (void)strlcpy(buf, ".", sizeof(buf)); |
963 | else { | | 978 | else { |
964 | if (g_Ctoc(str, buf, sizeof(buf))) | | 979 | if (g_Ctoc(str, buf, sizeof(buf))) |
965 | return NULL; | | 980 | return NULL; |
966 | } | | 981 | } |
967 | | | 982 | |
968 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | | 983 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) |
969 | return (*pglob->gl_opendir)(buf); | | 984 | return (*pglob->gl_opendir)(buf); |
970 | | | 985 | |
971 | return opendir(buf); | | 986 | return opendir(buf); |
972 | } | | 987 | } |
973 | | | 988 | |
974 | static int | | 989 | static int |
975 | g_lstat(Char *fn, __gl_stat_t *sb, glob_t *pglob) | | 990 | g_lstat(Char *fn, __gl_stat_t *sb, glob_t *pglob) |
976 | { | | 991 | { |
977 | char buf[MAXPATHLEN]; | | 992 | char buf[MAXPATHLEN]; |
978 | | | 993 | |
979 | _DIAGASSERT(fn != NULL); | | 994 | _DIAGASSERT(fn != NULL); |
980 | _DIAGASSERT(sb != NULL); | | 995 | _DIAGASSERT(sb != NULL); |
981 | _DIAGASSERT(pglob != NULL); | | 996 | _DIAGASSERT(pglob != NULL); |
982 | | | 997 | |
983 | if (g_Ctoc(fn, buf, sizeof(buf))) | | 998 | if (g_Ctoc(fn, buf, sizeof(buf))) |
984 | return -1; | | 999 | return -1; |
985 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | | 1000 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) |
986 | return (*pglob->gl_lstat)(buf, sb); | | 1001 | return (*pglob->gl_lstat)(buf, sb); |
987 | return lstat(buf, sb); | | 1002 | return lstat(buf, sb); |
988 | } | | 1003 | } |
989 | | | 1004 | |
990 | static int | | 1005 | static int |
991 | g_stat(Char *fn, __gl_stat_t *sb, glob_t *pglob) | | 1006 | g_stat(Char *fn, __gl_stat_t *sb, glob_t *pglob) |
992 | { | | 1007 | { |
993 | char buf[MAXPATHLEN]; | | 1008 | char buf[MAXPATHLEN]; |
994 | | | 1009 | |
995 | _DIAGASSERT(fn != NULL); | | 1010 | _DIAGASSERT(fn != NULL); |
996 | _DIAGASSERT(sb != NULL); | | 1011 | _DIAGASSERT(sb != NULL); |
997 | _DIAGASSERT(pglob != NULL); | | 1012 | _DIAGASSERT(pglob != NULL); |
998 | | | 1013 | |
999 | if (g_Ctoc(fn, buf, sizeof(buf))) | | 1014 | if (g_Ctoc(fn, buf, sizeof(buf))) |
1000 | return -1; | | 1015 | return -1; |
1001 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) | | 1016 | if (pglob->gl_flags & GLOB_ALTDIRFUNC) |
1002 | return (*pglob->gl_stat)(buf, sb); | | 1017 | return (*pglob->gl_stat)(buf, sb); |
1003 | return stat(buf, sb); | | 1018 | return stat(buf, sb); |
1004 | } | | 1019 | } |
1005 | | | 1020 | |
1006 | static Char * | | 1021 | static Char * |
1007 | g_strchr(const Char *str, int ch) | | 1022 | g_strchr(const Char *str, int ch) |
1008 | { | | 1023 | { |
1009 | | | 1024 | |
1010 | _DIAGASSERT(str != NULL); | | 1025 | _DIAGASSERT(str != NULL); |
1011 | | | 1026 | |
1012 | do { | | 1027 | do { |
1013 | if (*str == ch) | | 1028 | if (*str == ch) |
1014 | return __UNCONST(str); | | 1029 | return __UNCONST(str); |
1015 | } while (*str++); | | 1030 | } while (*str++); |
1016 | return NULL; | | 1031 | return NULL; |
1017 | } | | 1032 | } |
1018 | | | 1033 | |
1019 | static int | | 1034 | static int |
1020 | g_Ctoc(const Char *str, char *buf, size_t len) | | 1035 | g_Ctoc(const Char *str, char *buf, size_t len) |
1021 | { | | 1036 | { |
1022 | char *dc; | | 1037 | char *dc; |
1023 | | | 1038 | |
1024 | _DIAGASSERT(str != NULL); | | 1039 | _DIAGASSERT(str != NULL); |
1025 | _DIAGASSERT(buf != NULL); | | 1040 | _DIAGASSERT(buf != NULL); |
1026 | | | 1041 | |
1027 | if (len == 0) | | 1042 | if (len == 0) |
1028 | return 1; | | 1043 | return 1; |
1029 | | | 1044 | |
1030 | for (dc = buf; len && (*dc++ = *str++) != EOS; len--) | | 1045 | for (dc = buf; len && (*dc++ = *str++) != EOS; len--) |
1031 | continue; | | 1046 | continue; |
1032 | | | 1047 | |
1033 | return len == 0; | | 1048 | return len == 0; |
1034 | } | | 1049 | } |
1035 | | | 1050 | |
1036 | #ifdef DEBUG | | 1051 | #ifdef DEBUG |
1037 | static void | | 1052 | static void |
1038 | qprintf(const char *str, Char *s) | | 1053 | qprintf(const char *str, Char *s) |
1039 | { | | 1054 | { |
1040 | Char *p; | | 1055 | Char *p; |
1041 | | | 1056 | |
1042 | _DIAGASSERT(str != NULL); | | 1057 | _DIAGASSERT(str != NULL); |
1043 | _DIAGASSERT(s != NULL); | | 1058 | _DIAGASSERT(s != NULL); |
1044 | | | 1059 | |
1045 | (void)printf("%s:\n", str); | | 1060 | (void)printf("%s:\n", str); |
1046 | for (p = s; *p; p++) | | 1061 | for (p = s; *p; p++) |
1047 | (void)printf("%c", CHAR(*p)); | | 1062 | (void)printf("%c", CHAR(*p)); |
1048 | (void)printf("\n"); | | 1063 | (void)printf("\n"); |
1049 | for (p = s; *p; p++) | | 1064 | for (p = s; *p; p++) |
1050 | (void)printf("%c", *p & M_PROTECT ? '"' : ' '); | | 1065 | (void)printf("%c", *p & M_PROTECT ? '"' : ' '); |
1051 | (void)printf("\n"); | | 1066 | (void)printf("\n"); |
1052 | for (p = s; *p; p++) | | 1067 | for (p = s; *p; p++) |
1053 | (void)printf("%c", ismeta(*p) ? '_' : ' '); | | 1068 | (void)printf("%c", ismeta(*p) ? '_' : ' '); |
1054 | (void)printf("\n"); | | 1069 | (void)printf("\n"); |
1055 | } | | 1070 | } |
1056 | #endif | | 1071 | #endif |