]> git.ipfire.org Git - thirdparty/bash.git/blame - pathexp.c
prep for bash-4.3 release
[thirdparty/bash.git] / pathexp.c
CommitLineData
ccc6cda3
JA
1/* pathexp.c -- The shell interface to the globbing library. */
2
3185942a 3/* Copyright (C) 1995-2009 Free Software Foundation, Inc.
ccc6cda3
JA
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
3185942a
JA
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.
ccc6cda3 11
3185942a
JA
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.
ccc6cda3 16
3185942a
JA
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/>.
19*/
ccc6cda3
JA
20
21#include "config.h"
22
23#include "bashtypes.h"
24#include <stdio.h>
25
26#if defined (HAVE_UNISTD_H)
27# include <unistd.h>
28#endif
29
30#include "bashansi.h"
31
32#include "shell.h"
33#include "pathexp.h"
34#include "flags.h"
35
7117c2d2 36#include "shmbutil.h"
3185942a 37#include "bashintl.h"
7117c2d2 38
f73dda09 39#include <glob/strmatch.h>
b72432fd 40
7117c2d2
JA
41static int glob_name_is_acceptable __P((const char *));
42static void ignore_globbed_names __P((char **, sh_ignore_func_t *));
495aee44 43static char *split_ignorespec __P((char *, int *));
7117c2d2 44
b72432fd
JA
45#if defined (USE_POSIX_GLOB_LIBRARY)
46# include <glob.h>
f73dda09 47typedef int posix_glob_errfunc_t __P((const char *, int));
b72432fd
JA
48#else
49# include <glob/glob.h>
50#endif
ccc6cda3
JA
51
52/* Control whether * matches .files in globbing. */
53int glob_dot_filenames;
54
cce855bc 55/* Control whether the extended globbing features are enabled. */
0001803f 56int extended_glob = EXTGLOB_DEFAULT;
cce855bc 57
3185942a
JA
58/* Control enabling special handling of `**' */
59int glob_star = 0;
60
ccc6cda3
JA
61/* Return nonzero if STRING has any unquoted special globbing chars in it. */
62int
63unquoted_glob_pattern_p (string)
64 register char *string;
65{
66 register int c;
7117c2d2 67 char *send;
ccc6cda3
JA
68 int open;
69
7117c2d2
JA
70 DECLARE_MBSTATE;
71
ccc6cda3 72 open = 0;
7117c2d2
JA
73 send = string + strlen (string);
74
ccc6cda3
JA
75 while (c = *string++)
76 {
77 switch (c)
78 {
79 case '?':
80 case '*':
81 return (1);
82
83 case '[':
84 open++;
85 continue;
86
87 case ']':
88 if (open)
89 return (1);
90 continue;
91
cce855bc
JA
92 case '+':
93 case '@':
94 case '!':
95 if (*string == '(') /*)*/
96 return (1);
97 continue;
98
ccc6cda3
JA
99 case CTLESC:
100 case '\\':
101 if (*string++ == '\0')
102 return (0);
103 }
7117c2d2
JA
104
105 /* Advance one fewer byte than an entire multibyte character to
106 account for the auto-increment in the loop above. */
107#ifdef HANDLE_MULTIBYTE
108 string--;
109 ADVANCE_CHAR_P (string, send - string);
110 string++;
111#else
112 ADVANCE_CHAR_P (string, send - string);
113#endif
ccc6cda3
JA
114 }
115 return (0);
116}
117
f1be666c
JA
118/* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
119 be quoted to match itself. */
120static inline int
121ere_char (c)
122 int c;
123{
124 switch (c)
125 {
126 case '.':
127 case '[':
128 case '\\':
129 case '(':
130 case ')':
131 case '*':
132 case '+':
133 case '?':
134 case '{':
135 case '|':
136 case '^':
137 case '$':
138 return 1;
139 default:
140 return 0;
141 }
142 return (0);
143}
144
3185942a
JA
145int
146glob_char_p (s)
147 const char *s;
148{
149 switch (*s)
150 {
151 case '*':
152 case '[':
153 case ']':
154 case '?':
155 case '\\':
156 return 1;
157 case '+':
158 case '@':
159 case '!':
160 if (s[1] == '(') /*(*/
161 return 1;
162 break;
163 }
164 return 0;
165}
166
ccc6cda3
JA
167/* PATHNAME can contain characters prefixed by CTLESC; this indicates
168 that the character is to be quoted. We quote it here in the style
cce855bc 169 that the glob library recognizes. If flags includes QGLOB_CVTNULL,
ccc6cda3
JA
170 we change quoted null strings (pathname[0] == CTLNUL) into empty
171 strings (pathname[0] == 0). If this is called after quote removal
cce855bc 172 is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote
ccc6cda3 173 removal has not been done (for example, before attempting to match a
cce855bc
JA
174 pattern while executing a case statement), flags should include
175 QGLOB_CVTNULL. If flags includes QGLOB_FILENAME, appropriate quoting
176 to match a filename should be performed. */
ccc6cda3 177char *
cce855bc 178quote_string_for_globbing (pathname, qflags)
28ef6c31 179 const char *pathname;
cce855bc 180 int qflags;
ccc6cda3
JA
181{
182 char *temp;
cce855bc 183 register int i, j;
ccc6cda3 184
f73dda09 185 temp = (char *)xmalloc (strlen (pathname) + 1);
ccc6cda3 186
cce855bc 187 if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname))
ccc6cda3
JA
188 {
189 temp[0] = '\0';
190 return temp;
191 }
192
cce855bc 193 for (i = j = 0; pathname[i]; i++)
ccc6cda3 194 {
cce855bc 195 if (pathname[i] == CTLESC)
28ef6c31
JA
196 {
197 if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/')
198 continue;
25db9a70 199 if (pathname[i+1] != CTLESC && (qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0)
f1be666c 200 continue;
cce855bc 201 temp[j++] = '\\';
7117c2d2
JA
202 i++;
203 if (pathname[i] == '\0')
204 break;
28ef6c31 205 }
3185942a
JA
206 else if (pathname[i] == '\\')
207 {
208 temp[j++] = '\\';
209 i++;
210 if (pathname[i] == '\0')
211 break;
212 }
7117c2d2 213 temp[j++] = pathname[i];
ccc6cda3 214 }
cce855bc 215 temp[j] = '\0';
ccc6cda3
JA
216
217 return (temp);
218}
219
220char *
221quote_globbing_chars (string)
222 char *string;
223{
7117c2d2
JA
224 size_t slen;
225 char *temp, *s, *t, *send;
226 DECLARE_MBSTATE;
227
228 slen = strlen (string);
229 send = string + slen;
ccc6cda3 230
7117c2d2 231 temp = (char *)xmalloc (slen * 2 + 1);
ccc6cda3
JA
232 for (t = temp, s = string; *s; )
233 {
3185942a
JA
234 if (glob_char_p (s))
235 *t++ = '\\';
7117c2d2
JA
236
237 /* Copy a single (possibly multibyte) character from s to t,
238 incrementing both. */
239 COPY_CHAR_P (t, s, send);
ccc6cda3
JA
240 }
241 *t = '\0';
242 return temp;
243}
244
245/* Call the glob library to do globbing on PATHNAME. */
246char **
247shell_glob_filename (pathname)
28ef6c31 248 const char *pathname;
ccc6cda3
JA
249{
250#if defined (USE_POSIX_GLOB_LIBRARY)
251 register int i;
28ef6c31 252 char *temp, **results;
ccc6cda3
JA
253 glob_t filenames;
254 int glob_flags;
255
cce855bc 256 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
ccc6cda3
JA
257
258 filenames.gl_offs = 0;
259
b72432fd 260# if defined (GLOB_PERIOD)
ccc6cda3 261 glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
b72432fd
JA
262# else
263 glob_flags = 0;
264# endif /* !GLOB_PERIOD */
265
ccc6cda3
JA
266 glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
267
f73dda09 268 i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames);
ccc6cda3
JA
269
270 free (temp);
271
28ef6c31 272 if (i == GLOB_NOSPACE || i == GLOB_ABORTED)
ccc6cda3 273 return ((char **)NULL);
b72432fd
JA
274 else if (i == GLOB_NOMATCH)
275 filenames.gl_pathv = (char **)NULL;
276 else if (i != 0) /* other error codes not in POSIX.2 */
cce855bc 277 filenames.gl_pathv = (char **)NULL;
ccc6cda3 278
bb70624e
JA
279 results = filenames.gl_pathv;
280
281 if (results && ((GLOB_FAILED (results)) == 0))
282 {
283 if (should_ignore_glob_matches ())
284 ignore_glob_matches (results);
285 if (results && results[0])
7117c2d2 286 strvec_sort (results);
bb70624e
JA
287 else
288 {
289 FREE (results);
290 results = (char **)NULL;
291 }
292 }
293
294 return (results);
ccc6cda3
JA
295
296#else /* !USE_POSIX_GLOB_LIBRARY */
297
298 char *temp, **results;
299
300 noglob_dot_filenames = glob_dot_filenames == 0;
301
cce855bc 302 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
3185942a 303 results = glob_filename (temp, glob_star ? GX_GLOBSTAR : 0);
ccc6cda3
JA
304 free (temp);
305
306 if (results && ((GLOB_FAILED (results)) == 0))
307 {
308 if (should_ignore_glob_matches ())
309 ignore_glob_matches (results);
310 if (results && results[0])
7117c2d2 311 strvec_sort (results);
ccc6cda3
JA
312 else
313 {
314 FREE (results);
315 results = (char **)&glob_error_return;
316 }
317 }
318
319 return (results);
320#endif /* !USE_POSIX_GLOB_LIBRARY */
321}
322
323/* Stuff for GLOBIGNORE. */
324
325static struct ignorevar globignore =
326{
327 "GLOBIGNORE",
328 (struct ign *)0,
329 0,
330 (char *)0,
f73dda09 331 (sh_iv_item_func_t *)0,
ccc6cda3
JA
332};
333
334/* Set up to ignore some glob matches because the value of GLOBIGNORE
335 has changed. If GLOBIGNORE is being unset, we also need to disable
336 the globbing of filenames beginning with a `.'. */
337void
338setup_glob_ignore (name)
339 char *name;
340{
341 char *v;
342
343 v = get_string_value (name);
344 setup_ignore_patterns (&globignore);
345
346 if (globignore.num_ignores)
347 glob_dot_filenames = 1;
348 else if (v == 0)
349 glob_dot_filenames = 0;
350}
351
352int
353should_ignore_glob_matches ()
354{
355 return globignore.num_ignores;
356}
357
358/* Return 0 if NAME matches a pattern in the globignore.ignores list. */
359static int
360glob_name_is_acceptable (name)
f73dda09 361 const char *name;
ccc6cda3
JA
362{
363 struct ign *p;
cce855bc 364 int flags;
ccc6cda3
JA
365
366 /* . and .. are never matched */
367 if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
368 return (0);
369
cce855bc 370 flags = FNM_PATHNAME | FNMATCH_EXTFLAG;
ccc6cda3
JA
371 for (p = globignore.ignores; p->val; p++)
372 {
f73dda09 373 if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH)
28ef6c31 374 return (0);
ccc6cda3
JA
375 }
376 return (1);
377}
378
379/* Internal function to test whether filenames in NAMES should be
380 ignored. NAME_FUNC is a pointer to a function to call with each
381 name. It returns non-zero if the name is acceptable to the particular
382 ignore function which called _ignore_names; zero if the name should
383 be removed from NAMES. */
384
385static void
386ignore_globbed_names (names, name_func)
387 char **names;
f73dda09 388 sh_ignore_func_t *name_func;
ccc6cda3
JA
389{
390 char **newnames;
391 int n, i;
392
393 for (i = 0; names[i]; i++)
394 ;
7117c2d2 395 newnames = strvec_create (i + 1);
ccc6cda3
JA
396
397 for (n = i = 0; names[i]; i++)
398 {
399 if ((*name_func) (names[i]))
28ef6c31 400 newnames[n++] = names[i];
ccc6cda3
JA
401 else
402 free (names[i]);
403 }
404
405 newnames[n] = (char *)NULL;
406
407 if (n == 0)
408 {
409 names[0] = (char *)NULL;
410 free (newnames);
411 return;
412 }
413
414 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
415 new array end. */
416 for (n = 0; newnames[n]; n++)
417 names[n] = newnames[n];
418 names[n] = (char *)NULL;
d166f048 419 free (newnames);
ccc6cda3
JA
420}
421
422void
423ignore_glob_matches (names)
424 char **names;
425{
426 if (globignore.num_ignores == 0)
427 return;
428
429 ignore_globbed_names (names, glob_name_is_acceptable);
430}
431
495aee44
CR
432static char *
433split_ignorespec (s, ip)
434 char *s;
435 int *ip;
436{
437 char *t;
438 int n, i;
439
440 if (s == 0)
441 return 0;
442
443 i = *ip;
444 if (s[i] == 0)
445 return 0;
446
447 n = skip_to_delim (s, i, ":", SD_NOJMP|SD_EXTGLOB);
448 t = substring (s, i, n);
449
450 if (s[n] == ':')
451 n++;
452 *ip = n;
453 return t;
454}
455
ccc6cda3
JA
456void
457setup_ignore_patterns (ivp)
458 struct ignorevar *ivp;
459{
460 int numitems, maxitems, ptr;
461 char *colon_bit, *this_ignoreval;
462 struct ign *p;
463
464 this_ignoreval = get_string_value (ivp->varname);
465
466 /* If nothing has changed then just exit now. */
467 if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) ||
468 (!this_ignoreval && !ivp->last_ignoreval))
469 return;
470
471 /* Oops. The ignore variable has changed. Re-parse it. */
472 ivp->num_ignores = 0;
473
474 if (ivp->ignores)
475 {
476 for (p = ivp->ignores; p->val; p++)
477 free(p->val);
478 free (ivp->ignores);
479 ivp->ignores = (struct ign *)NULL;
480 }
481
482 if (ivp->last_ignoreval)
483 {
484 free (ivp->last_ignoreval);
485 ivp->last_ignoreval = (char *)NULL;
486 }
487
488 if (this_ignoreval == 0 || *this_ignoreval == '\0')
489 return;
490
491 ivp->last_ignoreval = savestring (this_ignoreval);
492
493 numitems = maxitems = ptr = 0;
494
495aee44 495#if 0
ccc6cda3 496 while (colon_bit = extract_colon_unit (this_ignoreval, &ptr))
495aee44
CR
497#else
498 while (colon_bit = split_ignorespec (this_ignoreval, &ptr))
499#endif
ccc6cda3
JA
500 {
501 if (numitems + 1 >= maxitems)
502 {
503 maxitems += 10;
504 ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign));
505 }
506 ivp->ignores[numitems].val = colon_bit;
507 ivp->ignores[numitems].len = strlen (colon_bit);
508 ivp->ignores[numitems].flags = 0;
509 if (ivp->item_func)
28ef6c31 510 (*ivp->item_func) (&ivp->ignores[numitems]);
ccc6cda3
JA
511 numitems++;
512 }
513 ivp->ignores[numitems].val = (char *)NULL;
514 ivp->num_ignores = numitems;
515}