const char *
VRT_regsub(const struct sess *sp, int all, const char *str, void *re,
    const char *sub)
{
	int ovector[30];
	vre_t *t;
	int i, l;
	txt res;
	char *b0;
	const char *s;
	unsigned u, x;

	AN(re);
	if (str == NULL)
		str = "";
	t = re;
	memset(ovector, 0, sizeof(ovector));
	i = VRE_exec(t, str, strlen(str), 0, 0, ovector, 30,
	    &params->vre_limits);

	/* If it didn't match, we can return the original string */
	if (i == VRE_ERROR_NOMATCH)
		return(str);
	if (i < VRE_ERROR_NOMATCH ) {
		WSP(sp, SLT_VCL_Error, "Regexp matching returned %d", i);
		return(str);
	}

	u = WS_Reserve(sp->http->ws, 0);
	res.e = res.b = b0 = sp->http->ws->f;
	res.e += u;

	do {
		/* Copy prefix to match */
		Tadd(&res, str, ovector[0]);
		for (s = sub ; *s != '\0'; s++ ) {
			if (*s != '\\' || s[1] == '\0') {
				if (res.b < res.e)
					*res.b++ = *s;
				continue;
			}
			s++;
			if (isdigit(*s)) {
				x = *s - '0';
				l = ovector[2*x+1] - ovector[2*x];
				Tadd(&res, str + ovector[2*x], l);
				continue;
			} else {
				if (res.b < res.e)
					*res.b++ = *s;
			}
		}
		str += ovector[1];
		if (!all)
			break;
		memset(&ovector, 0, sizeof(ovector));
		i = VRE_exec(t, str, strlen(str), 0, 0, ovector, 30,
		    &params->vre_limits);
		if (i < VRE_ERROR_NOMATCH ) {
			WSP(sp, SLT_VCL_Error,
			    "Regexp matching returned %d", i);
			return(str);
		}
	} while (i != VRE_ERROR_NOMATCH);

	/* Copy suffix to match */
	l = strlen(str) + 1;
	Tadd(&res, str, l);
	if (res.b >= res.e) {
		WS_Release(sp->http->ws, 0);
		return (str);
	}
	Tcheck(res);
	WS_ReleaseP(sp->http->ws, res.b);
	return (b0);
}
const char *
VRT_regsub(struct req *req, int all, const char *str, void *re,
    const char *sub)
{
	int ovector[30];
	vre_t *t;
	int i, l;
	txt res;
	char *b0;
	const char *s;
	unsigned u, x;
	int options = 0;
	size_t len;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	AN(re);
	if (str == NULL)
		str = "";
	if (sub == NULL)
		sub = "";
	t = re;
	memset(ovector, 0, sizeof(ovector));
	len = strlen(str);
	i = VRE_exec(t, str, len, 0, options, ovector, 30,
	    &cache_param->vre_limits);

	/* If it didn't match, we can return the original string */
	if (i == VRE_ERROR_NOMATCH)
		return(str);
	if (i < VRE_ERROR_NOMATCH ) {
		VSLb(req->vsl, SLT_VCL_Error, "Regexp matching returned %d", i);
		return(str);
	}

	u = WS_Reserve(req->http->ws, 0);
	res.e = res.b = b0 = req->http->ws->f;
	res.e += u;

	do {
		/* Copy prefix to match */
		Tadd(&res, str, ovector[0]);
		for (s = sub ; *s != '\0'; s++ ) {
			if (*s != '\\' || s[1] == '\0') {
				if (res.b < res.e)
					*res.b++ = *s;
				continue;
			}
			s++;
			if (isdigit(*s)) {
				x = *s - '0';
				l = ovector[2*x+1] - ovector[2*x];
				Tadd(&res, str + ovector[2*x], l);
				continue;
			} else {
				if (res.b < res.e)
					*res.b++ = *s;
			}
		}
		str += ovector[1];
		len -= ovector[1];
		if (!all)
			break;
		memset(&ovector, 0, sizeof(ovector));
		options |= VRE_NOTEMPTY;
		i = VRE_exec(t, str, len, 0, options, ovector, 30,
		    &cache_param->vre_limits);
		if (i < VRE_ERROR_NOMATCH ) {
			WS_Release(req->http->ws, 0);
			VSLb(req->vsl, SLT_VCL_Error,
			    "Regexp matching returned %d", i);
			return(str);
		}
	} while (i != VRE_ERROR_NOMATCH);

	/* Copy suffix to match */
	Tadd(&res, str, len+1);
	if (res.b >= res.e) {
		WS_Release(req->http->ws, 0);
		return (str);
	}
	Tcheck(res);
	WS_ReleaseP(req->http->ws, res.b);
	return (b0);
}