| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | /* pathexp.c -- The shell interface to the globbing library. */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | /* Copyright (C) 1995-2014 Free Software Foundation, Inc.
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |    This file is part of GNU Bash, the Bourne Again SHell. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    Bash is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |    it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |    the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  |    (at your option) any later version. | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    Bash is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |    GNU General Public License for more details. | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "config.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "bashtypes.h"
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (HAVE_UNISTD_H)
 | 
					
						
							|  |  |  | #  include <unistd.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "bashansi.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "shell.h"
 | 
					
						
							|  |  |  | #include "pathexp.h"
 | 
					
						
							|  |  |  | #include "flags.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | #include "shmbutil.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | #include "bashintl.h"
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #include <glob/strmatch.h>
 | 
					
						
							| 
									
										
										
										
											1999-02-19 17:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | static int glob_name_is_acceptable __P((const char *)); | 
					
						
							|  |  |  | static void ignore_globbed_names __P((char **, sh_ignore_func_t *)); | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | static char *split_ignorespec __P((char *, int *)); | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | 	        | 
					
						
							| 
									
										
										
										
											1999-02-19 17:11:39 +00:00
										 |  |  | #if defined (USE_POSIX_GLOB_LIBRARY)
 | 
					
						
							|  |  |  | #  include <glob.h>
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | typedef int posix_glob_errfunc_t __P((const char *, int)); | 
					
						
							| 
									
										
										
										
											1999-02-19 17:11:39 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | #  include <glob/glob.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Control whether * matches .files in globbing. */ | 
					
						
							|  |  |  | int glob_dot_filenames; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | /* Control whether the extended globbing features are enabled. */ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:51:19 -05:00
										 |  |  | int extended_glob = EXTGLOB_DEFAULT; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | /* Control enabling special handling of `**' */ | 
					
						
							|  |  |  | int glob_star = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | /* Return nonzero if STRING has any unquoted special globbing chars in it.  */ | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | unquoted_glob_pattern_p (string) | 
					
						
							|  |  |  |      register char *string; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   register int c; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   char *send; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   int open; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   DECLARE_MBSTATE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   open = 0; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   send = string + strlen (string); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   while (c = *string++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       switch (c) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case '?': | 
					
						
							|  |  |  | 	case '*': | 
					
						
							|  |  |  | 	  return (1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case '[': | 
					
						
							|  |  |  | 	  open++; | 
					
						
							|  |  |  | 	  continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ']': | 
					
						
							|  |  |  | 	  if (open) | 
					
						
							|  |  |  | 	    return (1); | 
					
						
							|  |  |  | 	  continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	case '+': | 
					
						
							|  |  |  | 	case '@': | 
					
						
							|  |  |  | 	case '!': | 
					
						
							|  |  |  | 	  if (*string == '(')	/*)*/ | 
					
						
							|  |  |  | 	    return (1); | 
					
						
							|  |  |  | 	  continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 	case CTLESC: | 
					
						
							|  |  |  | 	case '\\': | 
					
						
							|  |  |  | 	  if (*string++ == '\0') | 
					
						
							|  |  |  | 	    return (0); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       /* Advance one fewer byte than an entire multibyte character to
 | 
					
						
							|  |  |  | 	 account for the auto-increment in the loop above. */ | 
					
						
							|  |  |  | #ifdef HANDLE_MULTIBYTE
 | 
					
						
							|  |  |  |       string--; | 
					
						
							|  |  |  |       ADVANCE_CHAR_P (string, send - string); | 
					
						
							|  |  |  |       string++; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |       ADVANCE_CHAR_P (string, send - string); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   return (0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-18 13:15:12 +00:00
										 |  |  | /* Return 1 if C is a character that is `special' in a POSIX ERE and needs to
 | 
					
						
							|  |  |  |    be quoted to match itself. */ | 
					
						
							|  |  |  | static inline int | 
					
						
							|  |  |  | ere_char (c) | 
					
						
							|  |  |  |      int c; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (c) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case '.': | 
					
						
							|  |  |  |     case '[': | 
					
						
							|  |  |  |     case '\\': | 
					
						
							|  |  |  |     case '(': | 
					
						
							|  |  |  |     case ')': | 
					
						
							|  |  |  |     case '*': | 
					
						
							|  |  |  |     case '+': | 
					
						
							|  |  |  |     case '?': | 
					
						
							|  |  |  |     case '{': | 
					
						
							|  |  |  |     case '|': | 
					
						
							|  |  |  |     case '^': | 
					
						
							|  |  |  |     case '$': | 
					
						
							|  |  |  |       return 1; | 
					
						
							|  |  |  |     default:  | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return (0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | int | 
					
						
							|  |  |  | glob_char_p (s) | 
					
						
							|  |  |  |      const char *s; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (*s) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case '*': | 
					
						
							|  |  |  |     case '[': | 
					
						
							|  |  |  |     case ']': | 
					
						
							|  |  |  |     case '?': | 
					
						
							|  |  |  |     case '\\': | 
					
						
							|  |  |  |       return 1; | 
					
						
							|  |  |  |     case '+': | 
					
						
							|  |  |  |     case '@': | 
					
						
							|  |  |  |     case '!': | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |       if (s[1] == '(')	/*(*/ | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	return 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | /* PATHNAME can contain characters prefixed by CTLESC; this indicates
 | 
					
						
							|  |  |  |    that the character is to be quoted.  We quote it here in the style | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |    that the glob library recognizes.  If flags includes QGLOB_CVTNULL, | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |    we change quoted null strings (pathname[0] == CTLNUL) into empty | 
					
						
							|  |  |  |    strings (pathname[0] == 0).  If this is called after quote removal | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |    is performed, (flags & QGLOB_CVTNULL) should be 0; if called when quote | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |    removal has not been done (for example, before attempting to match a | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |    pattern while executing a case statement), flags should include | 
					
						
							|  |  |  |    QGLOB_CVTNULL.  If flags includes QGLOB_FILENAME, appropriate quoting | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |    to match a filename should be performed.  QGLOB_REGEXP means we're | 
					
						
							|  |  |  |    quoting for a Posix ERE (for [[ string =~ pat ]]) and that requires | 
					
						
							|  |  |  |    some special handling. */ | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | char * | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | quote_string_for_globbing (pathname, qflags) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |      const char *pathname; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |      int qflags; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   char *temp; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   register int i, j; | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |   int brack, cclass, collsym, equiv, c, last_was_backslash; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |   temp = (char *)xmalloc (2 * strlen (pathname) + 1); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   if ((qflags & QGLOB_CVTNULL) && QUOTED_NULL (pathname)) | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       temp[0] = '\0'; | 
					
						
							|  |  |  |       return temp; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |   brack = cclass = collsym = equiv = last_was_backslash = 0; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   for (i = j = 0; pathname[i]; i++) | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |       /* Fix for CTLESC at the end of the string? */ | 
					
						
							|  |  |  |       if (pathname[i] == CTLESC && pathname[i+1] == '\0') | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  temp[j++] = pathname[i++]; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       /* If we are parsing regexp, turn CTLESC CTLESC into CTLESC. It's not an
 | 
					
						
							|  |  |  | 	 ERE special character, so we should just be able to pass it through. */ | 
					
						
							|  |  |  |       else if ((qflags & QGLOB_REGEXP) && pathname[i] == CTLESC && pathname[i+1] == CTLESC) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  i++; | 
					
						
							|  |  |  | 	  temp[j++] = pathname[i]; | 
					
						
							|  |  |  | 	  continue; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       else if (pathname[i] == CTLESC) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 	  if ((qflags & QGLOB_FILENAME) && pathname[i+1] == '/') | 
					
						
							|  |  |  | 	    continue; | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | 	  /* What to do if preceding char is backslash? */ | 
					
						
							| 
									
										
										
										
											2011-11-22 20:02:46 -05:00
										 |  |  | 	  if (pathname[i+1] != CTLESC && (qflags & QGLOB_REGEXP) && ere_char (pathname[i+1]) == 0) | 
					
						
							| 
									
										
										
										
											2008-11-18 13:15:12 +00:00
										 |  |  | 	    continue; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	  temp[j++] = '\\'; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	  i++; | 
					
						
							|  |  |  | 	  if (pathname[i] == '\0') | 
					
						
							|  |  |  | 	    break; | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |       else if ((qflags & QGLOB_REGEXP) && (i == 0 || pathname[i-1] != CTLESC) && pathname[i] == '[')	/*]*/ | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  brack = 1; | 
					
						
							|  |  |  | 	  temp[j++] = pathname[i++];	/* open bracket */ | 
					
						
							|  |  |  | 	  c = pathname[i++];	/* c == char after open bracket */ | 
					
						
							|  |  |  | 	  do | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      if (c == 0) | 
					
						
							|  |  |  | 		goto endpat; | 
					
						
							|  |  |  | 	      else if (c == CTLESC) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  /* skip c, check for EOS, let assignment at end of loop */ | 
					
						
							|  |  |  | 		  /* pathname[i] == backslash-escaped character */ | 
					
						
							|  |  |  | 		  if (pathname[i] == 0) | 
					
						
							|  |  |  | 		    goto endpat; | 
					
						
							|  |  |  | 		  temp[j++] = pathname[i++]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	      else if (c == '[' && pathname[i] == ':') | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  temp[j++] = c; | 
					
						
							|  |  |  | 		  temp[j++] = pathname[i++]; | 
					
						
							|  |  |  | 		  cclass = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	      else if (cclass && c == ':' && pathname[i] == ']') | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  temp[j++] = c; | 
					
						
							|  |  |  | 		  temp[j++] = pathname[i++]; | 
					
						
							|  |  |  | 		  cclass = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	      else if (c == '[' && pathname[i] == '=') | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  temp[j++] = c; | 
					
						
							|  |  |  | 		  temp[j++] = pathname[i++]; | 
					
						
							|  |  |  | 		  if (pathname[i] == ']') | 
					
						
							|  |  |  | 		    temp[j++] = pathname[i++];		/* right brack can be in equiv */ | 
					
						
							|  |  |  | 		  equiv = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	      else if (equiv && c == '=' && pathname[i] == ']') | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  temp[j++] = c; | 
					
						
							|  |  |  | 		  temp[j++] = pathname[i++]; | 
					
						
							|  |  |  | 		  equiv = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	      else if (c == '[' && pathname[i] == '.') | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  temp[j++] = c; | 
					
						
							|  |  |  | 		  temp[j++] = pathname[i++]; | 
					
						
							|  |  |  | 		  if (pathname[i] == ']') | 
					
						
							|  |  |  | 		    temp[j++] = pathname[i++];		/* right brack can be in collsym */ | 
					
						
							|  |  |  | 		  collsym = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	      else if (collsym && c == '.' && pathname[i] == ']') | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  temp[j++] = c; | 
					
						
							|  |  |  | 		  temp[j++] = pathname[i++]; | 
					
						
							|  |  |  | 		  collsym = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	      else | 
					
						
							|  |  |  | 		temp[j++] = c; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	  while ((c = pathname[i++]) != ']'); | 
					
						
							|  |  |  | 	  temp[j++] = c;	/* closing right bracket */ | 
					
						
							|  |  |  | 	  i--;			/* increment will happen above in loop */ | 
					
						
							|  |  |  | 	  continue;		/* skip double assignment below */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       else if (pathname[i] == '\\' && (qflags & QGLOB_REGEXP) == 0) | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | 	  /* XXX - if not quoting regexp, use backslash as quote char. Should
 | 
					
						
							|  |  |  | 	     we just pass it through without treating it as special? That is | 
					
						
							|  |  |  | 	     what ksh93 seems to do. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  /* If we want to pass through backslash unaltered, comment out these
 | 
					
						
							|  |  |  | 	     lines. */ | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	  temp[j++] = '\\'; | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	  i++; | 
					
						
							|  |  |  | 	  if (pathname[i] == '\0') | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |       else if (pathname[i] == '\\' && (qflags & QGLOB_REGEXP)) | 
					
						
							|  |  |  |         last_was_backslash = 1; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |       temp[j++] = pathname[i]; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | endpat: | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   temp[j] = '\0'; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return (temp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | char * | 
					
						
							|  |  |  | quote_globbing_chars (string) | 
					
						
							|  |  |  |      char *string; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   size_t slen; | 
					
						
							|  |  |  |   char *temp, *s, *t, *send; | 
					
						
							|  |  |  |   DECLARE_MBSTATE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   slen = strlen (string); | 
					
						
							|  |  |  |   send = string + slen; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   temp = (char *)xmalloc (slen * 2 + 1); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   for (t = temp, s = string; *s; ) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |       if (glob_char_p (s)) | 
					
						
							|  |  |  | 	*t++ = '\\'; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       /* Copy a single (possibly multibyte) character from s to t,
 | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | 	 incrementing both. */ | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |       COPY_CHAR_P (t, s, send); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   *t = '\0'; | 
					
						
							|  |  |  |   return temp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Call the glob library to do globbing on PATHNAME. */ | 
					
						
							|  |  |  | char ** | 
					
						
							|  |  |  | shell_glob_filename (pathname) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |      const char *pathname; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  | #if defined (USE_POSIX_GLOB_LIBRARY)
 | 
					
						
							|  |  |  |   register int i; | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |   char *temp, **results; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   glob_t filenames; | 
					
						
							|  |  |  |   int glob_flags; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   temp = quote_string_for_globbing (pathname, QGLOB_FILENAME); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   filenames.gl_offs = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-02-19 17:11:39 +00:00
										 |  |  | #  if defined (GLOB_PERIOD)
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0; | 
					
						
							| 
									
										
										
										
											1999-02-19 17:11:39 +00:00
										 |  |  | #  else
 | 
					
						
							|  |  |  |   glob_flags = 0; | 
					
						
							|  |  |  | #  endif /* !GLOB_PERIOD */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   glob_flags |= (GLOB_ERR | GLOB_DOOFFS); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   i = glob (temp, glob_flags, (posix_glob_errfunc_t *)NULL, &filenames); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   free (temp); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |   if (i == GLOB_NOSPACE || i == GLOB_ABORTED) | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |     return ((char **)NULL); | 
					
						
							| 
									
										
										
										
											1999-02-19 17:11:39 +00:00
										 |  |  |   else if (i == GLOB_NOMATCH) | 
					
						
							|  |  |  |     filenames.gl_pathv = (char **)NULL; | 
					
						
							|  |  |  |   else if (i != 0)		/* other error codes not in POSIX.2 */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     filenames.gl_pathv = (char **)NULL; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |   results = filenames.gl_pathv; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (results && ((GLOB_FAILED (results)) == 0)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (should_ignore_glob_matches ()) | 
					
						
							|  |  |  | 	ignore_glob_matches (results); | 
					
						
							|  |  |  |       if (results && results[0]) | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	strvec_sort (results); | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  |       else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  FREE (results); | 
					
						
							|  |  |  | 	  results = (char **)NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return (results); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #else /* !USE_POSIX_GLOB_LIBRARY */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   char *temp, **results; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   noglob_dot_filenames = glob_dot_filenames == 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   temp = quote_string_for_globbing (pathname, QGLOB_FILENAME); | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |   results = glob_filename (temp, glob_star ? GX_GLOBSTAR : 0); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   free (temp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (results && ((GLOB_FAILED (results)) == 0)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (should_ignore_glob_matches ()) | 
					
						
							|  |  |  | 	ignore_glob_matches (results); | 
					
						
							|  |  |  |       if (results && results[0]) | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	strvec_sort (results); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  FREE (results); | 
					
						
							|  |  |  | 	  results = (char **)&glob_error_return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return (results); | 
					
						
							|  |  |  | #endif /* !USE_POSIX_GLOB_LIBRARY */
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Stuff for GLOBIGNORE. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ignorevar globignore = | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   "GLOBIGNORE", | 
					
						
							|  |  |  |   (struct ign *)0, | 
					
						
							|  |  |  |   0, | 
					
						
							|  |  |  |   (char *)0, | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   (sh_iv_item_func_t *)0, | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Set up to ignore some glob matches because the value of GLOBIGNORE
 | 
					
						
							|  |  |  |    has changed.  If GLOBIGNORE is being unset, we also need to disable | 
					
						
							|  |  |  |    the globbing of filenames beginning with a `.'. */ | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | setup_glob_ignore (name) | 
					
						
							|  |  |  |      char *name; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   char *v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   v = get_string_value (name); | 
					
						
							|  |  |  |   setup_ignore_patterns (&globignore); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (globignore.num_ignores) | 
					
						
							|  |  |  |     glob_dot_filenames = 1; | 
					
						
							|  |  |  |   else if (v == 0) | 
					
						
							|  |  |  |     glob_dot_filenames = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | should_ignore_glob_matches () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return globignore.num_ignores; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Return 0 if NAME matches a pattern in the globignore.ignores list. */ | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | glob_name_is_acceptable (name) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |      const char *name; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   struct ign *p; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   int flags; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* . and .. are never matched */ | 
					
						
							|  |  |  |   if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) | 
					
						
							|  |  |  |     return (0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   flags = FNM_PATHNAME | FNMATCH_EXTFLAG; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   for (p = globignore.ignores; p->val; p++) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       if (strmatch (p->val, (char *)name, flags) != FNM_NOMATCH) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	return (0); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   return (1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Internal function to test whether filenames in NAMES should be
 | 
					
						
							|  |  |  |    ignored.  NAME_FUNC is a pointer to a function to call with each | 
					
						
							|  |  |  |    name.  It returns non-zero if the name is acceptable to the particular | 
					
						
							|  |  |  |    ignore function which called _ignore_names; zero if the name should | 
					
						
							|  |  |  |    be removed from NAMES. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | ignore_globbed_names (names, name_func) | 
					
						
							|  |  |  |      char **names; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |      sh_ignore_func_t *name_func; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   char **newnames; | 
					
						
							|  |  |  |   int n, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; names[i]; i++) | 
					
						
							|  |  |  |     ; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   newnames = strvec_create (i + 1); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   for (n = i = 0; names[i]; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if ((*name_func) (names[i])) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	newnames[n++] = names[i]; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       else | 
					
						
							|  |  |  | 	free (names[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   newnames[n] = (char *)NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (n == 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       names[0] = (char *)NULL; | 
					
						
							|  |  |  |       free (newnames); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Copy the acceptable names from NEWNAMES back to NAMES and set the
 | 
					
						
							|  |  |  |      new array end. */ | 
					
						
							|  |  |  |   for (n = 0; newnames[n]; n++) | 
					
						
							|  |  |  |     names[n] = newnames[n]; | 
					
						
							|  |  |  |   names[n] = (char *)NULL; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |   free (newnames); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | ignore_glob_matches (names) | 
					
						
							|  |  |  |      char **names; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (globignore.num_ignores == 0) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ignore_globbed_names (names, glob_name_is_acceptable); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | static char * | 
					
						
							|  |  |  | split_ignorespec (s, ip) | 
					
						
							|  |  |  |      char *s; | 
					
						
							|  |  |  |      int *ip; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   char *t; | 
					
						
							|  |  |  |   int n, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (s == 0) | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   i = *ip; | 
					
						
							|  |  |  |   if (s[i] == 0) | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   n = skip_to_delim (s, i, ":", SD_NOJMP|SD_EXTGLOB); | 
					
						
							|  |  |  |   t = substring (s, i, n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (s[n] == ':') | 
					
						
							|  |  |  |     n++;   | 
					
						
							|  |  |  |   *ip = n;   | 
					
						
							|  |  |  |   return t; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | void | 
					
						
							|  |  |  | setup_ignore_patterns (ivp) | 
					
						
							|  |  |  |      struct ignorevar *ivp; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int numitems, maxitems, ptr; | 
					
						
							|  |  |  |   char *colon_bit, *this_ignoreval; | 
					
						
							|  |  |  |   struct ign *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   this_ignoreval = get_string_value (ivp->varname); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* If nothing has changed then just exit now. */ | 
					
						
							|  |  |  |   if ((this_ignoreval && ivp->last_ignoreval && STREQ (this_ignoreval, ivp->last_ignoreval)) || | 
					
						
							|  |  |  |       (!this_ignoreval && !ivp->last_ignoreval)) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Oops.  The ignore variable has changed.  Re-parse it. */ | 
					
						
							|  |  |  |   ivp->num_ignores = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ivp->ignores) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       for (p = ivp->ignores; p->val; p++) | 
					
						
							|  |  |  | 	free(p->val); | 
					
						
							|  |  |  |       free (ivp->ignores); | 
					
						
							|  |  |  |       ivp->ignores = (struct ign *)NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ivp->last_ignoreval) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       free (ivp->last_ignoreval); | 
					
						
							|  |  |  |       ivp->last_ignoreval = (char *)NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (this_ignoreval == 0 || *this_ignoreval == '\0') | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ivp->last_ignoreval = savestring (this_ignoreval); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   numitems = maxitems = ptr = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   while (colon_bit = extract_colon_unit (this_ignoreval, &ptr)) | 
					
						
							| 
									
										
										
										
											2011-11-22 19:11:26 -05:00
										 |  |  | #else
 | 
					
						
							|  |  |  |   while (colon_bit = split_ignorespec (this_ignoreval, &ptr)) | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       if (numitems + 1 >= maxitems) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  maxitems += 10; | 
					
						
							|  |  |  | 	  ivp->ignores = (struct ign *)xrealloc (ivp->ignores, maxitems * sizeof (struct ign)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       ivp->ignores[numitems].val = colon_bit; | 
					
						
							|  |  |  |       ivp->ignores[numitems].len = strlen (colon_bit); | 
					
						
							|  |  |  |       ivp->ignores[numitems].flags = 0; | 
					
						
							|  |  |  |       if (ivp->item_func) | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	(*ivp->item_func) (&ivp->ignores[numitems]); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       numitems++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   ivp->ignores[numitems].val = (char *)NULL; | 
					
						
							|  |  |  |   ivp->num_ignores = numitems; | 
					
						
							|  |  |  | } |