]> git.ipfire.org Git - thirdparty/bash.git/blob - pathexp.c
Bash-4.3 patch 32
[thirdparty/bash.git] / pathexp.c
1 /* pathexp.c -- The shell interface to the globbing library. */
2
3 /* Copyright (C) 1995-2014 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
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.
11
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.
16
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 */
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
36 #include "shmbutil.h"
37 #include "bashintl.h"
38
39 #include <glob/strmatch.h>
40
41 static int glob_name_is_acceptable __P((const char *));
42 static void ignore_globbed_names __P((char **, sh_ignore_func_t *));
43 static char *split_ignorespec __P((char *, int *));
44
45 #if defined (USE_POSIX_GLOB_LIBRARY)
46 # include <glob.h>
47 typedef int posix_glob_errfunc_t __P((const char *, int));
48 #else
49 # include <glob/glob.h>
50 #endif
51
52 /* Control whether * matches .files in globbing. */
53 int glob_dot_filenames;
54
55 /* Control whether the extended globbing features are enabled. */
56 int extended_glob = EXTGLOB_DEFAULT;
57
58 /* Control enabling special handling of `**' */
59 int glob_star = 0;
60
61 /* Return nonzero if STRING has any unquoted special globbing chars in it. */
62 int
63 unquoted_glob_pattern_p (string)
64 register char *string;
65 {
66 register int c;
67 char *send;
68 int open;
69
70 DECLARE_MBSTATE;
71
72 open = 0;
73 send = string + strlen (string);
74
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
92 case '+':
93 case '@':
94 case '!':
95 if (*string == '(') /*)*/
96 return (1);
97 continue;
98
99 case CTLESC:
100 case '\\':
101 if (*string++ == '\0')
102 return (0);
103 }
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
114 }
115 return (0);
116 }
117
118 /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
119 be quoted to match itself. */
120 static inline int
121 ere_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
145 int
146 glob_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
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
169 that the glob library recognizes. If flags includes QGLOB_CVTNULL,
170 we change quoted null strings (pathname[0] == CTLNUL) into empty
171 strings (pathname[0] == 0). If this is called after quote removal
172 is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote
173 removal has not been done (for example, before attempting to match a
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. QGLOB_REGEXP means we're
177 quoting for a Posix ERE (for [[ string =~ pat ]]) and that requires
178 some special handling. */
179 char *
180 quote_string_for_globbing (pathname, qflags)
181 const char *pathname;
182 int qflags;
183 {
184 char *temp;
185 register int i, j;
186 int brack, cclass, collsym, equiv, c, last_was_backslash;
187
188 temp = (char *)xmalloc (2 * strlen (pathname) + 1);
189
190 if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname))
191 {
192 temp[0] = '\0';
193 return temp;
194 }
195
196 brack = cclass = collsym = equiv = last_was_backslash = 0;
197 for (i = j = 0; pathname[i]; i++)
198 {
199 /* Fix for CTLESC at the end of the string? */
200 if (pathname[i] == CTLESC && pathname[i+1] == '\0')
201 {
202 temp[j++] = pathname[i++];
203 break;
204 }
205 /* If we are parsing regexp, turn CTLESC CTLESC into CTLESC. It's not an
206 ERE special character, so we should just be able to pass it through. */
207 else if ((qflags & QGLOB_REGEXP) && pathname[i] == CTLESC && pathname[i+1] == CTLESC)
208 {
209 i++;
210 temp[j++] = pathname[i];
211 continue;
212 }
213 else if (pathname[i] == CTLESC)
214 {
215 if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/')
216 continue;
217 /* What to do if preceding char is backslash? */
218 if (pathname[i+1] != CTLESC && (qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0)
219 continue;
220 temp[j++] = '\\';
221 i++;
222 if (pathname[i] == '\0')
223 break;
224 }
225 else if ((qflags & QGLOB_REGEXP) && (i == 0 || pathname[i-1] != CTLESC) && pathname[i] == '[') /*]*/
226 {
227 brack = 1;
228 temp[j++] = pathname[i++]; /* open bracket */
229 c = pathname[i++]; /* c == char after open bracket */
230 do
231 {
232 if (c == 0)
233 goto endpat;
234 else if (c == CTLESC)
235 {
236 /* skip c, check for EOS, let assignment at end of loop */
237 /* pathname[i] == backslash-escaped character */
238 if (pathname[i] == 0)
239 goto endpat;
240 temp[j++] = pathname[i++];
241 }
242 else if (c == '[' && pathname[i] == ':')
243 {
244 temp[j++] = c;
245 temp[j++] = pathname[i++];
246 cclass = 1;
247 }
248 else if (cclass && c == ':' && pathname[i] == ']')
249 {
250 temp[j++] = c;
251 temp[j++] = pathname[i++];
252 cclass = 0;
253 }
254 else if (c == '[' && pathname[i] == '=')
255 {
256 temp[j++] = c;
257 temp[j++] = pathname[i++];
258 if (pathname[i] == ']')
259 temp[j++] = pathname[i++]; /* right brack can be in equiv */
260 equiv = 1;
261 }
262 else if (equiv && c == '=' && pathname[i] == ']')
263 {
264 temp[j++] = c;
265 temp[j++] = pathname[i++];
266 equiv = 0;
267 }
268 else if (c == '[' && pathname[i] == '.')
269 {
270 temp[j++] = c;
271 temp[j++] = pathname[i++];
272 if (pathname[i] == ']')
273 temp[j++] = pathname[i++]; /* right brack can be in collsym */
274 collsym = 1;
275 }
276 else if (collsym && c == '.' && pathname[i] == ']')
277 {
278 temp[j++] = c;
279 temp[j++] = pathname[i++];
280 collsym = 0;
281 }
282 else
283 temp[j++] = c;
284 }
285 while ((c = pathname[i++]) != ']');
286 temp[j++] = c; /* closing right bracket */
287 i--; /* increment will happen above in loop */
288 continue; /* skip double assignment below */
289 }
290 else if (pathname[i] == '\\' && (qflags & QGLOB_REGEXP) == 0)
291 {
292 /* XXX - if not quoting regexp, use backslash as quote char. Should
293 we just pass it through without treating it as special? That is
294 what ksh93 seems to do. */
295
296 /* If we want to pass through backslash unaltered, comment out these
297 lines. */
298 temp[j++] = '\\';
299
300 i++;
301 if (pathname[i] == '\0')
302 break;
303 }
304 else if (pathname[i] == '\\' && (qflags & QGLOB_REGEXP))
305 last_was_backslash = 1;
306 temp[j++] = pathname[i];
307 }
308 endpat:
309 temp[j] = '\0';
310
311 return (temp);
312 }
313
314 char *
315 quote_globbing_chars (string)
316 char *string;
317 {
318 size_t slen;
319 char *temp, *s, *t, *send;
320 DECLARE_MBSTATE;
321
322 slen = strlen (string);
323 send = string + slen;
324
325 temp = (char *)xmalloc (slen * 2 + 1);
326 for (t = temp, s = string; *s; )
327 {
328 if (glob_char_p (s))
329 *t++ = '\\';
330
331 /* Copy a single (possibly multibyte) character from s to t,
332 incrementing both. */
333 COPY_CHAR_P (t, s, send);
334 }
335 *t = '\0';
336 return temp;
337 }
338
339 /* Call the glob library to do globbing on PATHNAME. */
340 char **
341 shell_glob_filename (pathname)
342 const char *pathname;
343 {
344 #if defined (USE_POSIX_GLOB_LIBRARY)
345 register int i;
346 char *temp, **results;
347 glob_t filenames;
348 int glob_flags;
349
350 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
351
352 filenames.gl_offs = 0;
353
354 # if defined (GLOB_PERIOD)
355 glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
356 # else
357 glob_flags = 0;
358 # endif /* !GLOB_PERIOD */
359
360 glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
361
362 i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames);
363
364 free (temp);
365
366 if (i == GLOB_NOSPACE || i == GLOB_ABORTED)
367 return ((char **)NULL);
368 else if (i == GLOB_NOMATCH)
369 filenames.gl_pathv = (char **)NULL;
370 else if (i != 0) /* other error codes not in POSIX.2 */
371 filenames.gl_pathv = (char **)NULL;
372
373 results = filenames.gl_pathv;
374
375 if (results && ((GLOB_FAILED (results)) == 0))
376 {
377 if (should_ignore_glob_matches ())
378 ignore_glob_matches (results);
379 if (results && results[0])
380 strvec_sort (results);
381 else
382 {
383 FREE (results);
384 results = (char **)NULL;
385 }
386 }
387
388 return (results);
389
390 #else /* !USE_POSIX_GLOB_LIBRARY */
391
392 char *temp, **results;
393
394 noglob_dot_filenames = glob_dot_filenames == 0;
395
396 temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
397 results = glob_filename (temp, glob_star ? GX_GLOBSTAR : 0);
398 free (temp);
399
400 if (results && ((GLOB_FAILED (results)) == 0))
401 {
402 if (should_ignore_glob_matches ())
403 ignore_glob_matches (results);
404 if (results && results[0])
405 strvec_sort (results);
406 else
407 {
408 FREE (results);
409 results = (char **)&glob_error_return;
410 }
411 }
412
413 return (results);
414 #endif /* !USE_POSIX_GLOB_LIBRARY */
415 }
416
417 /* Stuff for GLOBIGNORE. */
418
419 static struct ignorevar globignore =
420 {
421 "GLOBIGNORE",
422 (struct ign *)0,
423 0,
424 (char *)0,
425 (sh_iv_item_func_t *)0,
426 };
427
428 /* Set up to ignore some glob matches because the value of GLOBIGNORE
429 has changed. If GLOBIGNORE is being unset, we also need to disable
430 the globbing of filenames beginning with a `.'. */
431 void
432 setup_glob_ignore (name)
433 char *name;
434 {
435 char *v;
436
437 v = get_string_value (name);
438 setup_ignore_patterns (&globignore);
439
440 if (globignore.num_ignores)
441 glob_dot_filenames = 1;
442 else if (v == 0)
443 glob_dot_filenames = 0;
444 }
445
446 int
447 should_ignore_glob_matches ()
448 {
449 return globignore.num_ignores;
450 }
451
452 /* Return 0 if NAME matches a pattern in the globignore.ignores list. */
453 static int
454 glob_name_is_acceptable (name)
455 const char *name;
456 {
457 struct ign *p;
458 int flags;
459
460 /* . and .. are never matched */
461 if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
462 return (0);
463
464 flags = FNM_PATHNAME | FNMATCH_EXTFLAG;
465 for (p = globignore.ignores; p->val; p++)
466 {
467 if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH)
468 return (0);
469 }
470 return (1);
471 }
472
473 /* Internal function to test whether filenames in NAMES should be
474 ignored. NAME_FUNC is a pointer to a function to call with each
475 name. It returns non-zero if the name is acceptable to the particular
476 ignore function which called _ignore_names; zero if the name should
477 be removed from NAMES. */
478
479 static void
480 ignore_globbed_names (names, name_func)
481 char **names;
482 sh_ignore_func_t *name_func;
483 {
484 char **newnames;
485 int n, i;
486
487 for (i = 0; names[i]; i++)
488 ;
489 newnames = strvec_create (i + 1);
490
491 for (n = i = 0; names[i]; i++)
492 {
493 if ((*name_func) (names[i]))
494 newnames[n++] = names[i];
495 else
496 free (names[i]);
497 }
498
499 newnames[n] = (char *)NULL;
500
501 if (n == 0)
502 {
503 names[0] = (char *)NULL;
504 free (newnames);
505 return;
506 }
507
508 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
509 new array end. */
510 for (n = 0; newnames[n]; n++)
511 names[n] = newnames[n];
512 names[n] = (char *)NULL;
513 free (newnames);
514 }
515
516 void
517 ignore_glob_matches (names)
518 char **names;
519 {
520 if (globignore.num_ignores == 0)
521 return;
522
523 ignore_globbed_names (names, glob_name_is_acceptable);
524 }
525
526 static char *
527 split_ignorespec (s, ip)
528 char *s;
529 int *ip;
530 {
531 char *t;
532 int n, i;
533
534 if (s == 0)
535 return 0;
536
537 i = *ip;
538 if (s[i] == 0)
539 return 0;
540
541 n = skip_to_delim (s, i, ":", SD_NOJMP|SD_EXTGLOB);
542 t = substring (s, i, n);
543
544 if (s[n] == ':')
545 n++;
546 *ip = n;
547 return t;
548 }
549
550 void
551 setup_ignore_patterns (ivp)
552 struct ignorevar *ivp;
553 {
554 int numitems, maxitems, ptr;
555 char *colon_bit, *this_ignoreval;
556 struct ign *p;
557
558 this_ignoreval = get_string_value (ivp->varname);
559
560 /* If nothing has changed then just exit now. */
561 if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) ||
562 (!this_ignoreval && !ivp->last_ignoreval))
563 return;
564
565 /* Oops. The ignore variable has changed. Re-parse it. */
566 ivp->num_ignores = 0;
567
568 if (ivp->ignores)
569 {
570 for (p = ivp->ignores; p->val; p++)
571 free(p->val);
572 free (ivp->ignores);
573 ivp->ignores = (struct ign *)NULL;
574 }
575
576 if (ivp->last_ignoreval)
577 {
578 free (ivp->last_ignoreval);
579 ivp->last_ignoreval = (char *)NULL;
580 }
581
582 if (this_ignoreval == 0 || *this_ignoreval == '\0')
583 return;
584
585 ivp->last_ignoreval = savestring (this_ignoreval);
586
587 numitems = maxitems = ptr = 0;
588
589 #if 0
590 while (colon_bit = extract_colon_unit (this_ignoreval, &ptr))
591 #else
592 while (colon_bit = split_ignorespec (this_ignoreval, &ptr))
593 #endif
594 {
595 if (numitems + 1 >= maxitems)
596 {
597 maxitems += 10;
598 ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign));
599 }
600 ivp->ignores[numitems].val = colon_bit;
601 ivp->ignores[numitems].len = strlen (colon_bit);
602 ivp->ignores[numitems].flags = 0;
603 if (ivp->item_func)
604 (*ivp->item_func) (&ivp->ignores[numitems]);
605 numitems++;
606 }
607 ivp->ignores[numitems].val = (char *)NULL;
608 ivp->num_ignores = numitems;
609 }