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