📄 sm_loop.c
字号:
break; c = FOLD (c); continue; } } /* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of the symbol name, make sure it is terminated by `.]', translate the name to a character using the external table, and do the comparison. */ if (c == L('[') && *p == L('.')) { p = PARSE_COLLSYM (p, &pc); /* An invalid collating symbol cannot be the first point of a range. If it is, we set cstart to one greater than `test', so any comparisons later will fail. */ cstart = (pc == INVALID) ? test + 1 : pc; } if (!(flags & FNM_NOESCAPE) && c == L('\\')) { if (*p == '\0') return (CHAR *)0; cstart = cend = *p++; } cstart = cend = FOLD (cstart); /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that is not preceded by a backslash and is not part of a bracket expression produces undefined results.' This implementation treats the `[' as just a character to be matched if there is not a closing `]'. */ if (c == L('\0')) return ((test == L('[')) ? savep : (CHAR *)0); c = *p++; c = FOLD (c); if ((flags & FNM_PATHNAME) && c == L('/')) /* [/] can never match when matching a pathname. */ return (CHAR *)0; /* This introduces a range, unless the `-' is the last character of the class. Find the end of the range and move past it. */ if (c == L('-') && *p != L(']')) { cend = *p++; if (!(flags & FNM_NOESCAPE) && cend == L('\\')) cend = *p++; if (cend == L('\0')) return (CHAR *)0; if (cend == L('[') && *p == L('.')) { p = PARSE_COLLSYM (p, &pc); /* An invalid collating symbol cannot be the second part of a 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; } cend = FOLD (cend); c = *p++; /* POSIX.2 2.8.3.2: ``The ending range point shall collate equal to or higher than the starting range point; otherwise 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 (c == L(']')) break; c = FOLD (c); continue; } } if (RANGECMP (test, cstart) >= 0 && RANGECMP (test, cend) <= 0) goto matched; if (c == L(']')) break; } /* No match. */ return (!not ? (CHAR *)0 : p);matched: /* Skip the rest of the [...] that already matched. */ c = *--p; brcnt = 1; while (brcnt > 0) { /* A `[' without a matching `]' is just another character to match. */ if (c == L('\0')) return ((test == L('[')) ? savep : (CHAR *)0); c = *p++; if (c == L('[') && (*p == L('=') || *p == L(':') || *p == L('.'))) brcnt++; else if (c == L(']')) brcnt--; else if (!(flags & FNM_NOESCAPE) && c == L('\\')) { if (*p == '\0') return (CHAR *)0; /* XXX 1003.2d11 is unclear if this is right. */ ++p; } } return (not ? (CHAR *)0 : p);}#if defined (EXTENDED_GLOB)/* ksh-like extended pattern matching: [?*+@!](pat-list) where pat-list is a list of one or patterns separated by `|'. Operation is as follows: ?(patlist) match zero or one of the given patterns *(patlist) match zero or more of the given patterns +(patlist) match one or more of the given patterns @(patlist) match exactly one of the given patterns !(patlist) match anything except one of the given patterns*//* Scan a pattern starting at STRING and ending at END, keeping track of embedded () and []. If DELIM is 0, we scan until a matching `)' 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 *PATSCAN (string, end, delim) CHAR *string, *end; INT delim;{ int pnest, bnest, skip; INT cchar; CHAR *s, c, *bfirst; pnest = bnest = skip = 0; cchar = 0; bfirst = NULL; for (s = string; c = *s; s++) { if (s >= end) return (s); if (skip) { skip = 0; continue; } switch (c) { case L('\\'): skip = 1; break; case L('\0'): return ((CHAR *)NULL); /* `[' is not special inside a bracket expression, but it may introduce one of the special POSIX bracket expressions ([.SYM.], [=c=], [: ... :]) that needs special handling. */ case L('['): if (bnest == 0) { bfirst = s + 1; if (*bfirst == L('!') || *bfirst == L('^')) bfirst++; bnest++; } else if (s[1] == L(':') || s[1] == L('.') || s[1] == L('=')) cchar = s[1]; break; /* `]' is not special if it's the first char (after a leading `!' or `^') in a bracket expression or if it's part of one of the special POSIX bracket expressions ([.SYM.], [=c=], [: ... :]) */ case L(']'): if (bnest) { if (cchar && s[-1] == cchar) cchar = 0; else if (s != bfirst) { bnest--; bfirst = 0; } } break; case L('('): if (bnest == 0) pnest++; break; case L(')'): if (bnest == 0 && pnest-- <= 0) return ++s; break; case L('|'): if (bnest == 0 && pnest == 0 && delim == L('|')) return ++s; break; } } return (NULL);}/* Return 0 if dequoted pattern matches S in the current locale. */static intSTRCOMPARE (p, pe, s, se) CHAR *p, *pe, *s, *se;{ int ret; CHAR c1, c2; c1 = *pe; c2 = *se; *pe = *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; return (ret == 0 ? ret : FNM_NOMATCH);}/* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or 0 on success. This is handed the entire rest of the pattern and string the first time an extended pattern specifier is encountered, so it calls gmatch recursively. */static intEXTMATCH (xc, s, se, p, pe, flags) INT xc; /* select which operation */ CHAR *s, *se; CHAR *p, *pe; int flags;{ CHAR *prest; /* pointer to rest of pattern */ CHAR *psub; /* pointer to sub-pattern */ CHAR *pnext; /* pointer to next sub-pattern */ CHAR *srest; /* pointer to rest of string */ int m1, m2, xflags; /* xflags = flags passed to recursive matches */#if DEBUG_MATCHINGfprintf(stderr, "extmatch: xc = %c\n", xc);fprintf(stderr, "extmatch: s = %s; se = %s\n", s, se);fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe);fprintf(stderr, "extmatch: flags = %d\n", flags);#endif prest = PATSCAN (p + (*p == L('(')), pe, 0); /* ) */ if (prest == 0) /* If PREST is 0, we failed to scan a valid pattern. In this case, we just want to compare the two as strings. */ return (STRCOMPARE (p - 1, pe, s, se)); switch (xc) { case L('+'): /* match one or more occurrences */ case L('*'): /* match zero or more occurrences */ /* If we can get away with no matches, don't even bother. Just call GMATCH on the rest of the pattern and return success if it succeeds. */ if (xc == L('*') && (GMATCH (s, se, prest, pe, flags) == 0)) return 0; /* OK, we have to do this the hard way. First, we make sure one of the subpatterns matches, then we try to match the rest of the string. */ for (psub = p + 1; ; psub = pnext) { pnext = PATSCAN (psub, pe, L('|')); for (srest = s; srest <= se; srest++) { /* Match this substring (S -> SREST) against this subpattern (psub -> pnext - 1) */ m1 = GMATCH (s, srest, psub, pnext - 1, flags) == 0; /* OK, we matched a subpattern, so make sure the rest of the string matches the rest of the pattern. Also handle multiple matches of the pattern. */ if (m1) { /* if srest > s, we are not at start of string */ xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags; m2 = (GMATCH (srest, se, prest, pe, xflags) == 0) || (s != srest && GMATCH (srest, se, p - 1, pe, xflags) == 0); } if (m1 && m2) return (0); } if (pnext == prest) break; } return (FNM_NOMATCH); case L('?'): /* match zero or one of the patterns */ case L('@'): /* match one (or more) of the patterns */ /* If we can get away with no matches, don't even bother. Just call gmatch on the rest of the pattern and return success if it succeeds. */ if (xc == L('?') && (GMATCH (s, se, prest, pe, flags) == 0)) return 0; /* OK, we have to do this the hard way. First, we see if one of the subpatterns matches, then, if it does, we try to match the rest of the string. */ for (psub = p + 1; ; psub = pnext) { pnext = PATSCAN (psub, pe, L('|')); srest = (prest == pe) ? se : s; for ( ; srest <= se; srest++) { /* if srest > s, we are not at start of string */ xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags; if (GMATCH (s, srest, psub, pnext - 1, flags) == 0 && GMATCH (srest, se, prest, pe, xflags) == 0) return (0); } if (pnext == prest) break; } return (FNM_NOMATCH); case '!': /* match anything *except* one of the patterns */ for (srest = s; srest <= se; srest++) { m1 = 0; for (psub = p + 1; ; psub = pnext) { pnext = PATSCAN (psub, pe, L('|')); /* If one of the patterns matches, just bail immediately. */ if (m1 = (GMATCH (s, srest, psub, pnext - 1, flags) == 0)) break; if (pnext == prest) break; } /* if srest > s, we are not at start of string */ xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags; if (m1 == 0 && GMATCH (srest, se, prest, pe, xflags) == 0) return (0); } return (FNM_NOMATCH); } return (FNM_NOMATCH);}#endif /* EXTENDED_GLOB */#undef IS_CCLASS#undef FOLD#undef CHAR#undef U_CHAR#undef XCHAR#undef INT#undef INVALID#undef FCT#undef GMATCH#undef COLLSYM#undef PARSE_COLLSYM#undef PATSCAN#undef STRCOMPARE#undef EXTMATCH#undef BRACKMATCH#undef STRCHR#undef STRCOLL#undef STRLEN#undef STRCMP#undef COLLEQUIV#undef RANGECMP#undef L
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -