77dbde18c5d1272cbb8deef08c3d69315396bc50
[perl.git] / do / subst
1 int
2 do_subst(TARG,arg,sp)
3 STR *TARG;
4 ARG *arg;
5 int sp;
6 {
7     register SPAT *spat;
8     SPAT *rspat;
9     register STR *dstr;
10     register char *s = str_get(TARG);
11     char *strend = s + TARG->str_cur;
12     register char *m;
13     char *c;
14     register char *d;
15     int clen;
16     int iters = 0;
17     int maxiters = (strend - s) + 10;
18     register int i;
19     bool once;
20     char *orig;
21     int safebase;
22
23     rspat = spat = arg[2].arg_ptr.arg_spat;
24     if (!spat || !s)
25         fatal("panic: do_subst");
26     else if (spat->spat_runtime) {
27         nointrp = "|)";
28         (void)eval(spat->spat_runtime,G_SCALAR,sp);
29         m = str_get(dstr = stack->ary_array[sp+1]);
30         nointrp = "";
31         if (spat->spat_regexp) {
32             regfree(spat->spat_regexp);
33             spat->spat_regexp = Null(REGEXP*);  /* required if regcomp pukes */
34         }
35         spat->spat_regexp = regcomp(m,m+dstr->str_cur,
36             spat->spat_flags & SPAT_FOLD);
37         if (spat->spat_flags & SPAT_KEEP) {
38             if (!(spat->spat_flags & SPAT_FOLD))
39                 scanconst(spat, m, dstr->str_cur);
40             arg_free(spat->spat_runtime);       /* it won't change, so */
41             spat->spat_runtime = Nullarg;       /* no point compiling again */
42             hoistmust(spat);
43             if (curcmd->c_expr && (curcmd->c_flags & CF_OPTIMIZE) == CFT_EVAL) {
44                 curcmd->c_flags &= ~CF_OPTIMIZE;
45                 opt_arg(curcmd, 1, curcmd->c_type == C_EXPR);
46             }
47         }
48     }
49 #ifdef DEBUGGING
50     if (debug & 8) {
51         deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
52     }
53 #endif
54     safebase = ((!spat->spat_regexp || !spat->spat_regexp->nparens) &&
55       !sawampersand);
56     if (!spat->spat_regexp->prelen && lastspat)
57         spat = lastspat;
58     orig = m = s;
59     if (hint) {
60         if (hint < s || hint > strend)
61             fatal("panic: hint in do_match");
62         s = hint;
63         hint = Nullch;
64         if (spat->spat_regexp->regback >= 0) {
65             s -= spat->spat_regexp->regback;
66             if (s < m)
67                 s = m;
68         }
69         else
70             s = m;
71     }
72     else if (spat->spat_short) {
73         if (spat->spat_flags & SPAT_SCANFIRST) {
74             if (TARG->str_pok & SP_STUDIED) {
75                 if (screamfirst[spat->spat_short->str_rare] < 0)
76                     goto nope;
77                 else if (!(s = screaminstr(TARG,spat->spat_short)))
78                     goto nope;
79             }
80 #ifndef lint
81             else if (!(s = fbminstr((unsigned char*)s, (unsigned char*)strend,
82               spat->spat_short)))
83                 goto nope;
84 #endif
85             if (s && spat->spat_regexp->regback >= 0) {
86                 ++spat->spat_short->str_u.str_useful;
87                 s -= spat->spat_regexp->regback;
88                 if (s < m)
89                     s = m;
90             }
91             else
92                 s = m;
93         }
94         else if (!multiline && (*spat->spat_short->str_ptr != *s ||
95           bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) ))
96             goto nope;
97         if (--spat->spat_short->str_u.str_useful < 0) {
98             str_free(spat->spat_short);
99             spat->spat_short = Nullstr; /* opt is being useless */
100         }
101     }
102     once = !(rspat->spat_flags & SPAT_GLOBAL);
103     if (rspat->spat_flags & SPAT_CONST) {       /* known replacement string? */
104         if ((rspat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
105             dstr = rspat->spat_repl[1].arg_ptr.arg_str;
106         else {                                  /* constant over loop, anyway */
107             (void)eval(rspat->spat_repl,G_SCALAR,sp);
108             dstr = stack->ary_array[sp+1];
109         }
110         c = str_get(dstr);
111         clen = dstr->str_cur;
112         if (clen <= spat->spat_regexp->minlen) {
113                                         /* can do inplace substitution */
114             if (regexec(spat->spat_regexp, s, strend, orig, 0,
115               TARG->str_pok & SP_STUDIED ? TARG : Nullstr, safebase)) {
116                 if (spat->spat_regexp->subbase) /* oops, no we can't */
117                     goto long_way;
118                 d = s;
119                 lastspat = spat;
120                 TARG->str_pok = SP_VALID;       /* disable possible screamer */
121                 if (once) {
122                     m = spat->spat_regexp->startp[0];
123                     d = spat->spat_regexp->endp[0];
124                     s = orig;
125                     if (m - s > strend - d) {   /* faster to shorten from end */
126                         if (clen) {
127                             Copy(c, m, clen, char);
128                             m += clen;
129                         }
130                         i = strend - d;
131                         if (i > 0) {
132                             Move(d, m, i, char);
133                             m += i;
134                         }
135                         *m = '\0';
136                         TARG->str_cur = m - s;
137                         STABSET(TARG);
138                         str_numset(ARGTARG, 1.0);
139                         stack->ary_array[++sp] = ARGTARG;
140                         return sp;
141                     }
142                     /*SUPPRESS 560*/
143                     else if (i = m - s) {       /* faster from front */
144                         d -= clen;
145                         m = d;
146                         str_chop(TARG,d-i);
147                         s += i;
148                         while (i--)
149                             *--d = *--s;
150                         if (clen)
151                             Copy(c, m, clen, char);
152                         STABSET(TARG);
153                         str_numset(ARGTARG, 1.0);
154                         stack->ary_array[++sp] = ARGTARG;
155                         return sp;
156                     }
157                     else if (clen) {
158                         d -= clen;
159                         str_chop(TARG,d);
160                         Copy(c,d,clen,char);
161                         STABSET(TARG);
162                         str_numset(ARGTARG, 1.0);
163                         stack->ary_array[++sp] = ARGTARG;
164                         return sp;
165                     }
166                     else {
167                         str_chop(TARG,d);
168                         STABSET(TARG);
169                         str_numset(ARGTARG, 1.0);
170                         stack->ary_array[++sp] = ARGTARG;
171                         return sp;
172                     }
173                     /* NOTREACHED */
174                 }
175                 do {
176                     if (iters++ > maxiters)
177                         fatal("Substitution loop");
178                     m = spat->spat_regexp->startp[0];
179                     /*SUPPRESS 560*/
180                     if (i = m - s) {
181                         if (s != d)
182                             Move(s,d,i,char);
183                         d += i;
184                     }
185                     if (clen) {
186                         Copy(c,d,clen,char);
187                         d += clen;
188                     }
189                     s = spat->spat_regexp->endp[0];
190                 } while (regexec(spat->spat_regexp, s, strend, orig, s == m,
191                     Nullstr, TRUE));    /* (don't match same null twice) */
192                 if (s != d) {
193                     i = strend - s;
194                     TARG->str_cur = d - TARG->str_ptr + i;
195                     Move(s,d,i+1,char);         /* include the Null */
196                 }
197                 STABSET(TARG);
198                 str_numset(ARGTARG, (double)iters);
199                 stack->ary_array[++sp] = ARGTARG;
200                 return sp;
201             }
202             str_numset(ARGTARG, 0.0);
203             stack->ary_array[++sp] = ARGTARG;
204             return sp;
205         }
206     }
207     else
208         c = Nullch;
209     if (regexec(spat->spat_regexp, s, strend, orig, 0,
210       TARG->str_pok & SP_STUDIED ? TARG : Nullstr, safebase)) {
211     long_way:
212         dstr = Str_new(25,str_len(TARG));
213         str_nset(dstr,m,s-m);
214         if (spat->spat_regexp->subbase)
215             curspat = spat;
216         lastspat = spat;
217         do {
218             if (iters++ > maxiters)
219                 fatal("Substitution loop");
220             if (spat->spat_regexp->subbase
221               && spat->spat_regexp->subbase != orig) {
222                 m = s;
223                 s = orig;
224                 orig = spat->spat_regexp->subbase;
225                 s = orig + (m - s);
226                 strend = s + (strend - m);
227             }
228             m = spat->spat_regexp->startp[0];
229             str_ncat(dstr,s,m-s);
230             s = spat->spat_regexp->endp[0];
231             if (c) {
232                 if (clen)
233                     str_ncat(dstr,c,clen);
234             }
235             else {
236                 char *mysubbase = spat->spat_regexp->subbase;
237
238                 spat->spat_regexp->subbase = Nullch;    /* so recursion works */
239                 (void)eval(rspat->spat_repl,G_SCALAR,sp);
240                 str_scat(dstr,stack->ary_array[sp+1]);
241                 if (spat->spat_regexp->subbase)
242                     Safefree(spat->spat_regexp->subbase);
243                 spat->spat_regexp->subbase = mysubbase;
244             }
245             if (once)
246                 break;
247         } while (regexec(spat->spat_regexp, s, strend, orig, s == m, Nullstr,
248             safebase));
249         str_ncat(dstr,s,strend - s);
250         str_replace(TARG,dstr);
251         STABSET(TARG);
252         str_numset(ARGTARG, (double)iters);
253         stack->ary_array[++sp] = ARGTARG;
254         return sp;
255     }
256     str_numset(ARGTARG, 0.0);
257     stack->ary_array[++sp] = ARGTARG;
258     return sp;
259
260 nope:
261     ++spat->spat_short->str_u.str_useful;
262     str_numset(ARGTARG, 0.0);
263     stack->ary_array[++sp] = ARGTARG;
264     return sp;
265 }
266 #ifdef BUGGY_MSC
267  #pragma intrinsic(memcmp)
268 #endif /* BUGGY_MSC */
269