/* Function must return either 0 or 1 (assumed by code for 0x80|'!') */ static int do_gmatch(const unsigned char *s, const unsigned char *se, const unsigned char *p, const unsigned char *pe) { int sc, pc; const unsigned char *prest, *psub, *pnext; const unsigned char *srest; if (s == NULL || p == NULL) return 0; while (p < pe) { pc = *p++; sc = s < se ? *s : '\0'; s++; if (!ISMAGIC(pc)) { if (sc != pc) return 0; continue; } switch (*p++) { case '[': if (sc == 0 || (p = cclass(p, sc)) == NULL) return 0; break; case '?': if (sc == 0) return 0; break; case '*': if (p == pe) return 1; s--; do { if (do_gmatch(s, se, p, pe)) return 1; } while (s++ < se); return 0; /* * [*+?@!](pattern|pattern|..) * * Not ifdef'd KSH as this is needed for ${..%..}, etc. */ case 0x80|'+': /* matches one or more times */ case 0x80|'*': /* matches zero or more times */ if (!(prest = pat_scan(p, pe, 0))) return 0; s--; /* take care of zero matches */ if (p[-1] == (0x80 | '*') && do_gmatch(s, se, prest, pe)) return 1; for (psub = p; ; psub = pnext) { pnext = pat_scan(psub, pe, 1); for (srest = s; srest <= se; srest++) { if (do_gmatch(s, srest, psub, pnext - 2) && (do_gmatch(srest, se, prest, pe) || (s != srest && do_gmatch(srest, se, p - 2, pe)))) return 1; } if (pnext == prest) break; } return 0; case 0x80|'?': /* matches zero or once */ case 0x80|'@': /* matches one of the patterns */ case 0x80|' ': /* simile for @ */ if (!(prest = pat_scan(p, pe, 0))) return 0; s--; /* Take care of zero matches */ if (p[-1] == (0x80 | '?') && do_gmatch(s, se, prest, pe)) return 1; for (psub = p; ; psub = pnext) { pnext = pat_scan(psub, pe, 1); srest = prest == pe ? se : s; for (; srest <= se; srest++) { if (do_gmatch(s, srest, psub, pnext - 2) && do_gmatch(srest, se, prest, pe)) return 1; } if (pnext == prest) break; } return 0; case 0x80|'!': /* matches none of the patterns */ if (!(prest = pat_scan(p, pe, 0))) return 0; s--; for (srest = s; srest <= se; srest++) { int matched = 0; for (psub = p; ; psub = pnext) { pnext = pat_scan(psub, pe, 1); if (do_gmatch(s, srest, psub, pnext - 2)) { matched = 1; break; } if (pnext == prest) break; } if (!matched && do_gmatch(srest, se, prest, pe)) return 1; } return 0; default: if (sc != p[-1]) return 0; break; } } return s == se; }
/** * pattern simplifications: * - @(x) -> x (not @(x|y) though) * - ** -> * */ static void * simplify_gmatch_pattern(const unsigned char *sp) { uint8_t c; unsigned char *cp, *dp; const unsigned char *ps, *se; cp = alloc(strlen((const void *)sp) + 1, ATEMP); goto simplify_gmatch_pat1a; /* foo@(b@(a)r)b@(a|a)z -> foobarb@(a|a)z */ simplify_gmatch_pat1: sp = cp; simplify_gmatch_pat1a: dp = cp; se = sp + strlen((const void *)sp); while ((c = *sp++)) { if (!ISMAGIC(c)) { *dp++ = c; continue; } switch ((c = *sp++)) { case 0x80|'@': /* simile for @ */ case 0x80|' ': /* check whether it has only one clause */ ps = pat_scan(sp, se, true); if (!ps || ps[-1] != /*(*/ ')') /* nope */ break; /* copy inner clause until matching close */ ps -= 2; while ((const unsigned char *)sp < ps) *dp++ = *sp++; /* skip MAGIC and closing parenthesis */ sp += 2; /* copy the rest of the pattern */ memmove(dp, sp, strlen((const void *)sp) + 1); /* redo from start */ goto simplify_gmatch_pat1; } *dp++ = MAGIC; *dp++ = c; } *dp = '\0'; /* collapse adjacent asterisk wildcards */ sp = dp = cp; while ((c = *sp++)) { if (!ISMAGIC(c)) { *dp++ = c; continue; } switch ((c = *sp++)) { case '*': while (ISMAGIC(sp[0]) && sp[1] == c) sp += 2; break; } *dp++ = MAGIC; *dp++ = c; } *dp = '\0'; /* return the result, allocated from ATEMP */ return (cp); }