Пример #1
0
/* 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;
}
Пример #2
0
/**
 * 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);
}