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