Пример #1
0
/*XXX
- if no magic,
	if dest given, copy to dst
	return ?
- if magic && (no globbing || syntax error)
	debunk to dst
	return ?
- return ?
*/
int
has_globbing(const char *xp, const char *xpe)
{
	const unsigned char *p = (const unsigned char *) xp;
	const unsigned char *pe = (const unsigned char *) xpe;
	int c;
	int nest = 0, bnest = 0;
	int saw_glob = 0;
	int in_bracket = 0; /* inside [...] */

	for (; p < pe; p++) {
		if (!ISMAGIC(*p))
			continue;
		if ((c = *++p) == '*' || c == '?')
			saw_glob = 1;
		else if (c == '[') {
			if (!in_bracket) {
				saw_glob = 1;
				in_bracket = 1;
				if (ISMAGIC(p[1]) && p[2] == NOT)
					p += 2;
				if (ISMAGIC(p[1]) && p[2] == ']')
					p += 2;
			}
			/* XXX Do we need to check ranges here? POSIX Q */
		} else if (c == ']') {
			if (in_bracket) {
				if (bnest)		/* [a*(b]) */
					return 0;
				in_bracket = 0;
			}
		} else if ((c & 0x80) && strchr("*+?@! ", c & 0x7f)) {
			saw_glob = 1;
			if (in_bracket)
				bnest++;
			else
				nest++;
		} else if (c == '|') {
			if (in_bracket && !bnest)	/* *(a[foo|bar]) */
				return 0;
		} else if (c == /*(*/ ')') {
			if (in_bracket) {
				if (!bnest--)		/* *(a[b)c] */
					return 0;
			} else if (nest)
				nest--;
		}
		/* else must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, MAGIC-]
			 MAGIC-{, MAGIC-,, MAGIC-} */
	}
	return saw_glob && !in_bracket && !nest;
}
Пример #2
0
static const unsigned char *
cclass(const unsigned char *p, int sub)
{
	int c, d, rv, not, found = 0;
	const unsigned char *orig_p = p;

	if ((not = (ISMAGIC(*p) && *++p == NOT)))
		p++;
	do {
		/* check for POSIX character class (e.g. [[:alpha:]]) */
		if ((p[0] == MAGIC && p[1] == '[' && p[2] == ':') ||
		    (p[0] == '[' && p[1] == ':')) {
			do {
				const char *pp = p + (*p == MAGIC) + 2;
				rv = posix_cclass(pp, sub, &p);
				switch (rv) {
				case 1:
					found = 1;
					break;
				case -2:
					return NULL;
				}
			} while (rv != -1 && p[0] == MAGIC && p[1] == '[' && p[2] == ':');
			if (p[0] == MAGIC && p[1] == ']')
				break;
		}

		c = *p++;
		if (ISMAGIC(c)) {
			c = *p++;
			if ((c & 0x80) && !ISMAGIC(c)) {
				c &= 0x7f;/* extended pattern matching: *+?@! */
				/* XXX the ( char isn't handled as part of [] */
				if (c == ' ') /* simile for @: plain (..) */
					c = '(' /*)*/;
			}
		}
		if (c == '\0')
			/* No closing ] - act as if the opening [ was quoted */
			return sub == '[' ? orig_p : NULL;
		if (ISMAGIC(p[0]) && p[1] == '-' &&
		    (!ISMAGIC(p[2]) || p[3] != ']')) {
			p += 2; /* MAGIC- */
			d = *p++;
			if (ISMAGIC(d)) {
				d = *p++;
				if ((d & 0x80) && !ISMAGIC(d))
					d &= 0x7f;
			}
			/* POSIX says this is an invalid expression */
			if (c > d)
				return NULL;
		} else
			d = c;
		if (c == sub || (c <= sub && sub <= d))
			found = 1;
	} while (!(ISMAGIC(p[0]) && p[1] == ']'));

	return (found != not) ? p+2 : NULL;
}
Пример #3
0
static const unsigned char *
gmatch_cclass(const unsigned char *p, unsigned char sub)
{
	unsigned char c, d;
	bool notp, found = false;
	const unsigned char *orig_p = p;

	if ((notp = tobool(ISMAGIC(*p) && *++p == '!')))
		p++;
	do {
		c = *p++;
		if (ISMAGIC(c)) {
			c = *p++;
			if ((c & 0x80) && !ISMAGIC(c)) {
				/* extended pattern matching: *+?@! */
				c &= 0x7F;
				/* XXX the ( char isn't handled as part of [] */
				if (c == ' ')
					/* simile for @: plain (..) */
					c = '(' /*)*/;
			}
		}
		if (c == '\0')
			/* No closing ] - act as if the opening [ was quoted */
			return (sub == '[' ? orig_p : NULL);
		if (ISMAGIC(p[0]) && p[1] == '-' &&
		    (!ISMAGIC(p[2]) || p[3] != ']')) {
			/* MAGIC- */
			p += 2;
			d = *p++;
			if (ISMAGIC(d)) {
				d = *p++;
				if ((d & 0x80) && !ISMAGIC(d))
					d &= 0x7f;
			}
			/* POSIX says this is an invalid expression */
			if (c > d)
				return (NULL);
		} else
			d = c;
		if (c == sub || (c <= sub && sub <= d))
			found = true;
	} while (!(ISMAGIC(p[0]) && p[1] == ']'));

	return ((found != notp) ? p+2 : NULL);
}
Пример #4
0
/* Look for next ) or | (if match_sep) in *(foo|bar) pattern */
const unsigned char *
pat_scan(const unsigned char *p, const unsigned char *pe, int match_sep)
{
        int nest = 0;

        for (; p < pe; p++) {
                if (!ISMAGIC(*p))
                        continue;
                if ((*++p == /*(*/ ')' && nest-- == 0) ||
                        (*p == '|' && match_sep && nest == 0))
                        return ++p;
                if ((*p & 0x80) && strchr("*+?@! ", *p & 0x7f))
                        nest++;
        }
        return (const unsigned char *) 0;
}
Пример #5
0
static const unsigned char *
cclass(const unsigned char *p, int sub)
{
        int c, d, not, found = 0;
        const unsigned char *orig_p = p;

        if ((not = (ISMAGIC(*p) && *++p == NOT)))
                p++;
        do {
                c = *p++;
                if (ISMAGIC(c)) {
                        c = *p++;
                        if ((c & 0x80) && !ISMAGIC(c)) {
                                c &= 0x7f;/* extended pattern matching: *+?@! */
                                /* XXX the ( char isn't handled as part of [] */
                                if (c == ' ') /* simile for @: plain (..) */
                                        c = '(' /*)*/;
                        }
                }
                if (c == '\0')
                        /* No closing ] - act as if the opening [ was quoted */
                        return sub == '[' ? orig_p : NULL;
                if (ISMAGIC(p[0]) && p[1] == '-' &&
                        (!ISMAGIC(p[2]) || p[3] != ']'))
                {
                        p += 2; /* MAGIC- */
                        d = *p++;
                        if (ISMAGIC(d)) {
                                d = *p++;
                                if ((d & 0x80) && !ISMAGIC(d))
                                        d &= 0x7f;
                        }
                        /* POSIX says this is an invalid expression */
                        if (c > d)
                                return NULL;
                } else
                        d = c;
                if (c == sub || (c <= sub && sub <= d))
                        found = 1;
        } while (!(ISMAGIC(p[0]) && p[1] == ']'));

        return (found != not) ? p+2 : NULL;
}
Пример #6
0
/* variant of fputs for ptreef and wdstrip */
static const char *
wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
{
	int c;
	const char *cs;

	/*-
	 * problems:
	 *	`...` -> $(...)
	 *	'foo' -> "foo"
	 *	x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS
	 *	x${foo:-'hi'} -> x${foo:-hi} unless WDS_KEEPQ
	 * could change encoding to:
	 *	OQUOTE ["'] ... CQUOTE ["']
	 *	COMSUB [(`] ...\0	(handle $ ` \ and maybe " in `...` case)
	 */
	while (/* CONSTCOND */ 1)
		switch (*wp++) {
		case EOS:
			return (--wp);
		case ADELIM:
		case CHAR:
			c = *wp++;
			if ((opmode & WDS_MAGIC) &&
			    (ISMAGIC(c) || c == '[' || c == '!' ||
			    c == '-' || c == ']' || c == '*' || c == '?'))
				shf_putc(MAGIC, shf);
			shf_putc(c, shf);
			break;
		case QCHAR: {
			bool doq;

			c = *wp++;
			doq = (c == '"' || c == '`' || c == '$' || c == '\\');
			if (opmode & WDS_TPUTS) {
				if (quotelevel == 0)
					doq = true;
			} else {
				if (!(opmode & WDS_KEEPQ))
					doq = false;
			}
			if (doq)
				shf_putc('\\', shf);
			shf_putc(c, shf);
			break;
		}
		case COMSUB:
			shf_puts("$(", shf);
			cs = ")";
 pSUB:
			while ((c = *wp++) != 0)
				shf_putc(c, shf);
			shf_puts(cs, shf);
			break;
		case FUNSUB:
			c = ' ';
			if (0)
				/* FALLTHROUGH */
		case VALSUB:
			  c = '|';
			shf_putc('$', shf);
			shf_putc('{', shf);
			shf_putc(c, shf);
			cs = ";}";
			goto pSUB;
		case EXPRSUB:
			shf_puts("$((", shf);
			cs = "))";
			goto pSUB;
		case OQUOTE:
			if (opmode & WDS_TPUTS) {
				quotelevel++;
				shf_putc('"', shf);
			}
			break;
		case CQUOTE:
			if (opmode & WDS_TPUTS) {
				if (quotelevel)
					quotelevel--;
				shf_putc('"', shf);
			}
			break;
		case OSUBST:
			shf_putc('$', shf);
			if (*wp++ == '{')
				shf_putc('{', shf);
			while ((c = *wp++) != 0)
				shf_putc(c, shf);
			wp = wdvarput(shf, wp, 0, opmode);
			break;
		case CSUBST:
			if (*wp++ == '}')
				shf_putc('}', shf);
			return (wp);
		case OPAT:
			if (opmode & WDS_MAGIC) {
				shf_putc(MAGIC, shf);
				shf_putchar(*wp++ | 0x80, shf);
			} else {
				shf_putchar(*wp++, shf);
				shf_putc('(', shf);
			}
			break;
		case SPAT:
			c = '|';
			if (0)
		case CPAT:
				c = /*(*/ ')';
			if (opmode & WDS_MAGIC)
				shf_putc(MAGIC, shf);
			shf_putc(c, shf);
			break;
		}
}
Пример #7
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;
}
Пример #8
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);
}
Пример #9
0
static void
glob_path(int flags, const char *pat, XPtrV *wp, const char *path)
{
	const char *sp, *p;
	char *xp;
	int staterr;
	int pathlen;
	int patlen;
	int oldsize, newsize, i, j;
	char **words;
	XString xs;

	patlen = strlen(pat) + 1;
	sp = path;
	Xinit(xs, xp, patlen + 128, ATEMP);
	while (sp) {
		xp = Xstring(xs, xp);
		if (!(p = strchr(sp, ':')))
			p = sp + strlen(sp);
		pathlen = p - sp;
		if (pathlen) {
			/* Copy sp into xp, stuffing any MAGIC characters
			 * on the way
			 */
			const char *s = sp;

			XcheckN(xs, xp, pathlen * 2);
			while (s < p) {
				if (ISMAGIC(*s))
					*xp++ = MAGIC;
				*xp++ = *s++;
			}
			*xp++ = '/';
			pathlen++;
		}
		sp = p;
		XcheckN(xs, xp, patlen);
		memcpy(xp, pat, patlen);

		oldsize = XPsize(*wp);
		glob_str(Xstring(xs, xp), wp, 1); /* mark dirs */
		newsize = XPsize(*wp);

		/* Check that each match is executable... */
		words = (char **) XPptrv(*wp);
		for (i = j = oldsize; i < newsize; i++) {
			staterr = 0;
			if ((search_access(words[i], X_OK, &staterr) >= 0) ||
			    (staterr == EISDIR)) {
				words[j] = words[i];
				if (!(flags & XCF_FULLPATH))
					memmove(words[j], words[j] + pathlen,
					    strlen(words[j] + pathlen) + 1);
				j++;
			} else
				afree(words[i], ATEMP);
		}
		wp->cur = (void **) &words[j];

		if (!*sp++)
			break;
	}
	Xfree(xs, xp);
}