diff options
Diffstat (limited to 'do/subst')
-rw-r--r-- | do/subst | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/do/subst b/do/subst new file mode 100644 index 0000000000..77dbde18c5 --- /dev/null +++ b/do/subst @@ -0,0 +1,269 @@ +int +do_subst(TARG,arg,sp) +STR *TARG; +ARG *arg; +int sp; +{ + register SPAT *spat; + SPAT *rspat; + register STR *dstr; + register char *s = str_get(TARG); + char *strend = s + TARG->str_cur; + register char *m; + char *c; + register char *d; + int clen; + int iters = 0; + int maxiters = (strend - s) + 10; + register int i; + bool once; + char *orig; + int safebase; + + rspat = spat = arg[2].arg_ptr.arg_spat; + if (!spat || !s) + fatal("panic: do_subst"); + else if (spat->spat_runtime) { + nointrp = "|)"; + (void)eval(spat->spat_runtime,G_SCALAR,sp); + m = str_get(dstr = stack->ary_array[sp+1]); + nointrp = ""; + if (spat->spat_regexp) { + regfree(spat->spat_regexp); + spat->spat_regexp = Null(REGEXP*); /* required if regcomp pukes */ + } + spat->spat_regexp = regcomp(m,m+dstr->str_cur, + spat->spat_flags & SPAT_FOLD); + if (spat->spat_flags & SPAT_KEEP) { + if (!(spat->spat_flags & SPAT_FOLD)) + scanconst(spat, m, dstr->str_cur); + arg_free(spat->spat_runtime); /* it won't change, so */ + spat->spat_runtime = Nullarg; /* no point compiling again */ + hoistmust(spat); + if (curcmd->c_expr && (curcmd->c_flags & CF_OPTIMIZE) == CFT_EVAL) { + curcmd->c_flags &= ~CF_OPTIMIZE; + opt_arg(curcmd, 1, curcmd->c_type == C_EXPR); + } + } + } +#ifdef DEBUGGING + if (debug & 8) { + deb("2.SPAT /%s/\n",spat->spat_regexp->precomp); + } +#endif + safebase = ((!spat->spat_regexp || !spat->spat_regexp->nparens) && + !sawampersand); + if (!spat->spat_regexp->prelen && lastspat) + spat = lastspat; + orig = m = s; + if (hint) { + if (hint < s || hint > strend) + fatal("panic: hint in do_match"); + s = hint; + hint = Nullch; + if (spat->spat_regexp->regback >= 0) { + s -= spat->spat_regexp->regback; + if (s < m) + s = m; + } + else + s = m; + } + else if (spat->spat_short) { + if (spat->spat_flags & SPAT_SCANFIRST) { + if (TARG->str_pok & SP_STUDIED) { + if (screamfirst[spat->spat_short->str_rare] < 0) + goto nope; + else if (!(s = screaminstr(TARG,spat->spat_short))) + goto nope; + } +#ifndef lint + else if (!(s = fbminstr((unsigned char*)s, (unsigned char*)strend, + spat->spat_short))) + goto nope; +#endif + if (s && spat->spat_regexp->regback >= 0) { + ++spat->spat_short->str_u.str_useful; + s -= spat->spat_regexp->regback; + if (s < m) + s = m; + } + else + s = m; + } + else if (!multiline && (*spat->spat_short->str_ptr != *s || + bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) )) + goto nope; + if (--spat->spat_short->str_u.str_useful < 0) { + str_free(spat->spat_short); + spat->spat_short = Nullstr; /* opt is being useless */ + } + } + once = !(rspat->spat_flags & SPAT_GLOBAL); + if (rspat->spat_flags & SPAT_CONST) { /* known replacement string? */ + if ((rspat->spat_repl[1].arg_type & A_MASK) == A_SINGLE) + dstr = rspat->spat_repl[1].arg_ptr.arg_str; + else { /* constant over loop, anyway */ + (void)eval(rspat->spat_repl,G_SCALAR,sp); + dstr = stack->ary_array[sp+1]; + } + c = str_get(dstr); + clen = dstr->str_cur; + if (clen <= spat->spat_regexp->minlen) { + /* can do inplace substitution */ + if (regexec(spat->spat_regexp, s, strend, orig, 0, + TARG->str_pok & SP_STUDIED ? TARG : Nullstr, safebase)) { + if (spat->spat_regexp->subbase) /* oops, no we can't */ + goto long_way; + d = s; + lastspat = spat; + TARG->str_pok = SP_VALID; /* disable possible screamer */ + if (once) { + m = spat->spat_regexp->startp[0]; + d = spat->spat_regexp->endp[0]; + s = orig; + if (m - s > strend - d) { /* faster to shorten from end */ + if (clen) { + Copy(c, m, clen, char); + m += clen; + } + i = strend - d; + if (i > 0) { + Move(d, m, i, char); + m += i; + } + *m = '\0'; + TARG->str_cur = m - s; + STABSET(TARG); + str_numset(ARGTARG, 1.0); + stack->ary_array[++sp] = ARGTARG; + return sp; + } + /*SUPPRESS 560*/ + else if (i = m - s) { /* faster from front */ + d -= clen; + m = d; + str_chop(TARG,d-i); + s += i; + while (i--) + *--d = *--s; + if (clen) + Copy(c, m, clen, char); + STABSET(TARG); + str_numset(ARGTARG, 1.0); + stack->ary_array[++sp] = ARGTARG; + return sp; + } + else if (clen) { + d -= clen; + str_chop(TARG,d); + Copy(c,d,clen,char); + STABSET(TARG); + str_numset(ARGTARG, 1.0); + stack->ary_array[++sp] = ARGTARG; + return sp; + } + else { + str_chop(TARG,d); + STABSET(TARG); + str_numset(ARGTARG, 1.0); + stack->ary_array[++sp] = ARGTARG; + return sp; + } + /* NOTREACHED */ + } + do { + if (iters++ > maxiters) + fatal("Substitution loop"); + m = spat->spat_regexp->startp[0]; + /*SUPPRESS 560*/ + if (i = m - s) { + if (s != d) + Move(s,d,i,char); + d += i; + } + if (clen) { + Copy(c,d,clen,char); + d += clen; + } + s = spat->spat_regexp->endp[0]; + } while (regexec(spat->spat_regexp, s, strend, orig, s == m, + Nullstr, TRUE)); /* (don't match same null twice) */ + if (s != d) { + i = strend - s; + TARG->str_cur = d - TARG->str_ptr + i; + Move(s,d,i+1,char); /* include the Null */ + } + STABSET(TARG); + str_numset(ARGTARG, (double)iters); + stack->ary_array[++sp] = ARGTARG; + return sp; + } + str_numset(ARGTARG, 0.0); + stack->ary_array[++sp] = ARGTARG; + return sp; + } + } + else + c = Nullch; + if (regexec(spat->spat_regexp, s, strend, orig, 0, + TARG->str_pok & SP_STUDIED ? TARG : Nullstr, safebase)) { + long_way: + dstr = Str_new(25,str_len(TARG)); + str_nset(dstr,m,s-m); + if (spat->spat_regexp->subbase) + curspat = spat; + lastspat = spat; + do { + if (iters++ > maxiters) + fatal("Substitution loop"); + if (spat->spat_regexp->subbase + && spat->spat_regexp->subbase != orig) { + m = s; + s = orig; + orig = spat->spat_regexp->subbase; + s = orig + (m - s); + strend = s + (strend - m); + } + m = spat->spat_regexp->startp[0]; + str_ncat(dstr,s,m-s); + s = spat->spat_regexp->endp[0]; + if (c) { + if (clen) + str_ncat(dstr,c,clen); + } + else { + char *mysubbase = spat->spat_regexp->subbase; + + spat->spat_regexp->subbase = Nullch; /* so recursion works */ + (void)eval(rspat->spat_repl,G_SCALAR,sp); + str_scat(dstr,stack->ary_array[sp+1]); + if (spat->spat_regexp->subbase) + Safefree(spat->spat_regexp->subbase); + spat->spat_regexp->subbase = mysubbase; + } + if (once) + break; + } while (regexec(spat->spat_regexp, s, strend, orig, s == m, Nullstr, + safebase)); + str_ncat(dstr,s,strend - s); + str_replace(TARG,dstr); + STABSET(TARG); + str_numset(ARGTARG, (double)iters); + stack->ary_array[++sp] = ARGTARG; + return sp; + } + str_numset(ARGTARG, 0.0); + stack->ary_array[++sp] = ARGTARG; + return sp; + +nope: + ++spat->spat_short->str_u.str_useful; + str_numset(ARGTARG, 0.0); + stack->ary_array[++sp] = ARGTARG; + return sp; +} +#ifdef BUGGY_MSC + #pragma intrinsic(memcmp) +#endif /* BUGGY_MSC */ + |