📄 sm_loop.c
字号:
/* Copyright (C) 1991-2006 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. 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. 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. You should have received a copy of the GNU General Public License along with Bash. If not, see <http://www.gnu.org/licenses/>.*/int FCT __P((CHAR *, CHAR *, int));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));intFCT (pattern, string, flags) CHAR *pattern; CHAR *string; int flags;{ CHAR *se, *pe; if (string == 0 || pattern == 0) return FNM_NOMATCH; se = string + STRLEN ((XCHAR *)string); pe = pattern + STRLEN ((XCHAR *)pattern); return (GMATCH (string, se, pattern, pe, flags));}/* Match STRING against the filename pattern PATTERN, returning zero if it matches, FNM_NOMATCH if not. */static intGMATCH (string, se, pattern, pe, flags) CHAR *string, *se; CHAR *pattern, *pe; int flags;{ CHAR *p, *n; /* pattern, string */ INT c; /* current pattern character - XXX U_CHAR? */ INT sc; /* current string character - XXX U_CHAR? */ p = pattern; n = string; if (string == 0 || pattern == 0) return FNM_NOMATCH;#if DEBUG_MATCHINGfprintf(stderr, "gmatch: string = %s; se = %s\n", string, se);fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);#endif while (p < pe) { c = *p++; c = FOLD (c); sc = n < se ? *n : '\0';#ifdef EXTENDED_GLOB /* EXTMATCH () will handle recursively calling GMATCH, so we can just return what EXTMATCH() returns. */ if ((flags & FNM_EXTMATCH) && *p == L('(') && (c == L('+') || c == L('*') || c == L('?') || c == L('@') || c == L('!'))) /* ) */ { int lflags; /* If we're not matching the start of the string, we're not concerned about the special cases for matching `.' */ lflags = (n == string) ? flags : (flags & ~FNM_PERIOD); return (EXTMATCH (c, n, se, p, pe, lflags)); }#endif /* EXTENDED_GLOB */ switch (c) { case L('?'): /* Match single character */ if (sc == '\0') return FNM_NOMATCH; else if ((flags & FNM_PATHNAME) && sc == L('/')) /* If we are matching a pathname, `?' can never match a `/'. */ return FNM_NOMATCH; else if ((flags & FNM_PERIOD) && sc == L('.') && (n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/')))) /* `?' cannot match a `.' if it is the first character of the string or if it is the first character following a slash and we are matching a pathname. */ return FNM_NOMATCH; break; case L('\\'): /* backslash escape removes special meaning */ if (p == pe) return FNM_NOMATCH; if ((flags & FNM_NOESCAPE) == 0) { c = *p++; /* A trailing `\' cannot match. */ if (p > pe) return FNM_NOMATCH; c = FOLD (c); } if (FOLD (sc) != (U_CHAR)c) return FNM_NOMATCH; break; case '*': /* Match zero or more characters */ if (p == pe) return 0; if ((flags & FNM_PERIOD) && sc == L('.') && (n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/')))) /* `*' cannot match a `.' if it is the first character of the string or if it is the first character following a slash and we are matching a pathname. */ return FNM_NOMATCH; /* Collapse multiple consecutive `*' and `?', but make sure that one character of the string is consumed for each `?'. */ for (c = *p++; (c == L('?') || c == L('*')); c = *p++) { if ((flags & FNM_PATHNAME) && sc == L('/')) /* A slash does not match a wildcard under FNM_PATHNAME. */ return FNM_NOMATCH;#ifdef EXTENDED_GLOB else if ((flags & FNM_EXTMATCH) && c == L('?') && *p == L('(')) /* ) */ { CHAR *newn; for (newn = n; newn < se; ++newn) { 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; }#endif else if (c == L('?')) { if (sc == L('\0')) return FNM_NOMATCH; /* One character of the string is consumed in matching this ? wildcard, so *??? won't match if there are fewer than three characters. */ n++; sc = n < se ? *n : '\0'; }#ifdef EXTENDED_GLOB /* Handle ******(patlist) */ if ((flags & FNM_EXTMATCH) && c == L('*') && *p == L('(')) /*)*/ { CHAR *newn; /* We need to check whether or not the extended glob pattern matches the remainder of the string. If it does, we match the entire pattern. */ for (newn = n; newn < se; ++newn) { if (EXTMATCH (c, newn, se, p, pe, flags) == 0) return (0); } /* We didn't match the extended glob pattern, but that's OK, since we can match 0 or more occurrences. We need to skip the glob pattern and see if we match the rest of the string. */ newn = PATSCAN (p + 1, pe, 0); /* If NEWN is 0, we have an ill-formed pattern. */ p = newn ? newn : pe; }#endif if (p == pe) break; } /* If we've hit the end of the pattern and the last character of the pattern was handled by the loop above, we've succeeded. Otherwise, we need to match that last character. */ if (p == pe && (c == L('?') || c == L('*'))) return (0); /* General case, use recursion. */ { U_CHAR c1; c1 = ((flags & FNM_NOESCAPE) == 0 && c == L('\\')) ? *p : c; c1 = FOLD (c1); for (--p; n < se; ++n) { /* Only call strmatch if the first character indicates a possible match. We can check the first character if we're not doing an extended glob match. */ if ((flags & FNM_EXTMATCH) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/ continue; /* If we're doing an extended glob match and the pattern is not one of the extended glob patterns, we can check the first character. */ if ((flags & FNM_EXTMATCH) && p[1] != L('(') && /*)*/ STRCHR (L("?*+@!"), *p) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/ continue; /* Otherwise, we just recurse. */ if (GMATCH (n, se, p, pe, flags & ~FNM_PERIOD) == 0) return (0); } return FNM_NOMATCH; } case L('['): { if (sc == L('\0') || n == se) return FNM_NOMATCH; /* A character class cannot match a `.' if it is the first character of the string or if it is the first character following a slash and we are matching a pathname. */ if ((flags & FNM_PERIOD) && sc == L('.') && (n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/')))) return (FNM_NOMATCH); p = BRACKMATCH (p, sc, flags); if (p == 0) return FNM_NOMATCH; } break; default: if ((U_CHAR)c != FOLD (sc)) return (FNM_NOMATCH); } ++n; } if (n == se) return (0); if ((flags & FNM_LEADING_DIR) && *n == L('/')) /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ return 0; return (FNM_NOMATCH);}/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find the value of the symbol, and move P past the collating symbol expression. The value is returned in *VP, if VP is not null. */static CHAR *PARSE_COLLSYM (p, vp) CHAR *p; INT *vp;{ register int pc; INT val; p++; /* move past the `.' */ for (pc = 0; p[pc]; pc++) if (p[pc] == L('.') && p[pc+1] == L(']')) break; val = COLLSYM (p, pc); if (vp) *vp = val; return (p + pc + 2);}/* Use prototype definition here because of type promotion. */static CHAR *#if defined (PROTOTYPES)BRACKMATCH (CHAR *p, U_CHAR test, int flags)#elseBRACKMATCH (p, test, flags) CHAR *p; U_CHAR test; int flags;#endif{ register CHAR cstart, cend, c; register int not; /* Nonzero if the sense of the character class is inverted. */ int brcnt; INT pc; CHAR *savep; test = FOLD (test); savep = p; /* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the circumflex (`^') in its role in a `nonmatching list'. A bracket expression starting with an unquoted circumflex character produces unspecified results. This implementation treats the two identically. */ if (not = (*p == L('!') || *p == L('^'))) ++p; c = *p++; for (;;) { /* Initialize cstart and cend in case `-' is the last character of the pattern. */ cstart = cend = c; /* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find the end of the equivalence class, move the pattern pointer past it, and check for equivalence. XXX - this handles only single-character equivalence classes, which is wrong, or at least incomplete. */ if (c == L('[') && *p == L('=') && p[2] == L('=') && p[3] == L(']')) { pc = FOLD (p[1]); p += 4; if (COLLEQUIV (test, pc)) {/*[*/ /* Move past the closing `]', since the first thing we do at the `matched:' label is back p up one. */ p++; goto matched; } else { c = *p++; if (c == L('\0')) return ((test == L('[')) ? savep : (CHAR *)0); /*]*/ c = FOLD (c); continue; } } /* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */ if (c == L('[') && *p == L(':')) { CHAR *close, *ccname; pc = 0; /* make sure invalid char classes don't match. */ /* Find end of character class name */ for (close = p + 1; *close != '\0'; close++) if (*close == L(':') && *(close+1) == L(']')) break; if (*close != L('\0')) { ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR)); if (ccname == 0) pc = 0; else { bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR)); *(ccname + (close - p - 1)) = L('\0'); pc = IS_CCLASS (test, (XCHAR *)ccname); } if (pc == -1) pc = 0; else p = close + 2; free (ccname); } if (pc) {/*[*/ /* Move past the closing `]', since the first thing we do at the `matched:' label is back p up one. */ p++; goto matched; } else { /* continue the loop here, since this expression can't be the first part of a range expression. */ c = *p++; if (c == L('\0')) return ((test == L('[')) ? savep : (CHAR *)0); else if (c == L(']'))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -