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;
292 ignore_glob_matches (names)
295 if (globignore.num_ignores == 0)
298 ignore_globbed_names (names, glob_name_is_acceptable);
302 setup_ignore_patterns (ivp)
303 struct ignorevar *ivp;
305 int numitems, maxitems, ptr;
306 char *colon_bit, *this_ignoreval;
309 this_ignoreval = get_string_value (ivp->varname);
311 /* If nothing has changed then just exit now. */
312 if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) ||
313 (!this_ignoreval && !ivp->last_ignoreval))
316 /* Oops. The ignore variable has changed. Re-parse it. */
317 ivp->num_ignores = 0;
321 for (p = ivp->ignores; p->val; p++)
324 ivp->ignores = (struct ign *)NULL;
327 if (ivp->last_ignoreval)
329 free (ivp->last_ignoreval);
330 ivp->last_ignoreval = (char *)NULL;
333 if (this_ignoreval == 0 || *this_ignoreval == '\0')
336 ivp->last_ignoreval = savestring (this_ignoreval);
338 numitems = maxitems = ptr = 0;
340 while (colon_bit = extract_colon_unit (this_ignoreval, &ptr))
342 if (numitems + 1 >= maxitems)
345 ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign));
347 ivp->ignores[numitems].val = colon_bit;
348 ivp->ignores[numitems].len = strlen (colon_bit);
349 ivp->ignores[numitems].flags = 0;
351 (*ivp->item_func) (&ivp->ignores[numitems]);
354 ivp->ignores[numitems].val = (char *)NULL;
355 ivp->num_ignores = numitems;