]>
git.ipfire.org Git - thirdparty/bash.git/blob - pathexp.c
a498672f51ec668c266fb581a0a637b726b913c2
1 /* pathexp.c -- The shell interface to the globbing library. */
3 /* Copyright (C) 1995-2002 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 it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 #include "bashtypes.h"
26 #if defined (HAVE_UNISTD_H)
38 #include <glob/strmatch.h>
40 static int glob_name_is_acceptable
__P((const char *));
41 static void ignore_globbed_names
__P((char **, sh_ignore_func_t
*));
43 #if defined (USE_POSIX_GLOB_LIBRARY)
45 typedef int posix_glob_errfunc_t
__P((const char *, int));
47 # include <glob/glob.h>
50 /* Control whether * matches .files in globbing. */
51 int glob_dot_filenames
;
53 /* Control whether the extended globbing features are enabled. */
54 int extended_glob
= 0;
56 /* Return nonzero if STRING has any unquoted special globbing chars in it. */
58 unquoted_glob_pattern_p (string
)
59 register char *string
;
68 send
= string
+ strlen (string
);
90 if (*string
== '(') /*)*/
96 if (*string
++ == '\0')
100 /* Advance one fewer byte than an entire multibyte character to
101 account for the auto-increment in the loop above. */
102 #ifdef HANDLE_MULTIBYTE
104 ADVANCE_CHAR_P (string
, send
- string
);
107 ADVANCE_CHAR_P (string
, send
- string
);
113 /* PATHNAME can contain characters prefixed by CTLESC; this indicates
114 that the character is to be quoted. We quote it here in the style
115 that the glob library recognizes. If flags includes QGLOB_CVTNULL,
116 we change quoted null strings (pathname[0] == CTLNUL) into empty
117 strings (pathname[0] == 0). If this is called after quote removal
118 is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote
119 removal has not been done (for example, before attempting to match a
120 pattern while executing a case statement), flags should include
121 QGLOB_CVTNULL. If flags includes QGLOB_FILENAME, appropriate quoting
122 to match a filename should be performed. */
124 quote_string_for_globbing (pathname
, qflags
)
125 const char *pathname
;
131 temp
= (char *)xmalloc (strlen (pathname
) + 1);
133 if ((qflags
& QGLOB_CVTNULL
) && QUOTED_NULL (pathname
))
139 for (i
= j
= 0; pathname
[i
]; i
++)
141 if (pathname
[i
] == CTLESC
)
143 if ((qflags
& QGLOB_FILENAME
) && pathname
[i
+1] == '/')
147 if (pathname
[i
] == '\0')
150 temp
[j
++] = pathname
[i
];
158 quote_globbing_chars (string
)
162 char *temp
, *s
, *t
, *send
;
165 slen
= strlen (string
);
166 send
= string
+ slen
;
168 temp
= (char *)xmalloc (slen
* 2 + 1);
169 for (t
= temp
, s
= string
; *s
; )
183 if (s
[1] == '(') /*(*/
188 /* Copy a single (possibly multibyte) character from s to t,
189 incrementing both. */
190 COPY_CHAR_P (t
, s
, send
);
196 /* Call the glob library to do globbing on PATHNAME. */
198 shell_glob_filename (pathname
)
199 const char *pathname
;
201 #if defined (USE_POSIX_GLOB_LIBRARY)
203 char *temp
, **results
;
207 temp
= quote_string_for_globbing (pathname
, QGLOB_FILENAME
);
209 filenames
.gl_offs
= 0;
211 # if defined (GLOB_PERIOD)
212 glob_flags
= glob_dot_filenames
? GLOB_PERIOD
: 0;
215 # endif /* !GLOB_PERIOD */
217 glob_flags
|= (GLOB_ERR
| GLOB_DOOFFS
);
219 i
= glob (temp
, glob_flags
, (posix_glob_errfunc_t
*)NULL
, &filenames
);
223 if (i
== GLOB_NOSPACE
|| i
== GLOB_ABORTED
)
224 return ((char **)NULL
);
225 else if (i
== GLOB_NOMATCH
)
226 filenames
.gl_pathv
= (char **)NULL
;
227 else if (i
!= 0) /* other error codes not in POSIX.2 */
228 filenames
.gl_pathv
= (char **)NULL
;
230 results
= filenames
.gl_pathv
;
232 if (results
&& ((GLOB_FAILED (results
)) == 0))
234 if (should_ignore_glob_matches ())
235 ignore_glob_matches (results
);
236 if (results
&& results
[0])
237 strvec_sort (results
);
241 results
= (char **)NULL
;
247 #else /* !USE_POSIX_GLOB_LIBRARY */
249 char *temp
, **results
;
251 noglob_dot_filenames
= glob_dot_filenames
== 0;
253 temp
= quote_string_for_globbing (pathname
, QGLOB_FILENAME
);
254 results
= glob_filename (temp
, 0);
257 if (results
&& ((GLOB_FAILED (results
)) == 0))
259 if (should_ignore_glob_matches ())
260 ignore_glob_matches (results
);
261 if (results
&& results
[0])
262 strvec_sort (results
);
266 results
= (char **)&glob_error_return
;
271 #endif /* !USE_POSIX_GLOB_LIBRARY */
274 /* Stuff for GLOBIGNORE. */
276 static struct ignorevar globignore
=
282 (sh_iv_item_func_t
*)0,
285 /* Set up to ignore some glob matches because the value of GLOBIGNORE
286 has changed. If GLOBIGNORE is being unset, we also need to disable
287 the globbing of filenames beginning with a `.'. */
289 setup_glob_ignore (name
)
294 v
= get_string_value (name
);
295 setup_ignore_patterns (&globignore
);
297 if (globignore
.num_ignores
)
298 glob_dot_filenames
= 1;
300 glob_dot_filenames
= 0;
304 should_ignore_glob_matches ()
306 return globignore
.num_ignores
;
309 /* Return 0 if NAME matches a pattern in the globignore.ignores list. */
311 glob_name_is_acceptable (name
)
317 /* . and .. are never matched */
318 if (name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
321 flags
= FNM_PATHNAME
| FNMATCH_EXTFLAG
;
322 for (p
= globignore
.ignores
; p
->val
; p
++)
324 if (strmatch (p
->val
, (char *)name
, flags
) != FNM_NOMATCH
)
330 /* Internal function to test whether filenames in NAMES should be
331 ignored. NAME_FUNC is a pointer to a function to call with each
332 name. It returns non-zero if the name is acceptable to the particular
333 ignore function which called _ignore_names; zero if the name should
334 be removed from NAMES. */
337 ignore_globbed_names (names
, name_func
)
339 sh_ignore_func_t
*name_func
;
344 for (i
= 0; names
[i
]; i
++)
346 newnames
= strvec_create (i
+ 1);
348 for (n
= i
= 0; names
[i
]; i
++)
350 if ((*name_func
) (names
[i
]))
351 newnames
[n
++] = names
[i
];
356 newnames
[n
] = (char *)NULL
;
360 names
[0] = (char *)NULL
;
365 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
367 for (n
= 0; newnames
[n
]; n
++)
368 names
[n
] = newnames
[n
];
369 names
[n
] = (char *)NULL
;
374 ignore_glob_matches (names
)
377 if (globignore
.num_ignores
== 0)
380 ignore_globbed_names (names
, glob_name_is_acceptable
);
384 setup_ignore_patterns (ivp
)
385 struct ignorevar
*ivp
;
387 int numitems
, maxitems
, ptr
;
388 char *colon_bit
, *this_ignoreval
;
391 this_ignoreval
= get_string_value (ivp
->varname
);
393 /* If nothing has changed then just exit now. */
394 if ((this_ignoreval
&& ivp
->last_ignoreval
&& STREQ (this_ignoreval
, ivp
->last_ignoreval
)) ||
395 (!this_ignoreval
&& !ivp
->last_ignoreval
))
398 /* Oops. The ignore variable has changed. Re-parse it. */
399 ivp
->num_ignores
= 0;
403 for (p
= ivp
->ignores
; p
->val
; p
++)
406 ivp
->ignores
= (struct ign
*)NULL
;
409 if (ivp
->last_ignoreval
)
411 free (ivp
->last_ignoreval
);
412 ivp
->last_ignoreval
= (char *)NULL
;
415 if (this_ignoreval
== 0 || *this_ignoreval
== '\0')
418 ivp
->last_ignoreval
= savestring (this_ignoreval
);
420 numitems
= maxitems
= ptr
= 0;
422 while (colon_bit
= extract_colon_unit (this_ignoreval
, &ptr
))
424 if (numitems
+ 1 >= maxitems
)
427 ivp
->ignores
= (struct ign
*)xrealloc (ivp
->ignores
, maxitems
* sizeof (struct ign
));
429 ivp
->ignores
[numitems
].val
= colon_bit
;
430 ivp
->ignores
[numitems
].len
= strlen (colon_bit
);
431 ivp
->ignores
[numitems
].flags
= 0;
433 (*ivp
->item_func
) (&ivp
->ignores
[numitems
]);
436 ivp
->ignores
[numitems
].val
= (char *)NULL
;
437 ivp
->num_ignores
= numitems
;