diff options
Diffstat (limited to 'lib/glob')
-rw-r--r-- | lib/glob/glob.c | 347 | ||||
-rw-r--r-- | lib/glob/glob.h | 2 | ||||
-rw-r--r-- | lib/glob/gmisc.c | 18 | ||||
-rw-r--r-- | lib/glob/sm_loop.c | 55 | ||||
-rw-r--r-- | lib/glob/smatch.c | 43 | ||||
-rw-r--r-- | lib/glob/xmbsrtowcs.c | 17 |
6 files changed, 407 insertions, 75 deletions
diff --git a/lib/glob/glob.c b/lib/glob/glob.c index ad9b9d9..f549436 100644 --- a/lib/glob/glob.c +++ b/lib/glob/glob.c @@ -48,6 +48,8 @@ #include "stdc.h" #include "memalloc.h" +#include <signal.h> + #include "shell.h" #include "glob.h" @@ -84,6 +86,8 @@ struct globval extern void throw_to_top_level __P((void)); extern int sh_eaccess __P((char *, int)); extern char *sh_makepath __P((const char *, const char *, int)); +extern int signal_is_pending __P((int)); +extern void run_pending_traps __P((void)); extern int extended_glob; @@ -112,9 +116,13 @@ static void wdequote_pathname __P((char *)); # define dequote_pathname udequote_pathname #endif static void dequote_pathname __P((char *)); -static int glob_testdir __P((char *)); +static int glob_testdir __P((char *, int)); static char **glob_dir_to_array __P((char *, char **, int)); +/* Make sure these names continue to agree with what's in smatch.c */ +extern char *glob_patscan __P((char *, char *, int)); +extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int)); + /* Compile `glob_loop.c' for single-byte characters. */ #define CHAR unsigned char #define INT int @@ -162,15 +170,67 @@ glob_pattern_p (pattern) #endif } +#if EXTENDED_GLOB +/* Return 1 if all subpatterns in the extended globbing pattern PAT indicate + that the name should be skipped. XXX - doesn't handle pattern negation, + not sure if it should */ +static int +extglob_skipname (pat, dname, flags) + char *pat, *dname; + int flags; +{ + char *pp, *pe, *t; + int n, r; + + pp = pat + 2; + pe = pp + strlen (pp) - 1; /*(*/ + if (*pe != ')') + return 0; + if ((t = strchr (pp, '|')) == 0) /* easy case first */ + { + *pe = '\0'; + r = skipname (pp, dname, flags); /*(*/ + *pe = ')'; + return r; + } + while (t = glob_patscan (pp, pe, '|')) + { + n = t[-1]; + t[-1] = '\0'; + r = skipname (pp, dname, flags); + t[-1] = n; + if (r == 0) /* if any pattern says not skip, we don't skip */ + return r; + pp = t; + } /*(*/ + + if (pp == pe) /* glob_patscan might find end of pattern */ + return r; + + *pe = '\0'; +# if defined (HANDLE_MULTIBYTE) + r = mbskipname (pp, dname, flags); /*(*/ +# else + r = skipname (pp, dname, flags); /*(*/ +# endif + *pe = ')'; + return r; +} +#endif + /* Return 1 if DNAME should be skipped according to PAT. Mostly concerned with matching leading `.'. */ - static int skipname (pat, dname, flags) char *pat; char *dname; int flags; { +#if EXTENDED_GLOB + if (extglob_pattern_p (pat)) /* XXX */ + return (extglob_skipname (pat, dname, flags)); +#endif + /* If a leading dot need not be explicitly matched, and the pattern doesn't start with a `.', don't match `.' or `..' */ if (noglob_dot_filenames == 0 && pat[0] != '.' && @@ -179,7 +239,7 @@ skipname (pat, dname, flags) (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0')))) return 1; - /* If a dot must be explicity matched, check to see if they do. */ + /* If a dot must be explicitly matched, check to see if they do. */ else if (noglob_dot_filenames && dname[0] == '.' && pat[0] != '.' && (pat[0] != '\\' || pat[1] != '.')) return 1; @@ -188,18 +248,91 @@ skipname (pat, dname, flags) } #if HANDLE_MULTIBYTE + +static int +wchkname (pat_wc, dn_wc) + wchar_t *pat_wc, *dn_wc; +{ + /* If a leading dot need not be explicitly matched, and the + pattern doesn't start with a `.', don't match `.' or `..' */ + if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' && + (pat_wc[0] != L'\\' || pat_wc[1] != L'.') && + (dn_wc[0] == L'.' && + (dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0')))) + return 1; + + /* If a leading dot must be explicitly matched, check to see if the + pattern and dirname both have one. */ + else if (noglob_dot_filenames && dn_wc[0] == L'.' && + pat_wc[0] != L'.' && + (pat_wc[0] != L'\\' || pat_wc[1] != L'.')) + return 1; + + return 0; +} + +static int +wextglob_skipname (pat, dname, flags) + wchar_t *pat, *dname; + int flags; +{ +#if EXTENDED_GLOB + wchar_t *pp, *pe, *t, n; + int r; + + pp = pat + 2; + pe = pp + wcslen (pp) - 1; /*(*/ + if (*pe != L')') + return 0; + if ((t = wcschr (pp, L'|')) == 0) + { + *pe = L'\0'; + r = wchkname (pp, dname); /*(*/ + *pe = L')'; + return r; + } + while (t = glob_patscan_wc (pp, pe, '|')) + { + n = t[-1]; + t[-1] = L'\0'; + r = wchkname (pp, dname); + t[-1] = n; + if (r == 0) + return 0; + pp = t; + } + + if (pp == pe) /* glob_patscan_wc might find end of pattern */ + return r; + + *pe = L'\0'; + r = wchkname (pp, dname); /*(*/ + *pe = L')'; + return r; +#else + return (wchkname (pat, dname)); +#endif +} + /* Return 1 if DNAME should be skipped according to PAT. Handles multibyte characters in PAT and DNAME. Mostly concerned with matching leading `.'. */ - static int mbskipname (pat, dname, flags) char *pat, *dname; int flags; { - int ret; + int ret, ext; wchar_t *pat_wc, *dn_wc; size_t pat_n, dn_n; + if (mbsmbchar (dname) == 0 && mbsmbchar (pat) == 0) + return (skipname (pat, dname, flags)); + + ext = 0; +#if EXTENDED_GLOB + ext = extglob_pattern_p (pat); +#endif + pat_wc = dn_wc = (wchar_t *)NULL; pat_n = xdupmbstowcs (&pat_wc, NULL, pat); @@ -208,22 +341,7 @@ mbskipname (pat, dname, flags) ret = 0; if (pat_n != (size_t)-1 && dn_n !=(size_t)-1) - { - /* If a leading dot need not be explicitly matched, and the - pattern doesn't start with a `.', don't match `.' or `..' */ - if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' && - (pat_wc[0] != L'\\' || pat_wc[1] != L'.') && - (dn_wc[0] == L'.' && - (dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0')))) - ret = 1; - - /* If a leading dot must be explicity matched, check to see if the - pattern and dirname both have one. */ - else if (noglob_dot_filenames && dn_wc[0] == L'.' && - pat_wc[0] != L'.' && - (pat_wc[0] != L'\\' || pat_wc[1] != L'.')) - ret = 1; - } + ret = ext ? wextglob_skipname (pat_wc, dn_wc, flags) : wchkname (pat_wc, dn_wc); else ret = skipname (pat, dname, flags); @@ -325,13 +443,20 @@ dequote_pathname (pathname) /* Return 0 if DIR is a directory, -1 otherwise. */ static int -glob_testdir (dir) +glob_testdir (dir, flags) char *dir; + int flags; { struct stat finfo; + int r; -/*itrace("glob_testdir: testing %s", dir);*/ - if (stat (dir, &finfo) < 0) +/*itrace("glob_testdir: testing %s" flags = %d, dir, flags);*/ +#if defined (HAVE_LSTAT) + r = (flags & GX_ALLDIRS) ? lstat (dir, &finfo) : stat (dir, &finfo); +#else + r = stat (dir, &finfo); +#endif + if (r < 0) return (-1); if (S_ISDIR (finfo.st_mode) == 0) @@ -407,7 +532,6 @@ finddirs (pat, sdir, flags, ep, np) return ret; } - /* Return a vector of names of files in directory DIR whose names match glob pattern PAT. @@ -456,7 +580,7 @@ glob_vector (pat, dir, flags) /* If PAT is empty, skip the loop, but return one (empty) filename. */ if (pat == 0 || *pat == '\0') { - if (glob_testdir (dir) < 0) + if (glob_testdir (dir, 0) < 0) return ((char **) &glob_error_return); nextlink = (struct globval *)alloca (sizeof (struct globval)); @@ -478,7 +602,7 @@ glob_vector (pat, dir, flags) skip = 1; } - patlen = strlen (pat); + patlen = (pat && *pat) ? strlen (pat) : 0; /* If the filename pattern (PAT) does not contain any globbing characters, we can dispense with reading the directory, and just see if there is @@ -489,14 +613,18 @@ glob_vector (pat, dir, flags) int dirlen; struct stat finfo; - if (glob_testdir (dir) < 0) + if (glob_testdir (dir, 0) < 0) return ((char **) &glob_error_return); dirlen = strlen (dir); nextname = (char *)malloc (dirlen + patlen + 2); npat = (char *)malloc (patlen + 1); if (nextname == 0 || npat == 0) - lose = 1; + { + FREE (nextname); + FREE (npat); + lose = 1; + } else { strcpy (npat, pat); @@ -518,7 +646,10 @@ glob_vector (pat, dir, flags) count = 1; } else - lose = 1; + { + free (npat); + lose = 1; + } } else { @@ -536,7 +667,7 @@ glob_vector (pat, dir, flags) is not robust (i.e., it opens non-directories successfully), test that DIR is a directory and punt if it's not. */ #if defined (OPENDIR_NOT_ROBUST) - if (glob_testdir (dir) < 0) + if (glob_testdir (dir, 0) < 0) return ((char **) &glob_error_return); #endif @@ -570,7 +701,12 @@ glob_vector (pat, dir, flags) lose = 1; break; } - + else if (signal_is_pending (SIGINT)) /* XXX - make SIGINT traps responsive */ + { + lose = 1; + break; + } + dp = readdir (d); if (dp == NULL) break; @@ -599,7 +735,7 @@ glob_vector (pat, dir, flags) if (flags & GX_NULLDIR) pflags |= MP_IGNDOT; subdir = sh_makepath (dir, dp->d_name, pflags); - isdir = glob_testdir (subdir); + isdir = glob_testdir (subdir, flags); if (isdir < 0 && (flags & GX_MATCHDIRS)) { free (subdir); @@ -635,6 +771,8 @@ glob_vector (pat, dir, flags) nextname = (char *) malloc (sdlen + 1); if (nextlink == 0 || nextname == 0) { + FREE (nextlink); + FREE (nextname); free (subdir); lose = 1; break; @@ -647,6 +785,8 @@ glob_vector (pat, dir, flags) ++count; continue; } + else if (flags & GX_MATCHDIRS) + free (subdir); convfn = fnx_fromfs (dp->d_name, D_NAMLEN (dp)); if (strmatch (pat, convfn, mflags) != FNM_NOMATCH) @@ -666,6 +806,8 @@ glob_vector (pat, dir, flags) nextname = (char *) malloc (D_NAMLEN (dp) + 1); if (nextlink == 0 || nextname == 0) { + FREE (nextlink); + FREE (nextname); lose = 1; break; } @@ -689,7 +831,11 @@ glob_vector (pat, dir, flags) nextname = (char *)malloc (sdlen + 1); nextlink = (struct globval *) malloc (sizeof (struct globval)); if (nextlink == 0 || nextname == 0) - lose = 1; + { + FREE (nextlink); + FREE (nextname); + lose = 1; + } else { nextlink->name = nextname; @@ -733,7 +879,7 @@ glob_vector (pat, dir, flags) FREE (tmplink); } - QUIT; + /* Don't call QUIT; here; let higher layers deal with it. */ return ((char **)NULL); } @@ -815,7 +961,13 @@ glob_dir_to_array (dir, array, flags) result[i] = (char *) malloc (l + strlen (array[i]) + 3); if (result[i] == NULL) - return (NULL); + { + int ind; + for (ind = 0; ind < i; ind++) + free (result[ind]); + free (result); + return (NULL); + } strcpy (result[i], dir); if (add_slash) @@ -893,19 +1045,70 @@ glob_filename (pathname, flags) /* If directory_name contains globbing characters, then we have to expand the previous levels. Just recurse. */ - if (glob_pattern_p (directory_name)) + if (directory_len > 0 && glob_pattern_p (directory_name)) { - char **directories; + char **directories, *d, *p; register unsigned int i; + int all_starstar, last_starstar; + all_starstar = last_starstar = 0; + d = directory_name; dflags = flags & ~GX_MARKDIRS; - if ((flags & GX_GLOBSTAR) && directory_name[0] == '*' && directory_name[1] == '*' && (directory_name[2] == '/' || directory_name[2] == '\0')) - dflags |= GX_ALLDIRS|GX_ADDCURDIR; + /* Collapse a sequence of ** patterns separated by one or more slashes + to a single ** terminated by a slash or NUL */ + if ((flags & GX_GLOBSTAR) && d[0] == '*' && d[1] == '*' && (d[2] == '/' || d[2] == '\0')) + { + p = d; + while (d[0] == '*' && d[1] == '*' && (d[2] == '/' || d[2] == '\0')) + { + p = d; + if (d[2]) + { + d += 3; + while (*d == '/') + d++; + if (*d == 0) + break; + } + } + if (*d == 0) + all_starstar = 1; + d = p; + dflags |= GX_ALLDIRS|GX_ADDCURDIR; + directory_len = strlen (d); + } + + /* If there is a non [star][star]/ component in directory_name, we + still need to collapse trailing sequences of [star][star]/ into + a single one and note that the directory name ends with [star][star], + so we can compensate if filename is [star][star] */ + if ((flags & GX_GLOBSTAR) && all_starstar == 0) + { + int dl, prev; + prev = dl = directory_len; + while (dl >= 4 && d[dl - 1] == '/' && + d[dl - 2] == '*' && + d[dl - 3] == '*' && + d[dl - 4] == '/') + prev = dl, dl -= 3; + if (dl != directory_len) + last_starstar = 1; + directory_len = prev; + } + + /* If the directory name ends in [star][star]/ but the filename is + [star][star], just remove the final [star][star] from the directory + so we don't have to scan everything twice. */ + if (last_starstar && directory_len > 4 && + filename[0] == '*' && filename[1] == '*' && filename[2] == 0) + { + directory_len -= 3; + } - if (directory_name[directory_len - 1] == '/') - directory_name[directory_len - 1] = '\0'; + if (d[directory_len - 1] == '/') + d[directory_len - 1] = '\0'; - directories = glob_filename (directory_name, dflags); + directories = glob_filename (d, dflags); if (free_dirname) { @@ -927,13 +1130,26 @@ glob_filename (pathname, flags) return ((char **) &glob_error_return); } + /* If we have something like [star][star]/[star][star], it's no use to + glob **, then do it again, and throw half the results away. */ + if (all_starstar && filename[0] == '*' && filename[1] == '*' && filename[2] == 0) + { + free ((char *) directories); + free (directory_name); + directory_name = NULL; + directory_len = 0; + goto only_filename; + } + /* We have successfully globbed the preceding directory name. For each name in DIRECTORIES, call glob_vector on it and FILENAME. Concatenate the results together. */ for (i = 0; directories[i] != NULL; ++i) { char **temp_results; + int shouldbreak; + shouldbreak = 0; /* XXX -- we've recursively scanned any directories resulting from a `**', so turn off the flag. We turn it on again below if filename is `**' */ @@ -964,8 +1180,39 @@ glob_filename (pathname, flags) /* If we're expanding **, we don't need to glue the directory name to the results; we've already done it in glob_vector */ - if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0') - array = temp_results; + if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && (filename[2] == '\0' || filename[2] == '/')) + { + /* When do we remove null elements from temp_results? And + how to avoid duplicate elements in the final result? */ + /* If (dflags & GX_NULLDIR) glob_filename potentially left a + NULL placeholder in the temp results just in case + glob_vector/glob_dir_to_array did something with it, but + if it didn't, and we're not supposed to be passing them + through for some reason ((flags & GX_NULLDIR) == 0) we + need to remove all the NULL elements from the beginning + of TEMP_RESULTS. */ + /* If we have a null directory name and ** as the filename, + we have just searched for everything from the current + directory on down. Break now (shouldbreak = 1) to avoid + duplicate entries in the final result. */ +#define NULL_PLACEHOLDER(x) ((x) && *(x) && **(x) == 0) + if ((dflags & GX_NULLDIR) && (flags & GX_NULLDIR) == 0 && + NULL_PLACEHOLDER (temp_results)) +#undef NULL_PLACEHOLDER + { + register int i, n; + for (n = 0; temp_results[n] && *temp_results[n] == 0; n++) + ; + i = n; + do + temp_results[i - n] = temp_results[i]; + while (temp_results[i++] != 0); + array = temp_results; + shouldbreak = 1; + } + else + array = temp_results; + } else array = glob_dir_to_array (directories[i], temp_results, flags); l = 0; @@ -986,6 +1233,11 @@ glob_filename (pathname, flags) /* Note that the elements of ARRAY are not freed. */ if (array != temp_results) free ((char *) array); + else if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0') + free (temp_results); /* expanding ** case above */ + + if (shouldbreak) + break; } } /* Free the directories. */ @@ -997,6 +1249,7 @@ glob_filename (pathname, flags) return (result); } +only_filename: /* If there is only a directory name, return it. */ if (*filename == '\0') { @@ -1055,10 +1308,13 @@ glob_filename (pathname, flags) { if (free_dirname) free (directory_name); + QUIT; /* XXX - shell */ + run_pending_traps (); return (temp_results); } result = glob_dir_to_array ((dflags & GX_ALLDIRS) ? "" : directory_name, temp_results, flags); + if (free_dirname) free (directory_name); return (result); @@ -1079,6 +1335,7 @@ glob_filename (pathname, flags) free (directory_name); QUIT; + run_pending_traps (); return (NULL); } diff --git a/lib/glob/glob.h b/lib/glob/glob.h index 993ed70..b946233 100644 --- a/lib/glob/glob.h +++ b/lib/glob/glob.h @@ -35,6 +35,8 @@ extern int glob_pattern_p __P((const char *)); extern char **glob_vector __P((char *, char *, int)); extern char **glob_filename __P((char *, int)); +extern int extglob_pattern_p __P((const char *)); + extern char *glob_error_return; extern int noglob_dot_filenames; extern int glob_ignore_case; diff --git a/lib/glob/gmisc.c b/lib/glob/gmisc.c index 683035a..17e4265 100644 --- a/lib/glob/gmisc.c +++ b/lib/glob/gmisc.c @@ -200,6 +200,24 @@ bad_bracket: } #endif +int +extglob_pattern_p (pat) + char *pat; +{ + switch (pat[0]) + { + case '*': + case '+': + case '!': + case '@': + return (pat[1] == LPAREN); + default: + return 0; + } + + return 0; +} + /* Return 1 of the first character of STRING could match the first character of pattern PAT. Used to avoid n2 calls to strmatch(). */ int diff --git a/lib/glob/sm_loop.c b/lib/glob/sm_loop.c index dfff06c..7e7f538 100644 --- a/lib/glob/sm_loop.c +++ b/lib/glob/sm_loop.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991-2006 Free Software Foundation, Inc. +/* Copyright (C) 1991-2011 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -22,7 +22,8 @@ static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, int)); static CHAR *PARSE_COLLSYM __P((CHAR *, INT *)); static CHAR *BRACKMATCH __P((CHAR *, U_CHAR, int)); static int EXTMATCH __P((INT, CHAR *, CHAR *, CHAR *, CHAR *, int)); -static CHAR *PATSCAN __P((CHAR *, CHAR *, INT)); + +/*static*/ CHAR *PATSCAN __P((CHAR *, CHAR *, INT)); int FCT (pattern, string, flags) @@ -144,8 +145,9 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe); if (EXTMATCH (c, newn, se, p, pe, flags) == 0) return (0); } - /* We didn't match. If we have a `?(...)', that's failure. */ - return FNM_NOMATCH; + /* We didn't match. If we have a `?(...)', we can match 0 + or 1 times. */ + return 0; } #endif else if (c == L('?')) @@ -191,6 +193,18 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe); if (p == pe && (c == L('?') || c == L('*'))) return (0); + /* If we've hit the end of the string and the rest of the pattern + is something that matches the empty string, we can succeed. */ +#if defined (EXTENDED_GLOB) + if (n == se && ((flags & FNM_EXTMATCH) && (c == L('!') || c == L('?')) && *p == L('('))) + { + --p; + if (EXTMATCH (c, n, se, p, pe, flags) == 0) + return (c == L('!') ? FNM_NOMATCH : 0); + return (c == L('!') ? 0 : FNM_NOMATCH); + } +#endif + /* General case, use recursion. */ { U_CHAR c1; @@ -290,7 +304,7 @@ BRACKMATCH (p, test, flags) { register CHAR cstart, cend, c; register int not; /* Nonzero if the sense of the character class is inverted. */ - int brcnt; + int brcnt, forcecoll; INT pc; CHAR *savep; @@ -311,6 +325,7 @@ BRACKMATCH (p, test, flags) /* Initialize cstart and cend in case `-' is the last character of the pattern. */ cstart = cend = c; + forcecoll = 0; /* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find the end of the equivalence class, move the pattern pointer past @@ -400,6 +415,7 @@ BRACKMATCH (p, test, flags) range. If it is, we set cstart to one greater than `test', so any comparisons later will fail. */ cstart = (pc == INVALID) ? test + 1 : pc; + forcecoll = 1; } if (!(flags & FNM_NOESCAPE) && c == L('\\')) @@ -443,6 +459,7 @@ BRACKMATCH (p, test, flags) range expression. If we get one, we set cend to one fewer than the test character to make sure the range test fails. */ cend = (pc == INVALID) ? test - 1 : pc; + forcecoll = 1; } cend = FOLD (cend); @@ -453,7 +470,7 @@ BRACKMATCH (p, test, flags) the expression shall be treated as invalid.'' Note that this applies to only the range expression; the rest of the bracket expression is still checked for matches. */ - if (RANGECMP (cstart, cend) > 0) + if (RANGECMP (cstart, cend, forcecoll) > 0) { if (c == L(']')) break; @@ -462,7 +479,7 @@ BRACKMATCH (p, test, flags) } } - if (RANGECMP (test, cstart) >= 0 && RANGECMP (test, cend) <= 0) + if (RANGECMP (test, cstart, forcecoll) >= 0 && RANGECMP (test, cend, forcecoll) <= 0) goto matched; if (c == L(']')) @@ -517,7 +534,7 @@ matched: because we're scanning a `patlist'. Otherwise, we scan until we see DELIM. In all cases, we never scan past END. The return value is the first character after the matching DELIM. */ -static CHAR * +/*static*/ CHAR * PATSCAN (string, end, delim) CHAR *string, *end; INT delim; @@ -530,6 +547,9 @@ PATSCAN (string, end, delim) cchar = 0; bfirst = NULL; + if (string == end) + return (NULL); + for (s = string; c = *s; s++) { if (s >= end) @@ -606,19 +626,32 @@ STRCOMPARE (p, pe, s, se) { int ret; CHAR c1, c2; + int l1, l2; + + l1 = pe - p; + l2 = se - s; + if (l1 != l2) + return (FNM_NOMATCH); /* unequal lengths, can't be identical */ + c1 = *pe; c2 = *se; - *pe = *se = '\0'; + if (c1 != 0) + *pe = '\0'; + if (c2 != 0) + *se = '\0'; + #if HAVE_MULTIBYTE || defined (HAVE_STRCOLL) ret = STRCOLL ((XCHAR *)p, (XCHAR *)s); #else ret = STRCMP ((XCHAR *)p, (XCHAR *)s); #endif - *pe = c1; - *se = c2; + if (c1 != 0) + *pe = c1; + if (c2 != 0) + *se = c2; return (ret == 0 ? ret : FNM_NOMATCH); } diff --git a/lib/glob/smatch.c b/lib/glob/smatch.c index 061142b..848610a 100644 --- a/lib/glob/smatch.c +++ b/lib/glob/smatch.c @@ -43,15 +43,25 @@ #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0) #define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0) +#ifndef GLOBASCII_DEFAULT +# define GLOBASCII_DEFAULT 0 +#endif + +int glob_asciirange = GLOBASCII_DEFAULT; + /* We use strcoll(3) for range comparisons in bracket expressions, even though it can have unwanted side effects in locales other than POSIX or US. For instance, in the de locale, [A-Z] matches - all characters. */ + all characters. If GLOB_ASCIIRANGE is non-zero, and we're not forcing + the use of strcoll (e.g., for explicit collating symbols), we use + straight ordering as if in the C locale. */ #if defined (HAVE_STRCOLL) /* Helper function for collating symbol equivalence. */ -static int rangecmp (c1, c2) +static int +rangecmp (c1, c2, forcecoll) int c1, c2; + int forcecoll; { static char s1[2] = { ' ', '\0' }; static char s2[2] = { ' ', '\0' }; @@ -64,6 +74,9 @@ static int rangecmp (c1, c2) if (c1 == c2) return (0); + if (forcecoll == 0 && glob_asciirange) + return (c1 - c2); + s1[0] = c1; s2[0] = c2; @@ -72,7 +85,7 @@ static int rangecmp (c1, c2) return (c1 - c2); } #else /* !HAVE_STRCOLL */ -# define rangecmp(c1, c2) ((int)(c1) - (int)(c2)) +# define rangecmp(c1, c2, f) ((int)(c1) - (int)(c2)) #endif /* !HAVE_STRCOLL */ #if defined (HAVE_STRCOLL) @@ -80,7 +93,7 @@ static int collequiv (c1, c2) int c1, c2; { - return (rangecmp (c1, c2) == 0); + return (rangecmp (c1, c2, 1) == 0); } #else # define collequiv(c1, c2) ((c1) == (c2)) @@ -214,14 +227,14 @@ is_cclass (c, name) #define COLLSYM collsym #define PARSE_COLLSYM parse_collsym #define BRACKMATCH brackmatch -#define PATSCAN patscan +#define PATSCAN glob_patscan #define STRCOMPARE strcompare #define EXTMATCH extmatch #define STRCHR(S, C) strchr((S), (C)) #define STRCOLL(S1, S2) strcoll((S1), (S2)) #define STRLEN(S) strlen(S) #define STRCMP(S1, S2) strcmp((S1), (S2)) -#define RANGECMP(C1, C2) rangecmp((C1), (C2)) +#define RANGECMP(C1, C2, F) rangecmp((C1), (C2), (F)) #define COLLEQUIV(C1, C2) collequiv((C1), (C2)) #define CTYPE_T enum char_class #define IS_CCLASS(C, S) is_cclass((C), (S)) @@ -244,8 +257,9 @@ is_cclass (c, name) extern char *mbsmbchar __P((const char *)); static int -rangecmp_wc (c1, c2) +rangecmp_wc (c1, c2, forcecoll) wint_t c1, c2; + int forcecoll; { static wchar_t s1[2] = { L' ', L'\0' }; static wchar_t s2[2] = { L' ', L'\0' }; @@ -253,6 +267,9 @@ rangecmp_wc (c1, c2) if (c1 == c2) return 0; + if (forcecoll == 0 && glob_asciirange && c1 <= UCHAR_MAX && c2 <= UCHAR_MAX) + return ((int)(c1 - c2)); + s1[0] = c1; s2[0] = c2; @@ -263,7 +280,7 @@ static int collequiv_wc (c, equiv) wint_t c, equiv; { - return (!(c - equiv)); + return (c == equiv); } /* Helper function for collating symbol. */ @@ -342,14 +359,14 @@ is_wcclass (wc, name) #define COLLSYM collwcsym #define PARSE_COLLSYM parse_collwcsym #define BRACKMATCH brackmatch_wc -#define PATSCAN patscan_wc +#define PATSCAN glob_patscan_wc #define STRCOMPARE wscompare #define EXTMATCH extmatch_wc #define STRCHR(S, C) wcschr((S), (C)) #define STRCOLL(S1, S2) wcscoll((S1), (S2)) #define STRLEN(S) wcslen(S) #define STRCMP(S1, S2) wcscmp((S1), (S2)) -#define RANGECMP(C1, C2) rangecmp_wc((C1), (C2)) +#define RANGECMP(C1, C2, F) rangecmp_wc((C1), (C2), (F)) #define COLLEQUIV(C1, C2) collequiv_wc((C1), (C2)) #define CTYPE_T enum char_class #define IS_CCLASS(C, S) is_wcclass((C), (S)) @@ -369,13 +386,7 @@ xstrmatch (pattern, string, flags) wchar_t *wpattern, *wstring; size_t plen, slen, mplen, mslen; -#if 0 - plen = strlen (pattern); - mplen = mbstrlen (pattern); - if (plen == mplen && strlen (string) == mbstrlen (string)) -#else if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0) -#endif return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags)); if (MB_CUR_MAX == 1) diff --git a/lib/glob/xmbsrtowcs.c b/lib/glob/xmbsrtowcs.c index c410e05..11a4d1b 100644 --- a/lib/glob/xmbsrtowcs.c +++ b/lib/glob/xmbsrtowcs.c @@ -1,6 +1,6 @@ /* xmbsrtowcs.c -- replacement function for mbsrtowcs */ -/* Copyright (C) 2002-2010 Free Software Foundation, Inc. +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -166,7 +166,7 @@ xdupmbstowcs2 (destp, src) do { end_or_backslash = strchrnul(p, '\\'); - nms = (end_or_backslash - p); + nms = end_or_backslash - p; if (*end_or_backslash == '\0') nms++; @@ -283,6 +283,8 @@ xdupmbstowcs (destp, indicesp, src) { if (destp) *destp = NULL; + if (indicesp) + *indicesp = NULL; return (size_t)-1; } @@ -298,6 +300,8 @@ xdupmbstowcs (destp, indicesp, src) if (wsbuf == NULL) { *destp = NULL; + if (indicesp) + *indicesp = NULL; return (size_t)-1; } @@ -309,6 +313,7 @@ xdupmbstowcs (destp, indicesp, src) { free (wsbuf); *destp = NULL; + *indicesp = NULL; return (size_t)-1; } } @@ -343,6 +348,8 @@ xdupmbstowcs (destp, indicesp, src) free (wsbuf); FREE (indices); *destp = NULL; + if (indicesp) + *indicesp = NULL; return (size_t)-1; } @@ -362,18 +369,22 @@ xdupmbstowcs (destp, indicesp, src) free (wsbuf); FREE (indices); *destp = NULL; + if (indicesp) + *indicesp = NULL; return (size_t)-1; } wsbuf = wstmp; if (indicesp) { - idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char **)); + idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char *)); if (idxtmp == NULL) { free (wsbuf); free (indices); *destp = NULL; + if (indicesp) + *indicesp = NULL; return (size_t)-1; } indices = idxtmp; |