]>
git.ipfire.org Git - thirdparty/bash.git/blob - pathexp.c
1 /* pathexp.c -- The shell interface to the globbing library. */
3 /* Copyright (C) 1995-2014 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
*));
43 static char *split_ignorespec
__P((char *, int *));
45 #if defined (USE_POSIX_GLOB_LIBRARY)
47 typedef int posix_glob_errfunc_t
__P((const char *, int));
49 # include <glob/glob.h>
52 /* Control whether * matches .files in globbing. */
53 int glob_dot_filenames
;
55 /* Control whether the extended globbing features are enabled. */
56 int extended_glob
= EXTGLOB_DEFAULT
;
58 /* Control enabling special handling of `**' */
61 /* Return nonzero if STRING has any unquoted special globbing chars in it. */
63 unquoted_glob_pattern_p (string
)
64 register char *string
;
73 send
= string
+ strlen (string
);
95 if (*string
== '(') /*)*/
101 if (*string
++ == '\0')
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
109 ADVANCE_CHAR_P (string
, send
- string
);
112 ADVANCE_CHAR_P (string
, send
- string
);
118 /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
119 be quoted to match itself. */
160 if (s
[1] == '(') /*(*/
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. */
180 quote_string_for_globbing (pathname
, qflags
)
181 const char *pathname
;
186 int brack
, cclass
, collsym
, equiv
, c
, last_was_backslash
;
189 temp
= (char *)xmalloc (2 * strlen (pathname
) + 1);
191 if ((qflags
& QGLOB_CVTNULL
) && QUOTED_NULL (pathname
))
197 brack
= cclass
= collsym
= equiv
= last_was_backslash
= 0;
198 for (i
= j
= 0; pathname
[i
]; i
++)
200 /* Fix for CTLESC at the end of the string? */
201 if (pathname
[i
] == CTLESC
&& pathname
[i
+1] == '\0')
203 temp
[j
++] = pathname
[i
++];
206 /* If we are parsing regexp, turn CTLESC CTLESC into CTLESC. It's not an
207 ERE special character, so we should just be able to pass it through. */
208 else if ((qflags
& QGLOB_REGEXP
) && pathname
[i
] == CTLESC
&& pathname
[i
+1] == CTLESC
)
211 temp
[j
++] = pathname
[i
];
214 else if (pathname
[i
] == CTLESC
)
216 if ((qflags
& QGLOB_FILENAME
) && pathname
[i
+1] == '/')
218 /* What to do if preceding char is backslash? */
219 if (pathname
[i
+1] != CTLESC
&& (qflags
& QGLOB_REGEXP
) && ere_char (pathname
[i
+1]) == 0)
223 if (pathname
[i
] == '\0')
226 else if ((qflags
& QGLOB_REGEXP
) && (i
== 0 || pathname
[i
-1] != CTLESC
) && pathname
[i
] == '[') /*]*/
229 temp
[j
++] = pathname
[i
++]; /* open bracket */
232 c
= pathname
[i
++]; /* c == char after open bracket */
237 else if (c
== CTLESC
)
239 /* skip c, check for EOS, let assignment at end of loop */
240 /* pathname[i] == backslash-escaped character */
241 if (pathname
[i
] == 0)
243 temp
[j
++] = pathname
[i
++];
245 else if (c
== '[' && pathname
[i
] == ':')
248 temp
[j
++] = pathname
[i
++];
251 else if (cclass
&& c
== ':' && pathname
[i
] == ']')
254 temp
[j
++] = pathname
[i
++];
257 else if (c
== '[' && pathname
[i
] == '=')
260 temp
[j
++] = pathname
[i
++];
261 if (pathname
[i
] == ']')
262 temp
[j
++] = pathname
[i
++]; /* right brack can be in equiv */
265 else if (equiv
&& c
== '=' && pathname
[i
] == ']')
268 temp
[j
++] = pathname
[i
++];
271 else if (c
== '[' && pathname
[i
] == '.')
274 temp
[j
++] = pathname
[i
++];
275 if (pathname
[i
] == ']')
276 temp
[j
++] = pathname
[i
++]; /* right brack can be in collsym */
279 else if (collsym
&& c
== '.' && pathname
[i
] == ']')
282 temp
[j
++] = pathname
[i
++];
288 while (((c
= pathname
[i
++]) != ']') && c
!= 0);
290 /* If we don't find the closing bracket before we hit the end of
291 the string, rescan string without treating it as a bracket
292 expression (has implications for backslash and special ERE
296 i
= savei
- 1; /* -1 for autoincrement above */
301 temp
[j
++] = c
; /* closing right bracket */
302 i
--; /* increment will happen above in loop */
303 continue; /* skip double assignment below */
305 else if (pathname
[i
] == '\\' && (qflags
& QGLOB_REGEXP
) == 0)
307 /* XXX - if not quoting regexp, use backslash as quote char. Should
308 we just pass it through without treating it as special? That is
309 what ksh93 seems to do. */
311 /* If we want to pass through backslash unaltered, comment out these
316 if (pathname
[i
] == '\0')
319 else if (pathname
[i
] == '\\' && (qflags
& QGLOB_REGEXP
))
320 last_was_backslash
= 1;
321 temp
[j
++] = pathname
[i
];
330 quote_globbing_chars (string
)
335 const char *s
, *send
;
338 slen
= strlen (string
);
339 send
= string
+ slen
;
341 temp
= (char *)xmalloc (slen
* 2 + 1);
342 for (t
= temp
, s
= string
; *s
; )
347 /* Copy a single (possibly multibyte) character from s to t,
348 incrementing both. */
349 COPY_CHAR_P (t
, s
, send
);
355 /* Call the glob library to do globbing on PATHNAME. */
357 shell_glob_filename (pathname
)
358 const char *pathname
;
360 #if defined (USE_POSIX_GLOB_LIBRARY)
362 char *temp
, **results
;
366 temp
= quote_string_for_globbing (pathname
, QGLOB_FILENAME
);
368 filenames
.gl_offs
= 0;
370 # if defined (GLOB_PERIOD)
371 glob_flags
= glob_dot_filenames
? GLOB_PERIOD
: 0;
374 # endif /* !GLOB_PERIOD */
376 glob_flags
|= (GLOB_ERR
| GLOB_DOOFFS
);
378 i
= glob (temp
, glob_flags
, (posix_glob_errfunc_t
*)NULL
, &filenames
);
382 if (i
== GLOB_NOSPACE
|| i
== GLOB_ABORTED
)
383 return ((char **)NULL
);
384 else if (i
== GLOB_NOMATCH
)
385 filenames
.gl_pathv
= (char **)NULL
;
386 else if (i
!= 0) /* other error codes not in POSIX.2 */
387 filenames
.gl_pathv
= (char **)NULL
;
389 results
= filenames
.gl_pathv
;
391 if (results
&& ((GLOB_FAILED (results
)) == 0))
393 if (should_ignore_glob_matches ())
394 ignore_glob_matches (results
);
395 if (results
&& results
[0])
396 strvec_sort (results
);
400 results
= (char **)NULL
;
406 #else /* !USE_POSIX_GLOB_LIBRARY */
408 char *temp
, **results
;
410 noglob_dot_filenames
= glob_dot_filenames
== 0;
412 temp
= quote_string_for_globbing (pathname
, QGLOB_FILENAME
);
413 results
= glob_filename (temp
, glob_star
? GX_GLOBSTAR
: 0);
416 if (results
&& ((GLOB_FAILED (results
)) == 0))
418 if (should_ignore_glob_matches ())
419 ignore_glob_matches (results
);
420 if (results
&& results
[0])
421 strvec_sort (results
);
425 results
= (char **)&glob_error_return
;
430 #endif /* !USE_POSIX_GLOB_LIBRARY */
433 /* Stuff for GLOBIGNORE. */
435 static struct ignorevar globignore
=
441 (sh_iv_item_func_t
*)0,
444 /* Set up to ignore some glob matches because the value of GLOBIGNORE
445 has changed. If GLOBIGNORE is being unset, we also need to disable
446 the globbing of filenames beginning with a `.'. */
448 setup_glob_ignore (name
)
453 v
= get_string_value (name
);
454 setup_ignore_patterns (&globignore
);
456 if (globignore
.num_ignores
)
457 glob_dot_filenames
= 1;
459 glob_dot_filenames
= 0;
463 should_ignore_glob_matches ()
465 return globignore
.num_ignores
;
468 /* Return 0 if NAME matches a pattern in the globignore.ignores list. */
470 glob_name_is_acceptable (name
)
476 /* . and .. are never matched */
477 if (name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
480 flags
= FNM_PATHNAME
| FNMATCH_EXTFLAG
| FNMATCH_NOCASEGLOB
;
481 for (p
= globignore
.ignores
; p
->val
; p
++)
483 if (strmatch (p
->val
, (char *)name
, flags
) != FNM_NOMATCH
)
489 /* Internal function to test whether filenames in NAMES should be
490 ignored. NAME_FUNC is a pointer to a function to call with each
491 name. It returns non-zero if the name is acceptable to the particular
492 ignore function which called _ignore_names; zero if the name should
493 be removed from NAMES. */
496 ignore_globbed_names (names
, name_func
)
498 sh_ignore_func_t
*name_func
;
503 for (i
= 0; names
[i
]; i
++)
505 newnames
= strvec_create (i
+ 1);
507 for (n
= i
= 0; names
[i
]; i
++)
509 if ((*name_func
) (names
[i
]))
510 newnames
[n
++] = names
[i
];
515 newnames
[n
] = (char *)NULL
;
519 names
[0] = (char *)NULL
;
524 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
526 for (n
= 0; newnames
[n
]; n
++)
527 names
[n
] = newnames
[n
];
528 names
[n
] = (char *)NULL
;
533 ignore_glob_matches (names
)
536 if (globignore
.num_ignores
== 0)
539 ignore_globbed_names (names
, glob_name_is_acceptable
);
543 split_ignorespec (s
, ip
)
557 n
= skip_to_delim (s
, i
, ":", SD_NOJMP
|SD_EXTGLOB
|SD_GLOB
);
558 t
= substring (s
, i
, n
);
567 setup_ignore_patterns (ivp
)
568 struct ignorevar
*ivp
;
570 int numitems
, maxitems
, ptr
;
571 char *colon_bit
, *this_ignoreval
;
574 this_ignoreval
= get_string_value (ivp
->varname
);
576 /* If nothing has changed then just exit now. */
577 if ((this_ignoreval
&& ivp
->last_ignoreval
&& STREQ (this_ignoreval
, ivp
->last_ignoreval
)) ||
578 (!this_ignoreval
&& !ivp
->last_ignoreval
))
581 /* Oops. The ignore variable has changed. Re-parse it. */
582 ivp
->num_ignores
= 0;
586 for (p
= ivp
->ignores
; p
->val
; p
++)
589 ivp
->ignores
= (struct ign
*)NULL
;
592 if (ivp
->last_ignoreval
)
594 free (ivp
->last_ignoreval
);
595 ivp
->last_ignoreval
= (char *)NULL
;
598 if (this_ignoreval
== 0 || *this_ignoreval
== '\0')
601 ivp
->last_ignoreval
= savestring (this_ignoreval
);
603 numitems
= maxitems
= ptr
= 0;
606 while (colon_bit
= extract_colon_unit (this_ignoreval
, &ptr
))
608 while (colon_bit
= split_ignorespec (this_ignoreval
, &ptr
))
611 if (numitems
+ 1 >= maxitems
)
614 ivp
->ignores
= (struct ign
*)xrealloc (ivp
->ignores
, maxitems
* sizeof (struct ign
));
616 ivp
->ignores
[numitems
].val
= colon_bit
;
617 ivp
->ignores
[numitems
].len
= strlen (colon_bit
);
618 ivp
->ignores
[numitems
].flags
= 0;
620 (*ivp
->item_func
) (&ivp
->ignores
[numitems
]);
623 ivp
->ignores
[numitems
].val
= (char *)NULL
;
624 ivp
->num_ignores
= numitems
;