]> git.ipfire.org Git - thirdparty/bash.git/blame - pathexp.c
Bash-4.0 patchlevel 38
[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 *));
43
b72432fd
JA
44#if defined (USE_POSIX_GLOB_LIBRARY)
45# include <glob.h>
f73dda09 46typedef int posix_glob_errfunc_t __P((const char *, int));
b72432fd
JA
47#else
48# include <glob/glob.h>
49#endif
ccc6cda3
JA
50
51/* Control whether * matches .files in globbing. */
52int glob_dot_filenames;
53
cce855bc
JA
54/* Control whether the extended globbing features are enabled. */
55int extended_glob = 0;
56
3185942a
JA
57/* Control enabling special handling of `**' */
58int glob_star = 0;
59
ccc6cda3
JA
60/* Return nonzero if STRING has any unquoted special globbing chars in it. */
61int
62unquoted_glob_pattern_p (string)
63 register char *string;
64{
65 register int c;
7117c2d2 66 char *send;
ccc6cda3
JA
67 int open;
68
7117c2d2
JA
69 DECLARE_MBSTATE;
70
ccc6cda3 71 open = 0;
7117c2d2
JA
72 send = string + strlen (string);
73
ccc6cda3
JA
74 while (c = *string++)
75 {
76 switch (c)
77 {
78 case '?':
79 case '*':
80 return (1);
81
82 case '[':
83 open++;
84 continue;
85
86 case ']':
87 if (open)
88 return (1);
89 continue;
90
cce855bc
JA
91 case '+':
92 case '@':
93 case '!':
94 if (*string == '(') /*)*/
95 return (1);
96 continue;
97
ccc6cda3
JA
98 case CTLESC:
99 case '\\':
100 if (*string++ == '\0')
101 return (0);
102 }
7117c2d2
JA
103
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
107 string--;
108 ADVANCE_CHAR_P (string, send - string);
109 string++;
110#else
111 ADVANCE_CHAR_P (string, send - string);
112#endif
ccc6cda3
JA
113 }
114 return (0);
115}
116
f1be666c
JA
117/* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
118 be quoted to match itself. */
119static inline int
120ere_char (c)
121 int c;
122{
123 switch (c)
124 {
125 case '.':
126 case '[':
127 case '\\':
128 case '(':
129 case ')':
130 case '*':
131 case '+':
132 case '?':
133 case '{':
134 case '|':
135 case '^':
136 case '$':
137 return 1;
138 default:
139 return 0;
140 }
141 return (0);
142}
143
3185942a
JA
144int
145glob_char_p (s)
146 const char *s;
147{
148 switch (*s)
149 {
150 case '*':
151 case '[':
152 case ']':
153 case '?':
154 case '\\':
155 return 1;
156 case '+':
157 case '@':
158 case '!':
159 if (s[1] == '(') /*(*/
160 return 1;
161 break;
162 }
163 return 0;
164}
165
ccc6cda3
JA
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
cce855bc 168 that the glob library recognizes. If flags includes QGLOB_CVTNULL,
ccc6cda3
JA
169 we change quoted null strings (pathname[0] == CTLNUL) into empty
170 strings (pathname[0] == 0). If this is called after quote removal
cce855bc 171 is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote
ccc6cda3 172 removal has not been done (for example, before attempting to match a
cce855bc
JA
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. */
ccc6cda3 176char *
cce855bc 177quote_string_for_globbing (pathname, qflags)
28ef6c31 178 const char *pathname;
cce855bc 179 int qflags;
ccc6cda3
JA
180{
181 char *temp;
cce855bc 182 register int i, j;
ccc6cda3 183
f73dda09 184 temp = (char *)xmalloc (strlen (pathname) + 1);
ccc6cda3 185
cce855bc 186 if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname))
ccc6cda3
JA
187 {
188 temp[0] = '\0';
189 return temp;
190 }
191
cce855bc 192 for (i = j = 0; pathname[i]; i++)
ccc6cda3 193 {
cce855bc 194 if (pathname[i] == CTLESC)
28ef6c31
JA
195 {
196 if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/')
197 continue;
f1be666c
JA
198 if ((qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0)
199 continue;
cce855bc 200 temp[j++] = '\\';
7117c2d2
JA
201 i++;
202 if (pathname[i] == '\0')
203 break;
28ef6c31 204 }
3185942a
JA
205 else if (pathname[i] == '\\')
206 {
207 temp[j++] = '\\';
208 i++;
209 if (pathname[i] == '\0')
210 break;
211 }
7117c2d2 212 temp[j++] = pathname[i];
ccc6cda3 213 }
cce855bc 214 temp[j] = '\0';
ccc6cda3
JA
215
216 return (temp);
217}
218
219char *
220quote_globbing_chars (string)
221 char *string;
222{
7117c2d2
JA
223 size_t slen;
224 char *temp, *s, *t, *send;
225 DECLARE_MBSTATE;
226
227 slen = strlen (string);
228 send = string + slen;
ccc6cda3 229
7117c2d2 230 temp = (char *)xmalloc (slen * 2 + 1);
ccc6cda3
JA
231 for (t = temp, s = string; *s; )
232 {
3185942a
JA
233 if (glob_char_p (s))
234 *t++ = '\\';
7117c2d2
JA
235
236 /* Copy a single (possibly multibyte) character from s to t,
237 incrementing both. */
238 COPY_CHAR_P (t, s, send);
ccc6cda3
JA
239 }
240 *t = '\0';
241 return temp;
242}
243
244/* Call the glob library to do globbing on PATHNAME. */
245char **
246shell_glob_filename (pathname)
28ef6c31 247 const char *pathname;
ccc6cda3
JA
248{
249#if defined (USE_POSIX_GLOB_LIBRARY)
250 register int i;
28ef6c31 251 char *temp, **results;
ccc6cda3
JA
252 glob_t filenames;
253 int glob_flags;
254
cce855bc 255 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
ccc6cda3
JA
256
257 filenames.gl_offs = 0;
258
b72432fd 259# if defined (GLOB_PERIOD)
ccc6cda3 260 glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
b72432fd
JA
261# else
262 glob_flags = 0;
263# endif /* !GLOB_PERIOD */
264
ccc6cda3
JA
265 glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
266
f73dda09 267 i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames);
ccc6cda3
JA
268
269 free (temp);
270
28ef6c31 271 if (i == GLOB_NOSPACE || i == GLOB_ABORTED)
ccc6cda3 272 return ((char **)NULL);
b72432fd
JA
273 else if (i == GLOB_NOMATCH)
274 filenames.gl_pathv = (char **)NULL;
275 else if (i != 0) /* other error codes not in POSIX.2 */
cce855bc 276 filenames.gl_pathv = (char **)NULL;
ccc6cda3 277
bb70624e
JA
278 results = filenames.gl_pathv;
279
280 if (results && ((GLOB_FAILED (results)) == 0))
281 {
282 if (should_ignore_glob_matches ())
283 ignore_glob_matches (results);
284 if (results && results[0])
7117c2d2 285 strvec_sort (results);
bb70624e
JA
286 else
287 {
288 FREE (results);
289 results = (char **)NULL;
290 }
291 }
292
293 return (results);
ccc6cda3
JA
294
295#else /* !USE_POSIX_GLOB_LIBRARY */
296
297 char *temp, **results;
298
299 noglob_dot_filenames = glob_dot_filenames == 0;
300
cce855bc 301 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
3185942a 302 results = glob_filename (temp, glob_star ? GX_GLOBSTAR : 0);
ccc6cda3
JA
303 free (temp);
304
305 if (results && ((GLOB_FAILED (results)) == 0))
306 {
307 if (should_ignore_glob_matches ())
308 ignore_glob_matches (results);
309 if (results && results[0])
7117c2d2 310 strvec_sort (results);
ccc6cda3
JA
311 else
312 {
313 FREE (results);
314 results = (char **)&glob_error_return;
315 }
316 }
317
318 return (results);
319#endif /* !USE_POSIX_GLOB_LIBRARY */
320}
321
322/* Stuff for GLOBIGNORE. */
323
324static struct ignorevar globignore =
325{
326 "GLOBIGNORE",
327 (struct ign *)0,
328 0,
329 (char *)0,
f73dda09 330 (sh_iv_item_func_t *)0,
ccc6cda3
JA
331};
332
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 `.'. */
336void
337setup_glob_ignore (name)
338 char *name;
339{
340 char *v;
341
342 v = get_string_value (name);
343 setup_ignore_patterns (&globignore);
344
345 if (globignore.num_ignores)
346 glob_dot_filenames = 1;
347 else if (v == 0)
348 glob_dot_filenames = 0;
349}
350
351int
352should_ignore_glob_matches ()
353{
354 return globignore.num_ignores;
355}
356
357/* Return 0 if NAME matches a pattern in the globignore.ignores list. */
358static int
359glob_name_is_acceptable (name)
f73dda09 360 const char *name;
ccc6cda3
JA
361{
362 struct ign *p;
cce855bc 363 int flags;
ccc6cda3
JA
364
365 /* . and .. are never matched */
366 if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
367 return (0);
368
cce855bc 369 flags = FNM_PATHNAME | FNMATCH_EXTFLAG;
ccc6cda3
JA
370 for (p = globignore.ignores; p->val; p++)
371 {
f73dda09 372 if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH)
28ef6c31 373 return (0);
ccc6cda3
JA
374 }
375 return (1);
376}
377
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. */
383
384static void
385ignore_globbed_names (names, name_func)
386 char **names;
f73dda09 387 sh_ignore_func_t *name_func;
ccc6cda3
JA
388{
389 char **newnames;
390 int n, i;
391
392 for (i = 0; names[i]; i++)
393 ;
7117c2d2 394 newnames = strvec_create (i + 1);
ccc6cda3
JA
395
396 for (n = i = 0; names[i]; i++)
397 {
398 if ((*name_func) (names[i]))
28ef6c31 399 newnames[n++] = names[i];
ccc6cda3
JA
400 else
401 free (names[i]);
402 }
403
404 newnames[n] = (char *)NULL;
405
406 if (n == 0)
407 {
408 names[0] = (char *)NULL;
409 free (newnames);
410 return;
411 }
412
413 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
414 new array end. */
415 for (n = 0; newnames[n]; n++)
416 names[n] = newnames[n];
417 names[n] = (char *)NULL;
d166f048 418 free (newnames);
ccc6cda3
JA
419}
420
421void
422ignore_glob_matches (names)
423 char **names;
424{
425 if (globignore.num_ignores == 0)
426 return;
427
428 ignore_globbed_names (names, glob_name_is_acceptable);
429}
430
431void
432setup_ignore_patterns (ivp)
433 struct ignorevar *ivp;
434{
435 int numitems, maxitems, ptr;
436 char *colon_bit, *this_ignoreval;
437 struct ign *p;
438
439 this_ignoreval = get_string_value (ivp->varname);
440
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))
444 return;
445
446 /* Oops. The ignore variable has changed. Re-parse it. */
447 ivp->num_ignores = 0;
448
449 if (ivp->ignores)
450 {
451 for (p = ivp->ignores; p->val; p++)
452 free(p->val);
453 free (ivp->ignores);
454 ivp->ignores = (struct ign *)NULL;
455 }
456
457 if (ivp->last_ignoreval)
458 {
459 free (ivp->last_ignoreval);
460 ivp->last_ignoreval = (char *)NULL;
461 }
462
463 if (this_ignoreval == 0 || *this_ignoreval == '\0')
464 return;
465
466 ivp->last_ignoreval = savestring (this_ignoreval);
467
468 numitems = maxitems = ptr = 0;
469
470 while (colon_bit = extract_colon_unit (this_ignoreval, &ptr))
471 {
472 if (numitems + 1 >= maxitems)
473 {
474 maxitems += 10;
475 ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign));
476 }
477 ivp->ignores[numitems].val = colon_bit;
478 ivp->ignores[numitems].len = strlen (colon_bit);
479 ivp->ignores[numitems].flags = 0;
480 if (ivp->item_func)
28ef6c31 481 (*ivp->item_func) (&ivp->ignores[numitems]);
ccc6cda3
JA
482 numitems++;
483 }
484 ivp->ignores[numitems].val = (char *)NULL;
485 ivp->num_ignores = numitems;
486}