1 /* pathexp.c -- The shell interface to the globbing library. */
3 /* Copyright (C) 1995 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #include "bashtypes.h"
26 #if defined (HAVE_UNISTD_H)
36 #include <glob/fnmatch.h>
37 #include <glob/glob.h>
39 /* Control whether * matches .files in globbing. */
40 int glob_dot_filenames;
42 /* Return nonzero if STRING has any unquoted special globbing chars in it. */
44 unquoted_glob_pattern_p (string)
45 register char *string;
70 if (*string++ == '\0')
77 /* PATHNAME can contain characters prefixed by CTLESC; this indicates
78 that the character is to be quoted. We quote it here in the style
79 that the glob library recognizes. If CONVERT_QUOTED_NULLS is non-zero,
80 we change quoted null strings (pathname[0] == CTLNUL) into empty
81 strings (pathname[0] == 0). If this is called after quote removal
82 is performed, CONVERT_QUOTED_NULLS should be 0; if called when quote
83 removal has not been done (for example, before attempting to match a
84 pattern while executing a case statement), CONVERT_QUOTED_NULLS should
87 quote_string_for_globbing (pathname, convert_quoted_nulls)
89 int convert_quoted_nulls;
94 temp = savestring (pathname);
96 if (convert_quoted_nulls && QUOTED_NULL (pathname))
102 for (i = 0; temp[i]; i++)
104 if (temp[i] == CTLESC)
112 quote_globbing_chars (string)
117 temp = xmalloc (strlen (string) * 2 + 1);
118 for (t = temp, s = string; *s; )
136 /* Call the glob library to do globbing on PATHNAME. */
138 shell_glob_filename (pathname)
141 #if defined (USE_POSIX_GLOB_LIBRARY)
143 char *temp, **return_value;
147 temp = quote_string_for_globbing (pathname, 0);
149 filenames.gl_offs = 0;
151 glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
152 glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
154 i = glob (temp, glob_flags, (Function *)NULL, &filenames);
158 if (i == GLOB_NOSPACE || i == GLOB_ABEND)
159 return ((char **)NULL);
161 if (i == GLOB_NOMATCH)
162 filenames.gl_pathv[0] = (char *)NULL;
164 return (filenames.gl_pathv);
166 #else /* !USE_POSIX_GLOB_LIBRARY */
168 char *temp, **results;
170 noglob_dot_filenames = glob_dot_filenames == 0;
172 temp = quote_string_for_globbing (pathname, 0);
174 results = glob_filename (temp);
177 if (results && ((GLOB_FAILED (results)) == 0))
179 if (should_ignore_glob_matches ())
180 ignore_glob_matches (results);
181 if (results && results[0])
182 sort_char_array (results);
186 results = (char **)&glob_error_return;
191 #endif /* !USE_POSIX_GLOB_LIBRARY */
194 /* Stuff for GLOBIGNORE. */
196 static struct ignorevar globignore =
205 /* Set up to ignore some glob matches because the value of GLOBIGNORE
206 has changed. If GLOBIGNORE is being unset, we also need to disable
207 the globbing of filenames beginning with a `.'. */
209 setup_glob_ignore (name)
214 v = get_string_value (name);
215 setup_ignore_patterns (&globignore);
217 if (globignore.num_ignores)
218 glob_dot_filenames = 1;
220 glob_dot_filenames = 0;
224 should_ignore_glob_matches ()
226 return globignore.num_ignores;
229 /* Return 0 if NAME matches a pattern in the globignore.ignores list. */
231 glob_name_is_acceptable (name)
236 /* . and .. are never matched */
237 if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
240 for (p = globignore.ignores; p->val; p++)
242 if (fnmatch (p->val, name, FNM_PATHNAME) != FNM_NOMATCH)
248 /* Internal function to test whether filenames in NAMES should be
249 ignored. NAME_FUNC is a pointer to a function to call with each
250 name. It returns non-zero if the name is acceptable to the particular
251 ignore function which called _ignore_names; zero if the name should
252 be removed from NAMES. */
255 ignore_globbed_names (names, name_func)
262 for (i = 0; names[i]; i++)
264 newnames = (char **)xmalloc ((i + 1) * sizeof (char *));
266 for (n = i = 0; names[i]; i++)
268 if ((*name_func) (names[i]))
269 newnames[n++] = names[i];
274 newnames[n] = (char *)NULL;
278 names[0] = (char *)NULL;
283 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
285 for (n = 0; newnames[n]; n++)
286 names[n] = newnames[n];
287 names[n] = (char *)NULL;
291 ignore_glob_matches (names)
294 if (globignore.num_ignores == 0)
297 ignore_globbed_names (names, glob_name_is_acceptable);
301 setup_ignore_patterns (ivp)
302 struct ignorevar *ivp;
304 int numitems, maxitems, ptr;
305 char *colon_bit, *this_ignoreval;
308 this_ignoreval = get_string_value (ivp->varname);
310 /* If nothing has changed then just exit now. */
311 if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) ||
312 (!this_ignoreval && !ivp->last_ignoreval))
315 /* Oops. The ignore variable has changed. Re-parse it. */
316 ivp->num_ignores = 0;
320 for (p = ivp->ignores; p->val; p++)
323 ivp->ignores = (struct ign *)NULL;
326 if (ivp->last_ignoreval)
328 free (ivp->last_ignoreval);
329 ivp->last_ignoreval = (char *)NULL;
332 if (this_ignoreval == 0 || *this_ignoreval == '\0')
335 ivp->last_ignoreval = savestring (this_ignoreval);
337 numitems = maxitems = ptr = 0;
339 while (colon_bit = extract_colon_unit (this_ignoreval, &ptr))
341 if (numitems + 1 >= maxitems)
344 ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign));
346 ivp->ignores[numitems].val = colon_bit;
347 ivp->ignores[numitems].len = strlen (colon_bit);
348 ivp->ignores[numitems].flags = 0;
350 (*ivp->item_func) (&ivp->ignores[numitems]);
353 ivp->ignores[numitems].val = (char *)NULL;
354 ivp->num_ignores = numitems;