1 /* pathexp.c -- The shell interface to the globbing library. */
3 /* Copyright (C) 1995-2007 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 it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 #include "bashtypes.h"
26 #if defined (HAVE_UNISTD_H)
38 #include <glob/strmatch.h>
40 static int glob_name_is_acceptable __P((const char *));
41 static void ignore_globbed_names __P((char **, sh_ignore_func_t *));
43 #if defined (USE_POSIX_GLOB_LIBRARY)
45 typedef int posix_glob_errfunc_t __P((const char *, int));
47 # include <glob/glob.h>
50 /* Control whether * matches .files in globbing. */
51 int glob_dot_filenames;
53 /* Control whether the extended globbing features are enabled. */
54 int extended_glob = 0;
56 /* Return nonzero if STRING has any unquoted special globbing chars in it. */
58 unquoted_glob_pattern_p (string)
59 register char *string;
68 send = string + strlen (string);
90 if (*string == '(') /*)*/
96 if (*string++ == '\0')
100 /* Advance one fewer byte than an entire multibyte character to
101 account for the auto-increment in the loop above. */
102 #ifdef HANDLE_MULTIBYTE
104 ADVANCE_CHAR_P (string, send - string);
107 ADVANCE_CHAR_P (string, send - string);
113 /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
114 be quoted to match itself. */
140 /* PATHNAME can contain characters prefixed by CTLESC; this indicates
141 that the character is to be quoted. We quote it here in the style
142 that the glob library recognizes. If flags includes QGLOB_CVTNULL,
143 we change quoted null strings (pathname[0] == CTLNUL) into empty
144 strings (pathname[0] == 0). If this is called after quote removal
145 is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote
146 removal has not been done (for example, before attempting to match a
147 pattern while executing a case statement), flags should include
148 QGLOB_CVTNULL. If flags includes QGLOB_FILENAME, appropriate quoting
149 to match a filename should be performed. */
151 quote_string_for_globbing (pathname, qflags)
152 const char *pathname;
158 temp = (char *)xmalloc (strlen (pathname) + 1);
160 if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname))
166 for (i = j = 0; pathname[i]; i++)
168 if (pathname[i] == CTLESC)
170 if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/')
172 if ((qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0)
176 if (pathname[i] == '\0')
179 temp[j++] = pathname[i];
187 quote_globbing_chars (string)
191 char *temp, *s, *t, *send;
194 slen = strlen (string);
195 send = string + slen;
197 temp = (char *)xmalloc (slen * 2 + 1);
198 for (t = temp, s = string; *s; )
212 if (s[1] == '(') /*(*/
217 /* Copy a single (possibly multibyte) character from s to t,
218 incrementing both. */
219 COPY_CHAR_P (t, s, send);
225 /* Call the glob library to do globbing on PATHNAME. */
227 shell_glob_filename (pathname)
228 const char *pathname;
230 #if defined (USE_POSIX_GLOB_LIBRARY)
232 char *temp, **results;
236 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
238 filenames.gl_offs = 0;
240 # if defined (GLOB_PERIOD)
241 glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
244 # endif /* !GLOB_PERIOD */
246 glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
248 i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames);
252 if (i == GLOB_NOSPACE || i == GLOB_ABORTED)
253 return ((char **)NULL);
254 else if (i == GLOB_NOMATCH)
255 filenames.gl_pathv = (char **)NULL;
256 else if (i != 0) /* other error codes not in POSIX.2 */
257 filenames.gl_pathv = (char **)NULL;
259 results = filenames.gl_pathv;
261 if (results && ((GLOB_FAILED (results)) == 0))
263 if (should_ignore_glob_matches ())
264 ignore_glob_matches (results);
265 if (results && results[0])
266 strvec_sort (results);
270 results = (char **)NULL;
276 #else /* !USE_POSIX_GLOB_LIBRARY */
278 char *temp, **results;
280 noglob_dot_filenames = glob_dot_filenames == 0;
282 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
283 results = glob_filename (temp, 0);
286 if (results && ((GLOB_FAILED (results)) == 0))
288 if (should_ignore_glob_matches ())
289 ignore_glob_matches (results);
290 if (results && results[0])
291 strvec_sort (results);
295 results = (char **)&glob_error_return;
300 #endif /* !USE_POSIX_GLOB_LIBRARY */
303 /* Stuff for GLOBIGNORE. */
305 static struct ignorevar globignore =
311 (sh_iv_item_func_t *)0,
314 /* Set up to ignore some glob matches because the value of GLOBIGNORE
315 has changed. If GLOBIGNORE is being unset, we also need to disable
316 the globbing of filenames beginning with a `.'. */
318 setup_glob_ignore (name)
323 v = get_string_value (name);
324 setup_ignore_patterns (&globignore);
326 if (globignore.num_ignores)
327 glob_dot_filenames = 1;
329 glob_dot_filenames = 0;
333 should_ignore_glob_matches ()
335 return globignore.num_ignores;
338 /* Return 0 if NAME matches a pattern in the globignore.ignores list. */
340 glob_name_is_acceptable (name)
346 /* . and .. are never matched */
347 if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
350 flags = FNM_PATHNAME | FNMATCH_EXTFLAG;
351 for (p = globignore.ignores; p->val; p++)
353 if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH)
359 /* Internal function to test whether filenames in NAMES should be
360 ignored. NAME_FUNC is a pointer to a function to call with each
361 name. It returns non-zero if the name is acceptable to the particular
362 ignore function which called _ignore_names; zero if the name should
363 be removed from NAMES. */
366 ignore_globbed_names (names, name_func)
368 sh_ignore_func_t *name_func;
373 for (i = 0; names[i]; i++)
375 newnames = strvec_create (i + 1);
377 for (n = i = 0; names[i]; i++)
379 if ((*name_func) (names[i]))
380 newnames[n++] = names[i];
385 newnames[n] = (char *)NULL;
389 names[0] = (char *)NULL;
394 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
396 for (n = 0; newnames[n]; n++)
397 names[n] = newnames[n];
398 names[n] = (char *)NULL;
403 ignore_glob_matches (names)
406 if (globignore.num_ignores == 0)
409 ignore_globbed_names (names, glob_name_is_acceptable);
413 setup_ignore_patterns (ivp)
414 struct ignorevar *ivp;
416 int numitems, maxitems, ptr;
417 char *colon_bit, *this_ignoreval;
420 this_ignoreval = get_string_value (ivp->varname);
422 /* If nothing has changed then just exit now. */
423 if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) ||
424 (!this_ignoreval && !ivp->last_ignoreval))
427 /* Oops. The ignore variable has changed. Re-parse it. */
428 ivp->num_ignores = 0;
432 for (p = ivp->ignores; p->val; p++)
435 ivp->ignores = (struct ign *)NULL;
438 if (ivp->last_ignoreval)
440 free (ivp->last_ignoreval);
441 ivp->last_ignoreval = (char *)NULL;
444 if (this_ignoreval == 0 || *this_ignoreval == '\0')
447 ivp->last_ignoreval = savestring (this_ignoreval);
449 numitems = maxitems = ptr = 0;
451 while (colon_bit = extract_colon_unit (this_ignoreval, &ptr))
453 if (numitems + 1 >= maxitems)
456 ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign));
458 ivp->ignores[numitems].val = colon_bit;
459 ivp->ignores[numitems].len = strlen (colon_bit);
460 ivp->ignores[numitems].flags = 0;
462 (*ivp->item_func) (&ivp->ignores[numitems]);
465 ivp->ignores[numitems].val = (char *)NULL;
466 ivp->num_ignores = numitems;