Patch-ID: bash40-032
[bash.git] / pathexp.c
blobece200d3d18a04b8c646689a3cb626236171257a
1 /* pathexp.c -- The shell interface to the globbing library. */
3 /* Copyright (C) 1995-2009 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
21 #include "config.h"
23 #include "bashtypes.h"
24 #include <stdio.h>
26 #if defined (HAVE_UNISTD_H)
27 # include <unistd.h>
28 #endif
30 #include "bashansi.h"
32 #include "shell.h"
33 #include "pathexp.h"
34 #include "flags.h"
36 #include "shmbutil.h"
37 #include "bashintl.h"
39 #include <glob/strmatch.h>
41 static int glob_name_is_acceptable __P((const char *));
42 static void ignore_globbed_names __P((char **, sh_ignore_func_t *));
44 #if defined (USE_POSIX_GLOB_LIBRARY)
45 # include <glob.h>
46 typedef int posix_glob_errfunc_t __P((const char *, int));
47 #else
48 # include <glob/glob.h>
49 #endif
51 /* Control whether * matches .files in globbing. */
52 int glob_dot_filenames;
54 /* Control whether the extended globbing features are enabled. */
55 int extended_glob = 0;
57 /* Control enabling special handling of `**' */
58 int glob_star = 0;
60 /* Return nonzero if STRING has any unquoted special globbing chars in it. */
61 int
62 unquoted_glob_pattern_p (string)
63 register char *string;
65 register int c;
66 char *send;
67 int open;
69 DECLARE_MBSTATE;
71 open = 0;
72 send = string + strlen (string);
74 while (c = *string++)
76 switch (c)
78 case '?':
79 case '*':
80 return (1);
82 case '[':
83 open++;
84 continue;
86 case ']':
87 if (open)
88 return (1);
89 continue;
91 case '+':
92 case '@':
93 case '!':
94 if (*string == '(') /*)*/
95 return (1);
96 continue;
98 case CTLESC:
99 case '\\':
100 if (*string++ == '\0')
101 return (0);
104 /* Advance one fewer byte than an entire multibyte character to
105 account for the auto-increment in the loop above. */
106 #ifdef HANDLE_MULTIBYTE
107 string--;
108 ADVANCE_CHAR_P (string, send - string);
109 string++;
110 #else
111 ADVANCE_CHAR_P (string, send - string);
112 #endif
114 return (0);
117 /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
118 be quoted to match itself. */
119 static inline int
120 ere_char (c)
121 int c;
123 switch (c)
125 case '.':
126 case '[':
127 case '\\':
128 case '(':
129 case ')':
130 case '*':
131 case '+':
132 case '?':
133 case '{':
134 case '|':
135 case '^':
136 case '$':
137 return 1;
138 default:
139 return 0;
141 return (0);
145 glob_char_p (s)
146 const char *s;
148 switch (*s)
150 case '*':
151 case '[':
152 case ']':
153 case '?':
154 case '\\':
155 return 1;
156 case '+':
157 case '@':
158 case '!':
159 if (s[1] == '(') /*(*/
160 return 1;
161 break;
163 return 0;
166 /* PATHNAME can contain characters prefixed by CTLESC; this indicates
167 that the character is to be quoted. We quote it here in the style
168 that the glob library recognizes. If flags includes QGLOB_CVTNULL,
169 we change quoted null strings (pathname[0] == CTLNUL) into empty
170 strings (pathname[0] == 0). If this is called after quote removal
171 is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote
172 removal has not been done (for example, before attempting to match a
173 pattern while executing a case statement), flags should include
174 QGLOB_CVTNULL. If flags includes QGLOB_FILENAME, appropriate quoting
175 to match a filename should be performed. */
176 char *
177 quote_string_for_globbing (pathname, qflags)
178 const char *pathname;
179 int qflags;
181 char *temp;
182 register int i, j;
184 temp = (char *)xmalloc (strlen (pathname) + 1);
186 if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname))
188 temp[0] = '\0';
189 return temp;
192 for (i = j = 0; pathname[i]; i++)
194 if (pathname[i] == CTLESC)
196 if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/')
197 continue;
198 if ((qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0)
199 continue;
200 temp[j++] = '\\';
201 i++;
202 if (pathname[i] == '\0')
203 break;
205 else if (pathname[i] == '\\')
207 temp[j++] = '\\';
208 i++;
209 if (pathname[i] == '\0')
210 break;
212 temp[j++] = pathname[i];
214 temp[j] = '\0';
216 return (temp);
219 char *
220 quote_globbing_chars (string)
221 char *string;
223 size_t slen;
224 char *temp, *s, *t, *send;
225 DECLARE_MBSTATE;
227 slen = strlen (string);
228 send = string + slen;
230 temp = (char *)xmalloc (slen * 2 + 1);
231 for (t = temp, s = string; *s; )
233 if (glob_char_p (s))
234 *t++ = '\\';
236 /* Copy a single (possibly multibyte) character from s to t,
237 incrementing both. */
238 COPY_CHAR_P (t, s, send);
240 *t = '\0';
241 return temp;
244 /* Call the glob library to do globbing on PATHNAME. */
245 char **
246 shell_glob_filename (pathname)
247 const char *pathname;
249 #if defined (USE_POSIX_GLOB_LIBRARY)
250 register int i;
251 char *temp, **results;
252 glob_t filenames;
253 int glob_flags;
255 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
257 filenames.gl_offs = 0;
259 # if defined (GLOB_PERIOD)
260 glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
261 # else
262 glob_flags = 0;
263 # endif /* !GLOB_PERIOD */
265 glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
267 i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames);
269 free (temp);
271 if (i == GLOB_NOSPACE || i == GLOB_ABORTED)
272 return ((char **)NULL);
273 else if (i == GLOB_NOMATCH)
274 filenames.gl_pathv = (char **)NULL;
275 else if (i != 0) /* other error codes not in POSIX.2 */
276 filenames.gl_pathv = (char **)NULL;
278 results = filenames.gl_pathv;
280 if (results && ((GLOB_FAILED (results)) == 0))
282 if (should_ignore_glob_matches ())
283 ignore_glob_matches (results);
284 if (results && results[0])
285 strvec_sort (results);
286 else
288 FREE (results);
289 results = (char **)NULL;
293 return (results);
295 #else /* !USE_POSIX_GLOB_LIBRARY */
297 char *temp, **results;
299 noglob_dot_filenames = glob_dot_filenames == 0;
301 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
302 results = glob_filename (temp, glob_star ? GX_GLOBSTAR : 0);
303 free (temp);
305 if (results && ((GLOB_FAILED (results)) == 0))
307 if (should_ignore_glob_matches ())
308 ignore_glob_matches (results);
309 if (results && results[0])
310 strvec_sort (results);
311 else
313 FREE (results);
314 results = (char **)&glob_error_return;
318 return (results);
319 #endif /* !USE_POSIX_GLOB_LIBRARY */
322 /* Stuff for GLOBIGNORE. */
324 static struct ignorevar globignore =
326 "GLOBIGNORE",
327 (struct ign *)0,
329 (char *)0,
330 (sh_iv_item_func_t *)0,
333 /* Set up to ignore some glob matches because the value of GLOBIGNORE
334 has changed. If GLOBIGNORE is being unset, we also need to disable
335 the globbing of filenames beginning with a `.'. */
336 void
337 setup_glob_ignore (name)
338 char *name;
340 char *v;
342 v = get_string_value (name);
343 setup_ignore_patterns (&globignore);
345 if (globignore.num_ignores)
346 glob_dot_filenames = 1;
347 else if (v == 0)
348 glob_dot_filenames = 0;
352 should_ignore_glob_matches ()
354 return globignore.num_ignores;
357 /* Return 0 if NAME matches a pattern in the globignore.ignores list. */
358 static int
359 glob_name_is_acceptable (name)
360 const char *name;
362 struct ign *p;
363 int flags;
365 /* . and .. are never matched */
366 if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
367 return (0);
369 flags = FNM_PATHNAME | FNMATCH_EXTFLAG;
370 for (p = globignore.ignores; p->val; p++)
372 if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH)
373 return (0);
375 return (1);
378 /* Internal function to test whether filenames in NAMES should be
379 ignored. NAME_FUNC is a pointer to a function to call with each
380 name. It returns non-zero if the name is acceptable to the particular
381 ignore function which called _ignore_names; zero if the name should
382 be removed from NAMES. */
384 static void
385 ignore_globbed_names (names, name_func)
386 char **names;
387 sh_ignore_func_t *name_func;
389 char **newnames;
390 int n, i;
392 for (i = 0; names[i]; i++)
394 newnames = strvec_create (i + 1);
396 for (n = i = 0; names[i]; i++)
398 if ((*name_func) (names[i]))
399 newnames[n++] = names[i];
400 else
401 free (names[i]);
404 newnames[n] = (char *)NULL;
406 if (n == 0)
408 names[0] = (char *)NULL;
409 free (newnames);
410 return;
413 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
414 new array end. */
415 for (n = 0; newnames[n]; n++)
416 names[n] = newnames[n];
417 names[n] = (char *)NULL;
418 free (newnames);
421 void
422 ignore_glob_matches (names)
423 char **names;
425 if (globignore.num_ignores == 0)
426 return;
428 ignore_globbed_names (names, glob_name_is_acceptable);
431 void
432 setup_ignore_patterns (ivp)
433 struct ignorevar *ivp;
435 int numitems, maxitems, ptr;
436 char *colon_bit, *this_ignoreval;
437 struct ign *p;
439 this_ignoreval = get_string_value (ivp->varname);
441 /* If nothing has changed then just exit now. */
442 if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) ||
443 (!this_ignoreval && !ivp->last_ignoreval))
444 return;
446 /* Oops. The ignore variable has changed. Re-parse it. */
447 ivp->num_ignores = 0;
449 if (ivp->ignores)
451 for (p = ivp->ignores; p->val; p++)
452 free(p->val);
453 free (ivp->ignores);
454 ivp->ignores = (struct ign *)NULL;
457 if (ivp->last_ignoreval)
459 free (ivp->last_ignoreval);
460 ivp->last_ignoreval = (char *)NULL;
463 if (this_ignoreval == 0 || *this_ignoreval == '\0')
464 return;
466 ivp->last_ignoreval = savestring (this_ignoreval);
468 numitems = maxitems = ptr = 0;
470 while (colon_bit = extract_colon_unit (this_ignoreval, &ptr))
472 if (numitems + 1 >= maxitems)
474 maxitems += 10;
475 ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign));
477 ivp->ignores[numitems].val = colon_bit;
478 ivp->ignores[numitems].len = strlen (colon_bit);
479 ivp->ignores[numitems].flags = 0;
480 if (ivp->item_func)
481 (*ivp->item_func) (&ivp->ignores[numitems]);
482 numitems++;
484 ivp->ignores[numitems].val = (char *)NULL;
485 ivp->num_ignores = numitems;