3c02effc66943f2d53faeaa12a20828825ef40b9
[platform/upstream/bash.git] / pathexp.c
1 /* pathexp.c -- The shell interface to the globbing library. */
2
3 /* Copyright (C) 1995 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, 675 Mass Ave, Cambridge, MA 02139, 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 <glob/fnmatch.h>
37
38 #if defined (USE_POSIX_GLOB_LIBRARY)
39 #  include <glob.h>
40 #else
41 #  include <glob/glob.h>
42 #endif
43
44 /* Control whether * matches .files in globbing. */
45 int glob_dot_filenames;
46
47 /* Control whether the extended globbing features are enabled. */
48 int extended_glob = 0;
49
50 /* Return nonzero if STRING has any unquoted special globbing chars in it.  */
51 int
52 unquoted_glob_pattern_p (string)
53      register char *string;
54 {
55   register int c;
56   int open;
57
58   open = 0;
59   while (c = *string++)
60     {
61       switch (c)
62         {
63         case '?':
64         case '*':
65           return (1);
66
67         case '[':
68           open++;
69           continue;
70
71         case ']':
72           if (open)
73             return (1);
74           continue;
75
76         case '+':
77         case '@':
78         case '!':
79           if (*string == '(')   /*)*/
80             return (1);
81           continue;
82
83         case CTLESC:
84         case '\\':
85           if (*string++ == '\0')
86             return (0);
87         }
88     }
89   return (0);
90 }
91
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. */
102 char *
103 quote_string_for_globbing (pathname, qflags)
104      char *pathname;
105      int qflags;
106 {
107   char *temp;
108   register int i, j;
109
110   temp = xmalloc (strlen (pathname) + 1);
111
112   if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname))
113     {
114       temp[0] = '\0';
115       return temp;
116     }
117
118   for (i = j = 0; pathname[i]; i++)
119     {
120       if (pathname[i] == CTLESC)
121         {
122           if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/')
123             continue;
124           temp[j++] = '\\';
125         }
126       else
127         temp[j++] = pathname[i];
128     }
129   temp[j] = '\0';
130
131   return (temp);
132 }
133
134 char *
135 quote_globbing_chars (string)
136      char *string;
137 {
138   char *temp, *s, *t;
139
140   temp = xmalloc (strlen (string) * 2 + 1);
141   for (t = temp, s = string; *s; )
142     {
143       switch (*s)
144         {
145         case '*':
146         case '[':
147         case ']':
148         case '?':
149         case '\\':
150           *t++ = '\\';
151           break;
152         case '+':
153         case '@':
154         case '!':
155           if (s[1] == '(')      /*(*/
156             *t++ = '\\';
157           break;
158         }
159       *t++ = *s++;
160     }
161   *t = '\0';
162   return temp;
163 }
164
165 /* Call the glob library to do globbing on PATHNAME. */
166 char **
167 shell_glob_filename (pathname)
168      char *pathname;
169 {
170 #if defined (USE_POSIX_GLOB_LIBRARY)
171   register int i;
172   char *temp, **return_value;
173   glob_t filenames;
174   int glob_flags;
175
176   temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
177
178   filenames.gl_offs = 0;
179
180 #  if defined (GLOB_PERIOD)
181   glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
182 #  else
183   glob_flags = 0;
184 #  endif /* !GLOB_PERIOD */
185
186   glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
187
188   i = glob (temp, glob_flags, (Function *)NULL, &filenames);
189
190   free (temp);
191
192   if (i == GLOB_NOSPACE || i == GLOB_ABEND)
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;
198
199   return (filenames.gl_pathv);
200
201 #else /* !USE_POSIX_GLOB_LIBRARY */
202
203   char *temp, **results;
204
205   noglob_dot_filenames = glob_dot_filenames == 0;
206
207   temp = quote_string_for_globbing (pathname, QGLOB_FILENAME);
208
209   results = glob_filename (temp);
210   free (temp);
211
212   if (results && ((GLOB_FAILED (results)) == 0))
213     {
214       if (should_ignore_glob_matches ())
215         ignore_glob_matches (results);
216       if (results && results[0])
217         sort_char_array (results);
218       else
219         {
220           FREE (results);
221           results = (char **)&glob_error_return;
222         }
223     }
224
225   return (results);
226 #endif /* !USE_POSIX_GLOB_LIBRARY */
227 }
228
229 /* Stuff for GLOBIGNORE. */
230
231 static struct ignorevar globignore =
232 {
233   "GLOBIGNORE",
234   (struct ign *)0,
235   0,
236   (char *)0,
237   (Function *)0,
238 };
239
240 /* Set up to ignore some glob matches because the value of GLOBIGNORE
241    has changed.  If GLOBIGNORE is being unset, we also need to disable
242    the globbing of filenames beginning with a `.'. */
243 void
244 setup_glob_ignore (name)
245      char *name;
246 {
247   char *v;
248
249   v = get_string_value (name);
250   setup_ignore_patterns (&globignore);
251
252   if (globignore.num_ignores)
253     glob_dot_filenames = 1;
254   else if (v == 0)
255     glob_dot_filenames = 0;
256 }
257
258 int
259 should_ignore_glob_matches ()
260 {
261   return globignore.num_ignores;
262 }
263
264 /* Return 0 if NAME matches a pattern in the globignore.ignores list. */
265 static int
266 glob_name_is_acceptable (name)
267      char *name;
268 {
269   struct ign *p;
270   int flags;
271
272   /* . and .. are never matched */
273   if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
274     return (0);
275
276   flags = FNM_PATHNAME | FNMATCH_EXTFLAG;
277   for (p = globignore.ignores; p->val; p++)
278     {
279       if (fnmatch (p->val, name, flags) != FNM_NOMATCH)
280         return (0);
281     }
282   return (1);
283 }
284
285 /* Internal function to test whether filenames in NAMES should be
286    ignored.  NAME_FUNC is a pointer to a function to call with each
287    name.  It returns non-zero if the name is acceptable to the particular
288    ignore function which called _ignore_names; zero if the name should
289    be removed from NAMES. */
290
291 static void
292 ignore_globbed_names (names, name_func)
293      char **names;
294      Function *name_func;
295 {
296   char **newnames;
297   int n, i;
298
299   for (i = 0; names[i]; i++)
300     ;
301   newnames = (char **)xmalloc ((i + 1) * sizeof (char *));
302
303   for (n = i = 0; names[i]; i++)
304     {
305       if ((*name_func) (names[i]))
306         newnames[n++] = names[i];
307       else
308         free (names[i]);
309     }
310
311   newnames[n] = (char *)NULL;
312
313   if (n == 0)
314     {
315       names[0] = (char *)NULL;
316       free (newnames);
317       return;
318     }
319
320   /* Copy the acceptable names from NEWNAMES back to NAMES and set the
321      new array end. */
322   for (n = 0; newnames[n]; n++)
323     names[n] = newnames[n];
324   names[n] = (char *)NULL;
325   free (newnames);
326 }
327
328 void
329 ignore_glob_matches (names)
330      char **names;
331 {
332   if (globignore.num_ignores == 0)
333     return;
334
335   ignore_globbed_names (names, glob_name_is_acceptable);
336 }
337
338 void
339 setup_ignore_patterns (ivp)
340      struct ignorevar *ivp;
341 {
342   int numitems, maxitems, ptr;
343   char *colon_bit, *this_ignoreval;
344   struct ign *p;
345
346   this_ignoreval = get_string_value (ivp->varname);
347
348   /* If nothing has changed then just exit now. */
349   if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) ||
350       (!this_ignoreval && !ivp->last_ignoreval))
351     return;
352
353   /* Oops.  The ignore variable has changed.  Re-parse it. */
354   ivp->num_ignores = 0;
355
356   if (ivp->ignores)
357     {
358       for (p = ivp->ignores; p->val; p++)
359         free(p->val);
360       free (ivp->ignores);
361       ivp->ignores = (struct ign *)NULL;
362     }
363
364   if (ivp->last_ignoreval)
365     {
366       free (ivp->last_ignoreval);
367       ivp->last_ignoreval = (char *)NULL;
368     }
369
370   if (this_ignoreval == 0 || *this_ignoreval == '\0')
371     return;
372
373   ivp->last_ignoreval = savestring (this_ignoreval);
374
375   numitems = maxitems = ptr = 0;
376
377   while (colon_bit = extract_colon_unit (this_ignoreval, &ptr))
378     {
379       if (numitems + 1 >= maxitems)
380         {
381           maxitems += 10;
382           ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign));
383         }
384       ivp->ignores[numitems].val = colon_bit;
385       ivp->ignores[numitems].len = strlen (colon_bit);
386       ivp->ignores[numitems].flags = 0;
387       if (ivp->item_func)
388         (*ivp->item_func) (&ivp->ignores[numitems]);
389       numitems++;
390     }
391   ivp->ignores[numitems].val = (char *)NULL;
392   ivp->num_ignores = numitems;
393 }