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/>.
23 #include "bashtypes.h"
26 #if defined (HAVE_UNISTD_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)
46 typedef int posix_glob_errfunc_t
__P((const char *, int));
48 # include <glob/glob.h>
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 `**' */
60 /* Return nonzero if STRING has any unquoted special globbing chars in it. */
62 unquoted_glob_pattern_p (string
)
63 register char *string
;
72 send
= string
+ strlen (string
);
94 if (*string
== '(') /*)*/
100 if (*string
++ == '\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
108 ADVANCE_CHAR_P (string
, send
- string
);
111 ADVANCE_CHAR_P (string
, send
- string
);
117 /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
118 be quoted to match itself. */
159 if (s
[1] == '(') /*(*/
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. */
177 quote_string_for_globbing (pathname
, qflags
)
178 const char *pathname
;
184 temp
= (char *)xmalloc (strlen (pathname
) + 1);
186 if ((qflags
& QGLOB_CVTNULL
) && QUOTED_NULL (pathname
))
192 for (i
= j
= 0; pathname
[i
]; i
++)
194 if (pathname
[i
] == CTLESC
)
196 if ((qflags
& QGLOB_FILENAME
) && pathname
[i
+1] == '/')
198 if ((qflags
& QGLOB_REGEXP
) && ere_char (pathname
[i
+1]) == 0)
202 if (pathname
[i
] == '\0')
205 else if (pathname
[i
] == '\\')
209 if (pathname
[i
] == '\0')
212 temp
[j
++] = pathname
[i
];
220 quote_globbing_chars (string
)
224 char *temp
, *s
, *t
, *send
;
227 slen
= strlen (string
);
228 send
= string
+ slen
;
230 temp
= (char *)xmalloc (slen
* 2 + 1);
231 for (t
= temp
, s
= string
; *s
; )
236 /* Copy a single (possibly multibyte) character from s to t,
237 incrementing both. */
238 COPY_CHAR_P (t
, s
, send
);
244 /* Call the glob library to do globbing on PATHNAME. */
246 shell_glob_filename (pathname
)
247 const char *pathname
;
249 #if defined (USE_POSIX_GLOB_LIBRARY)
251 char *temp
, **results
;
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;
263 # endif /* !GLOB_PERIOD */
265 glob_flags
|= (GLOB_ERR
| GLOB_DOOFFS
);
267 i
= glob (temp
, glob_flags
, (posix_glob_errfunc_t
*)NULL
, &filenames
);
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
);
289 results
= (char **)NULL
;
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);
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
);
314 results
= (char **)&glob_error_return
;
319 #endif /* !USE_POSIX_GLOB_LIBRARY */
322 /* Stuff for GLOBIGNORE. */
324 static struct ignorevar globignore
=
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 `.'. */
337 setup_glob_ignore (name
)
342 v
= get_string_value (name
);
343 setup_ignore_patterns (&globignore
);
345 if (globignore
.num_ignores
)
346 glob_dot_filenames
= 1;
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. */
359 glob_name_is_acceptable (name
)
365 /* . and .. are never matched */
366 if (name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\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
)
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. */
385 ignore_globbed_names (names
, name_func
)
387 sh_ignore_func_t
*name_func
;
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
];
404 newnames
[n
] = (char *)NULL
;
408 names
[0] = (char *)NULL
;
413 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
415 for (n
= 0; newnames
[n
]; n
++)
416 names
[n
] = newnames
[n
];
417 names
[n
] = (char *)NULL
;
422 ignore_glob_matches (names
)
425 if (globignore
.num_ignores
== 0)
428 ignore_globbed_names (names
, glob_name_is_acceptable
);
432 setup_ignore_patterns (ivp
)
433 struct ignorevar
*ivp
;
435 int numitems
, maxitems
, ptr
;
436 char *colon_bit
, *this_ignoreval
;
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
))
446 /* Oops. The ignore variable has changed. Re-parse it. */
447 ivp
->num_ignores
= 0;
451 for (p
= ivp
->ignores
; p
->val
; p
++)
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')
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
)
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;
481 (*ivp
->item_func
) (&ivp
->ignores
[numitems
]);
484 ivp
->ignores
[numitems
].val
= (char *)NULL
;
485 ivp
->num_ignores
= numitems
;