static List *extractsinglematch(const char *subject, const char *pattern, const char *quoting, List *result) { int i; const char *s; if (!haswild(pattern, quoting) /* no wildcards, so no matches */ || !match(subject, pattern, quoting)) return NULL; for (s = subject, i = 0; pattern[i] != '\0'; s++) { if (ISQUOTED(quoting, i)) i++; else { int c = pattern[i++]; switch (c) { case '*': { const char *begin; if (pattern[i] == '\0') return mklist(mkstr(gcdup(s)), result); for (begin = s;; s++) { const char *q = TAILQUOTE(quoting, i); assert(*s != '\0'); if (match(s, pattern + i, q)) { result = mklist(mkstr(gcndup(begin, s - begin)), result); return haswild(pattern + i, q) ? extractsinglematch(s, pattern + i, q, result) : result; } } } case '[': { int j = rangematch(pattern + i, TAILQUOTE(quoting, i), *s); assert(j != RANGE_FAIL); if (j == RANGE_ERROR) { assert(*s == '['); break; } i += j; } /* FALLTHROUGH */ case '?': result = mklist(mkstr(str("%c", *s)), result); break; default: break; } } } return result; }
/* match -- match a single pattern against a single string. */ extern Boolean match(const char *s, const char *p, const char *q) { int i; if (q == QUOTED) return streq(s, p); for (i = 0;;) { int c = p[i++]; if (c == '\0') return *s == '\0'; else if (q == UNQUOTED || q[i - 1] == 'r') { switch (c) { case '?': if (*s++ == '\0') return FALSE; break; case '*': while (p[i] == '*' && (q == UNQUOTED || q[i] == 'r')) /* collapse multiple stars */ i++; if (p[i] == '\0') /* star at end of pattern? */ return TRUE; while (*s != '\0') if (match(s++, p + i, TAILQUOTE(q, i))) return TRUE; return FALSE; case '[': { int j; if (*s == '\0') return FALSE; switch (j = rangematch(p + i, TAILQUOTE(q, i), *s)) { default: i += j; break; case RANGE_FAIL: return FALSE; case RANGE_ERROR: if (*s != '[') return FALSE; } s++; break; } default: if (c != *s++) return FALSE; } } else if (c != *s++) return FALSE; } }