]>
git.ipfire.org Git - thirdparty/bash.git/blob - pathexp.c
1 /* pathexp.c -- The shell interface to the globbing library. */
3 /* Copyright (C) 1995 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)
36 #include <glob/fnmatch.h>
38 #if defined (USE_POSIX_GLOB_LIBRARY)
41 # include <glob/glob.h>
44 /* Control whether * matches .files in globbing. */
45 int glob_dot_filenames
;
47 /* Control whether the extended globbing features are enabled. */
48 int extended_glob
= 0;
50 /* Return nonzero if STRING has any unquoted special globbing chars in it. */
52 unquoted_glob_pattern_p (string
)
53 register char *string
;
79 if (*string
== '(') /*)*/
85 if (*string
++ == '\0')
92 /* PATHNAME can contain characters prefixed by CTLESC; this indicates
93 that the character is to be quoted. We quote it here in the style
94 that the glob library recognizes. If flags includes QGLOB_CVTNULL,
95 we change quoted null strings (pathname[0] == CTLNUL) into empty
96 strings (pathname[0] == 0). If this is called after quote removal
97 is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote
98 removal has not been done (for example, before attempting to match a
99 pattern while executing a case statement), flags should include
100 QGLOB_CVTNULL. If flags includes QGLOB_FILENAME, appropriate quoting
101 to match a filename should be performed. */
103 quote_string_for_globbing (pathname
, qflags
)
104 const char *pathname
;
110 temp
= xmalloc (strlen (pathname
) + 1);
112 if ((qflags
& QGLOB_CVTNULL
) && QUOTED_NULL (pathname
))
118 for (i
= j
= 0; pathname
[i
]; i
++)
120 if (pathname
[i
] == CTLESC
)
122 if ((qflags
& QGLOB_FILENAME
) && pathname
[i
+1] == '/')
127 temp
[j
++] = pathname
[i
];
135 quote_globbing_chars (string
)
140 temp
= xmalloc (strlen (string
) * 2 + 1);
141 for (t
= temp
, s
= string
; *s
; )
155 if (s
[1] == '(') /*(*/
165 /* Call the glob library to do globbing on PATHNAME. */
167 shell_glob_filename (pathname
)
168 const char *pathname
;
170 #if defined (USE_POSIX_GLOB_LIBRARY)
172 char *temp
, **results
;
176 temp
= quote_string_for_globbing (pathname
, QGLOB_FILENAME
);
178 filenames
.gl_offs
= 0;
180 # if defined (GLOB_PERIOD)
181 glob_flags
= glob_dot_filenames
? GLOB_PERIOD
: 0;
184 # endif /* !GLOB_PERIOD */
186 glob_flags
|= (GLOB_ERR
| GLOB_DOOFFS
);
188 i
= glob (temp
, glob_flags
, (Function
*)NULL
, &filenames
);
192 if (i
== GLOB_NOSPACE
|| i
== GLOB_ABORTED
)
193 return ((char **)NULL
);
194 else if (i
== GLOB_NOMATCH
)
195 filenames
.gl_pathv
= (char **)NULL
;
196 else if (i
!= 0) /* other error codes not in POSIX.2 */
197 filenames
.gl_pathv
= (char **)NULL
;
199 results
= filenames
.gl_pathv
;
201 if (results
&& ((GLOB_FAILED (results
)) == 0))
203 if (should_ignore_glob_matches ())
204 ignore_glob_matches (results
);
205 if (results
&& results
[0])
206 sort_char_array (results
);
210 results
= (char **)NULL
;
216 #else /* !USE_POSIX_GLOB_LIBRARY */
218 char *temp
, **results
;
220 noglob_dot_filenames
= glob_dot_filenames
== 0;
222 temp
= quote_string_for_globbing (pathname
, QGLOB_FILENAME
);
224 results
= glob_filename (temp
);
227 if (results
&& ((GLOB_FAILED (results
)) == 0))
229 if (should_ignore_glob_matches ())
230 ignore_glob_matches (results
);
231 if (results
&& results
[0])
232 sort_char_array (results
);
236 results
= (char **)&glob_error_return
;
241 #endif /* !USE_POSIX_GLOB_LIBRARY */
244 /* Stuff for GLOBIGNORE. */
246 static struct ignorevar globignore
=
255 /* Set up to ignore some glob matches because the value of GLOBIGNORE
256 has changed. If GLOBIGNORE is being unset, we also need to disable
257 the globbing of filenames beginning with a `.'. */
259 setup_glob_ignore (name
)
264 v
= get_string_value (name
);
265 setup_ignore_patterns (&globignore
);
267 if (globignore
.num_ignores
)
268 glob_dot_filenames
= 1;
270 glob_dot_filenames
= 0;
274 should_ignore_glob_matches ()
276 return globignore
.num_ignores
;
279 /* Return 0 if NAME matches a pattern in the globignore.ignores list. */
281 glob_name_is_acceptable (name
)
287 /* . and .. are never matched */
288 if (name
[0] == '.' && (name
[1] == '\0' || (name
[1] == '.' && name
[2] == '\0')))
291 flags
= FNM_PATHNAME
| FNMATCH_EXTFLAG
;
292 for (p
= globignore
.ignores
; p
->val
; p
++)
294 if (fnmatch (p
->val
, name
, flags
) != FNM_NOMATCH
)
300 /* Internal function to test whether filenames in NAMES should be
301 ignored. NAME_FUNC is a pointer to a function to call with each
302 name. It returns non-zero if the name is acceptable to the particular
303 ignore function which called _ignore_names; zero if the name should
304 be removed from NAMES. */
307 ignore_globbed_names (names
, name_func
)
314 for (i
= 0; names
[i
]; i
++)
316 newnames
= alloc_array (i
+ 1);
318 for (n
= i
= 0; names
[i
]; i
++)
320 if ((*name_func
) (names
[i
]))
321 newnames
[n
++] = names
[i
];
326 newnames
[n
] = (char *)NULL
;
330 names
[0] = (char *)NULL
;
335 /* Copy the acceptable names from NEWNAMES back to NAMES and set the
337 for (n
= 0; newnames
[n
]; n
++)
338 names
[n
] = newnames
[n
];
339 names
[n
] = (char *)NULL
;
344 ignore_glob_matches (names
)
347 if (globignore
.num_ignores
== 0)
350 ignore_globbed_names (names
, glob_name_is_acceptable
);
354 setup_ignore_patterns (ivp
)
355 struct ignorevar
*ivp
;
357 int numitems
, maxitems
, ptr
;
358 char *colon_bit
, *this_ignoreval
;
361 this_ignoreval
= get_string_value (ivp
->varname
);
363 /* If nothing has changed then just exit now. */
364 if ((this_ignoreval
&& ivp
->last_ignoreval
&& STREQ (this_ignoreval
, ivp
->last_ignoreval
)) ||
365 (!this_ignoreval
&& !ivp
->last_ignoreval
))
368 /* Oops. The ignore variable has changed. Re-parse it. */
369 ivp
->num_ignores
= 0;
373 for (p
= ivp
->ignores
; p
->val
; p
++)
376 ivp
->ignores
= (struct ign
*)NULL
;
379 if (ivp
->last_ignoreval
)
381 free (ivp
->last_ignoreval
);
382 ivp
->last_ignoreval
= (char *)NULL
;
385 if (this_ignoreval
== 0 || *this_ignoreval
== '\0')
388 ivp
->last_ignoreval
= savestring (this_ignoreval
);
390 numitems
= maxitems
= ptr
= 0;
392 while (colon_bit
= extract_colon_unit (this_ignoreval
, &ptr
))
394 if (numitems
+ 1 >= maxitems
)
397 ivp
->ignores
= (struct ign
*)xrealloc (ivp
->ignores
, maxitems
* sizeof (struct ign
));
399 ivp
->ignores
[numitems
].val
= colon_bit
;
400 ivp
->ignores
[numitems
].len
= strlen (colon_bit
);
401 ivp
->ignores
[numitems
].flags
= 0;
403 (*ivp
->item_func
) (&ivp
->ignores
[numitems
]);
406 ivp
->ignores
[numitems
].val
= (char *)NULL
;
407 ivp
->num_ignores
= numitems
;