int gmatch(const char *s, const char *p, int isfile) { const char *se, *pe; if (s == NULL || p == NULL) return 0; se = s + strlen(s); pe = p + strlen(p); /* isfile is false iff no syntax check has been done on * the pattern. If check fails, just to a strcmp(). */ if (!isfile && !has_globbing(p, pe)) { int len = pe - p + 1; char tbuf[64]; char *t = len <= sizeof(tbuf) ? tbuf : (char *) alloc(len, ATEMP); debunk(t, p, len); return !strcmp(t, s); } return do_gmatch((const unsigned char *) s, (const unsigned char *) se, (const unsigned char *) p, (const unsigned char *) pe); }
/* * int gmatch(string, pattern) * char *string, *pattern; * * Match a pattern as in sh(1). * pattern character are prefixed with MAGIC by expand. */ int gmatchx(const char *s, const char *p, bool isfile) { const char *se, *pe; char *pnew; int rv; if (s == NULL || p == NULL) return (0); se = s + strlen(s); pe = p + strlen(p); /* * isfile is false iff no syntax check has been done on * the pattern. If check fails, just to a strcmp(). */ if (!isfile && !has_globbing(p, pe)) { size_t len = pe - p + 1; char tbuf[64]; char *t = len <= sizeof(tbuf) ? tbuf : alloc(len, ATEMP); debunk(t, p, len); return (!strcmp(t, s)); } /* * since the do_gmatch() engine sucks so much, we must do some * pattern simplifications */ pnew = simplify_gmatch_pattern((const unsigned char *)p); pe = pnew + strlen(pnew); rv = do_gmatch((const unsigned char *)s, (const unsigned char *)se, (const unsigned char *)pnew, (const unsigned char *)pe); afree(pnew, ATEMP); return (rv); }
/* 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; }