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