Commit | Line | Data |
f0fcb552 |
1 | /* $RCSfile: str.c,v $$Revision: 4.0.1.4 $$Date: 91/11/05 18:40:51 $ |
a687059c |
2 | * |
d48672a2 |
3 | * Copyright (c) 1991, Larry Wall |
a687059c |
4 | * |
d48672a2 |
5 | * You may distribute under the terms of either the GNU General Public |
6 | * License or the Artistic License, as specified in the README file. |
8d063cd8 |
7 | * |
8 | * $Log: str.c,v $ |
f0fcb552 |
9 | * Revision 4.0.1.4 91/11/05 18:40:51 lwall |
10 | * patch11: $foo .= <BAR> could overrun malloced memory |
11 | * patch11: \$ didn't always make it through double-quoter to regexp routines |
12 | * patch11: prepared for ctype implementations that don't define isascii() |
13 | * |
1462b684 |
14 | * Revision 4.0.1.3 91/06/10 01:27:54 lwall |
15 | * patch10: $) and $| incorrectly handled in run-time patterns |
16 | * |
d48672a2 |
17 | * Revision 4.0.1.2 91/06/07 11:58:13 lwall |
18 | * patch4: new copyright notice |
19 | * patch4: taint check on undefined string could cause core dump |
20 | * |
35c8bce7 |
21 | * Revision 4.0.1.1 91/04/12 09:15:30 lwall |
22 | * patch1: fixed undefined environ problem |
23 | * patch1: substr($ENV{"PATH"},0,0) = "/foo:" didn't modify environment |
24 | * patch1: $foo .= <BAR> could cause core dump for certain lengths of $foo |
25 | * |
fe14fcc3 |
26 | * Revision 4.0 91/03/20 01:39:55 lwall |
27 | * 4.0 baseline. |
8d063cd8 |
28 | * |
29 | */ |
30 | |
8d063cd8 |
31 | #include "EXTERN.h" |
8d063cd8 |
32 | #include "perl.h" |
a687059c |
33 | #include "perly.h" |
8d063cd8 |
34 | |
a687059c |
35 | #ifndef str_get |
36 | char * |
37 | str_get(str) |
38 | STR *str; |
8d063cd8 |
39 | { |
a687059c |
40 | #ifdef TAINT |
41 | tainted |= str->str_tainted; |
42 | #endif |
43 | return str->str_pok ? str->str_ptr : str_2ptr(str); |
44 | } |
45 | #endif |
8d063cd8 |
46 | |
a687059c |
47 | /* dlb ... guess we have a "crippled cc". |
48 | * dlb the following functions are usually macros. |
49 | */ |
50 | #ifndef str_true |
51 | str_true(Str) |
52 | STR *Str; |
53 | { |
54 | if (Str->str_pok) { |
55 | if (*Str->str_ptr > '0' || |
56 | Str->str_cur > 1 || |
57 | (Str->str_cur && *Str->str_ptr != '0')) |
58 | return 1; |
59 | return 0; |
8d063cd8 |
60 | } |
a687059c |
61 | if (Str->str_nok) |
62 | return (Str->str_u.str_nval != 0.0); |
63 | return 0; |
64 | } |
65 | #endif /* str_true */ |
8d063cd8 |
66 | |
a687059c |
67 | #ifndef str_gnum |
68 | double str_gnum(Str) |
69 | STR *Str; |
70 | { |
71 | #ifdef TAINT |
72 | tainted |= Str->str_tainted; |
73 | #endif /* TAINT*/ |
74 | if (Str->str_nok) |
75 | return Str->str_u.str_nval; |
76 | return str_2num(Str); |
77 | } |
78 | #endif /* str_gnum */ |
79 | /* dlb ... end of crutch */ |
8d063cd8 |
80 | |
a687059c |
81 | char * |
82 | str_grow(str,newlen) |
83 | register STR *str; |
e929a76b |
84 | #ifndef MSDOS |
a687059c |
85 | register int newlen; |
e929a76b |
86 | #else |
87 | unsigned long newlen; |
88 | #endif |
a687059c |
89 | { |
90 | register char *s = str->str_ptr; |
91 | |
e929a76b |
92 | #ifdef MSDOS |
93 | if (newlen >= 0x10000) { |
94 | fprintf(stderr, "Allocation too large: %lx\n", newlen); |
95 | exit(1); |
96 | } |
97 | #endif /* MSDOS */ |
a687059c |
98 | if (str->str_state == SS_INCR) { /* data before str_ptr? */ |
99 | str->str_len += str->str_u.str_useful; |
100 | str->str_ptr -= str->str_u.str_useful; |
101 | str->str_u.str_useful = 0L; |
102 | bcopy(s, str->str_ptr, str->str_cur+1); |
103 | s = str->str_ptr; |
104 | str->str_state = SS_NORM; /* normal again */ |
105 | if (newlen > str->str_len) |
106 | newlen += 10 * (newlen - str->str_cur); /* avoid copy each time */ |
107 | } |
108 | if (newlen > str->str_len) { /* need more room? */ |
109 | if (str->str_len) |
110 | Renew(s,newlen,char); |
111 | else |
112 | New(703,s,newlen,char); |
113 | str->str_ptr = s; |
114 | str->str_len = newlen; |
8d063cd8 |
115 | } |
a687059c |
116 | return s; |
8d063cd8 |
117 | } |
118 | |
119 | str_numset(str,num) |
120 | register STR *str; |
121 | double num; |
122 | { |
0f85fab0 |
123 | if (str->str_pok) { |
124 | str->str_pok = 0; /* invalidate pointer */ |
125 | if (str->str_state == SS_INCR) |
e929a76b |
126 | Str_Grow(str,0); |
0f85fab0 |
127 | } |
a687059c |
128 | str->str_u.str_nval = num; |
129 | str->str_state = SS_NORM; |
a687059c |
130 | str->str_nok = 1; /* validate number */ |
131 | #ifdef TAINT |
132 | str->str_tainted = tainted; |
133 | #endif |
8d063cd8 |
134 | } |
135 | |
136 | char * |
137 | str_2ptr(str) |
138 | register STR *str; |
139 | { |
140 | register char *s; |
378cc40b |
141 | int olderrno; |
8d063cd8 |
142 | |
143 | if (!str) |
144 | return ""; |
8d063cd8 |
145 | if (str->str_nok) { |
9f68db38 |
146 | STR_GROW(str, 30); |
a687059c |
147 | s = str->str_ptr; |
378cc40b |
148 | olderrno = errno; /* some Xenix systems wipe out errno here */ |
149 | #if defined(scs) && defined(ns32000) |
a687059c |
150 | gcvt(str->str_u.str_nval,20,s); |
378cc40b |
151 | #else |
152 | #ifdef apollo |
a687059c |
153 | if (str->str_u.str_nval == 0.0) |
154 | (void)strcpy(s,"0"); |
378cc40b |
155 | else |
156 | #endif /*apollo*/ |
a687059c |
157 | (void)sprintf(s,"%.20g",str->str_u.str_nval); |
378cc40b |
158 | #endif /*scs*/ |
159 | errno = olderrno; |
8d063cd8 |
160 | while (*s) s++; |
9f68db38 |
161 | #ifdef hcx |
162 | if (s[-1] == '.') |
163 | s--; |
164 | #endif |
8d063cd8 |
165 | } |
a687059c |
166 | else { |
167 | if (str == &str_undef) |
168 | return No; |
169 | if (dowarn) |
170 | warn("Use of uninitialized variable"); |
9f68db38 |
171 | STR_GROW(str, 30); |
a687059c |
172 | s = str->str_ptr; |
173 | } |
8d063cd8 |
174 | *s = '\0'; |
175 | str->str_cur = s - str->str_ptr; |
176 | str->str_pok = 1; |
177 | #ifdef DEBUGGING |
178 | if (debug & 32) |
179 | fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr); |
180 | #endif |
181 | return str->str_ptr; |
182 | } |
183 | |
184 | double |
185 | str_2num(str) |
186 | register STR *str; |
187 | { |
188 | if (!str) |
189 | return 0.0; |
0f85fab0 |
190 | if (str->str_state == SS_INCR) |
e929a76b |
191 | Str_Grow(str,0); /* just force copy down */ |
a687059c |
192 | str->str_state = SS_NORM; |
8d063cd8 |
193 | if (str->str_len && str->str_pok) |
a687059c |
194 | str->str_u.str_nval = atof(str->str_ptr); |
195 | else { |
196 | if (str == &str_undef) |
197 | return 0.0; |
378cc40b |
198 | if (dowarn) |
a687059c |
199 | warn("Use of uninitialized variable"); |
200 | str->str_u.str_nval = 0.0; |
378cc40b |
201 | } |
8d063cd8 |
202 | str->str_nok = 1; |
203 | #ifdef DEBUGGING |
204 | if (debug & 32) |
a687059c |
205 | fprintf(stderr,"0x%lx num(%g)\n",str,str->str_u.str_nval); |
8d063cd8 |
206 | #endif |
a687059c |
207 | return str->str_u.str_nval; |
8d063cd8 |
208 | } |
209 | |
34de22dd |
210 | /* Note: str_sset() should not be called with a source string that needs |
211 | * be reused, since it may destroy the source string if it is marked |
212 | * as temporary. |
213 | */ |
214 | |
8d063cd8 |
215 | str_sset(dstr,sstr) |
216 | STR *dstr; |
217 | register STR *sstr; |
218 | { |
a687059c |
219 | #ifdef TAINT |
0f85fab0 |
220 | if (sstr) |
221 | tainted |= sstr->str_tainted; |
a687059c |
222 | #endif |
395c3793 |
223 | if (sstr == dstr || dstr == &str_undef) |
9f68db38 |
224 | return; |
8d063cd8 |
225 | if (!sstr) |
a687059c |
226 | dstr->str_pok = dstr->str_nok = 0; |
227 | else if (sstr->str_pok) { |
34de22dd |
228 | |
229 | /* |
230 | * Check to see if we can just swipe the string. If so, it's a |
231 | * possible small lose on short strings, but a big win on long ones. |
4e8eb4f0 |
232 | * It might even be a win on short strings if dstr->str_ptr |
233 | * has to be allocated and sstr->str_ptr has to be freed. |
34de22dd |
234 | */ |
235 | |
236 | if (sstr->str_pok & SP_TEMP) { /* slated for free anyway? */ |
4e8eb4f0 |
237 | if (dstr->str_ptr) { |
238 | if (dstr->str_state == SS_INCR) |
239 | dstr->str_ptr -= dstr->str_u.str_useful; |
34de22dd |
240 | Safefree(dstr->str_ptr); |
4e8eb4f0 |
241 | } |
242 | dstr->str_ptr = sstr->str_ptr; |
243 | dstr->str_len = sstr->str_len; |
244 | dstr->str_cur = sstr->str_cur; |
245 | dstr->str_state = sstr->str_state; |
246 | dstr->str_pok = sstr->str_pok & ~SP_TEMP; |
247 | #ifdef TAINT |
248 | dstr->str_tainted = sstr->str_tainted; |
34de22dd |
249 | #endif |
4e8eb4f0 |
250 | sstr->str_ptr = Nullch; |
251 | sstr->str_len = 0; |
252 | sstr->str_pok = 0; /* wipe out any weird flags */ |
253 | sstr->str_state = 0; /* so sstr frees uneventfully */ |
a687059c |
254 | } |
27e2fb84 |
255 | else { /* have to copy actual string */ |
256 | if (dstr->str_ptr) { |
257 | if (dstr->str_state == SS_INCR) { |
258 | Str_Grow(dstr,0); |
259 | } |
260 | } |
34de22dd |
261 | str_nset(dstr,sstr->str_ptr,sstr->str_cur); |
27e2fb84 |
262 | } |
f0fcb552 |
263 | /*SUPPRESS 560*/ |
4e8eb4f0 |
264 | if (dstr->str_nok = sstr->str_nok) |
265 | dstr->str_u.str_nval = sstr->str_u.str_nval; |
266 | else { |
267 | #ifdef STRUCTCOPY |
268 | dstr->str_u = sstr->str_u; |
269 | #else |
270 | dstr->str_u.str_nval = sstr->str_u.str_nval; |
271 | #endif |
272 | if (dstr->str_cur == sizeof(STBP)) { |
273 | char *tmps = dstr->str_ptr; |
a687059c |
274 | |
34de22dd |
275 | if (*tmps == 'S' && bcmp(tmps,"StB",4) == 0) { |
276 | if (!dstr->str_magic) { |
277 | dstr->str_magic = str_smake(sstr->str_magic); |
278 | dstr->str_magic->str_rare = 'X'; |
279 | } |
395c3793 |
280 | } |
a687059c |
281 | } |
282 | } |
283 | } |
284 | else if (sstr->str_nok) |
285 | str_numset(dstr,sstr->str_u.str_nval); |
663a0e37 |
286 | else { |
0f85fab0 |
287 | if (dstr->str_state == SS_INCR) |
e929a76b |
288 | Str_Grow(dstr,0); /* just force copy down */ |
0f85fab0 |
289 | |
663a0e37 |
290 | #ifdef STRUCTCOPY |
291 | dstr->str_u = sstr->str_u; |
292 | #else |
293 | dstr->str_u.str_nval = sstr->str_u.str_nval; |
294 | #endif |
a687059c |
295 | dstr->str_pok = dstr->str_nok = 0; |
663a0e37 |
296 | } |
8d063cd8 |
297 | } |
298 | |
299 | str_nset(str,ptr,len) |
300 | register STR *str; |
301 | register char *ptr; |
e929a76b |
302 | register STRLEN len; |
8d063cd8 |
303 | { |
395c3793 |
304 | if (str == &str_undef) |
305 | return; |
a687059c |
306 | STR_GROW(str, len + 1); |
0f85fab0 |
307 | if (ptr) |
308 | (void)bcopy(ptr,str->str_ptr,len); |
8d063cd8 |
309 | str->str_cur = len; |
310 | *(str->str_ptr+str->str_cur) = '\0'; |
311 | str->str_nok = 0; /* invalidate number */ |
312 | str->str_pok = 1; /* validate pointer */ |
a687059c |
313 | #ifdef TAINT |
314 | str->str_tainted = tainted; |
315 | #endif |
8d063cd8 |
316 | } |
317 | |
318 | str_set(str,ptr) |
319 | register STR *str; |
320 | register char *ptr; |
321 | { |
e929a76b |
322 | register STRLEN len; |
8d063cd8 |
323 | |
395c3793 |
324 | if (str == &str_undef) |
325 | return; |
8d063cd8 |
326 | if (!ptr) |
327 | ptr = ""; |
328 | len = strlen(ptr); |
a687059c |
329 | STR_GROW(str, len + 1); |
330 | (void)bcopy(ptr,str->str_ptr,len+1); |
8d063cd8 |
331 | str->str_cur = len; |
332 | str->str_nok = 0; /* invalidate number */ |
333 | str->str_pok = 1; /* validate pointer */ |
a687059c |
334 | #ifdef TAINT |
335 | str->str_tainted = tainted; |
336 | #endif |
8d063cd8 |
337 | } |
338 | |
339 | str_chop(str,ptr) /* like set but assuming ptr is in str */ |
340 | register STR *str; |
341 | register char *ptr; |
342 | { |
e929a76b |
343 | register STRLEN delta; |
a687059c |
344 | |
fe14fcc3 |
345 | if (!ptr || !(str->str_pok)) |
346 | return; |
a687059c |
347 | delta = ptr - str->str_ptr; |
348 | str->str_len -= delta; |
349 | str->str_cur -= delta; |
350 | str->str_ptr += delta; |
351 | if (str->str_state == SS_INCR) |
352 | str->str_u.str_useful += delta; |
353 | else { |
354 | str->str_u.str_useful = delta; |
355 | str->str_state = SS_INCR; |
356 | } |
8d063cd8 |
357 | str->str_nok = 0; /* invalidate number */ |
a687059c |
358 | str->str_pok = 1; /* validate pointer (and unstudy str) */ |
8d063cd8 |
359 | } |
360 | |
361 | str_ncat(str,ptr,len) |
362 | register STR *str; |
363 | register char *ptr; |
e929a76b |
364 | register STRLEN len; |
8d063cd8 |
365 | { |
395c3793 |
366 | if (str == &str_undef) |
367 | return; |
8d063cd8 |
368 | if (!(str->str_pok)) |
a687059c |
369 | (void)str_2ptr(str); |
370 | STR_GROW(str, str->str_cur + len + 1); |
371 | (void)bcopy(ptr,str->str_ptr+str->str_cur,len); |
8d063cd8 |
372 | str->str_cur += len; |
373 | *(str->str_ptr+str->str_cur) = '\0'; |
374 | str->str_nok = 0; /* invalidate number */ |
375 | str->str_pok = 1; /* validate pointer */ |
a687059c |
376 | #ifdef TAINT |
377 | str->str_tainted |= tainted; |
378 | #endif |
8d063cd8 |
379 | } |
380 | |
381 | str_scat(dstr,sstr) |
382 | STR *dstr; |
383 | register STR *sstr; |
384 | { |
d48672a2 |
385 | if (!sstr) |
386 | return; |
a687059c |
387 | #ifdef TAINT |
388 | tainted |= sstr->str_tainted; |
389 | #endif |
8d063cd8 |
390 | if (!(sstr->str_pok)) |
a687059c |
391 | (void)str_2ptr(sstr); |
8d063cd8 |
392 | if (sstr) |
393 | str_ncat(dstr,sstr->str_ptr,sstr->str_cur); |
394 | } |
395 | |
396 | str_cat(str,ptr) |
397 | register STR *str; |
398 | register char *ptr; |
399 | { |
e929a76b |
400 | register STRLEN len; |
8d063cd8 |
401 | |
395c3793 |
402 | if (str == &str_undef) |
403 | return; |
8d063cd8 |
404 | if (!ptr) |
405 | return; |
406 | if (!(str->str_pok)) |
a687059c |
407 | (void)str_2ptr(str); |
8d063cd8 |
408 | len = strlen(ptr); |
a687059c |
409 | STR_GROW(str, str->str_cur + len + 1); |
410 | (void)bcopy(ptr,str->str_ptr+str->str_cur,len+1); |
8d063cd8 |
411 | str->str_cur += len; |
412 | str->str_nok = 0; /* invalidate number */ |
413 | str->str_pok = 1; /* validate pointer */ |
a687059c |
414 | #ifdef TAINT |
415 | str->str_tainted |= tainted; |
416 | #endif |
8d063cd8 |
417 | } |
418 | |
419 | char * |
a687059c |
420 | str_append_till(str,from,fromend,delim,keeplist) |
8d063cd8 |
421 | register STR *str; |
422 | register char *from; |
a687059c |
423 | register char *fromend; |
8d063cd8 |
424 | register int delim; |
425 | char *keeplist; |
426 | { |
427 | register char *to; |
e929a76b |
428 | register STRLEN len; |
8d063cd8 |
429 | |
395c3793 |
430 | if (str == &str_undef) |
431 | return Nullch; |
8d063cd8 |
432 | if (!from) |
433 | return Nullch; |
a687059c |
434 | len = fromend - from; |
435 | STR_GROW(str, str->str_cur + len + 1); |
8d063cd8 |
436 | str->str_nok = 0; /* invalidate number */ |
437 | str->str_pok = 1; /* validate pointer */ |
438 | to = str->str_ptr+str->str_cur; |
a687059c |
439 | for (; from < fromend; from++,to++) { |
440 | if (*from == '\\' && from+1 < fromend && delim != '\\') { |
8d063cd8 |
441 | if (!keeplist) { |
442 | if (from[1] == delim || from[1] == '\\') |
443 | from++; |
444 | else |
445 | *to++ = *from++; |
446 | } |
a687059c |
447 | else if (from[1] && index(keeplist,from[1])) |
8d063cd8 |
448 | *to++ = *from++; |
449 | else |
450 | from++; |
451 | } |
452 | else if (*from == delim) |
453 | break; |
454 | *to = *from; |
455 | } |
456 | *to = '\0'; |
457 | str->str_cur = to - str->str_ptr; |
458 | return from; |
459 | } |
460 | |
461 | STR * |
a687059c |
462 | #ifdef LEAKTEST |
463 | str_new(x,len) |
464 | int x; |
465 | #else |
8d063cd8 |
466 | str_new(len) |
a687059c |
467 | #endif |
e929a76b |
468 | STRLEN len; |
8d063cd8 |
469 | { |
470 | register STR *str; |
471 | |
472 | if (freestrroot) { |
473 | str = freestrroot; |
a687059c |
474 | freestrroot = str->str_magic; |
475 | str->str_magic = Nullstr; |
476 | str->str_state = SS_NORM; |
8d063cd8 |
477 | } |
478 | else { |
a687059c |
479 | Newz(700+x,str,1,STR); |
8d063cd8 |
480 | } |
481 | if (len) |
a687059c |
482 | STR_GROW(str, len + 1); |
8d063cd8 |
483 | return str; |
484 | } |
485 | |
486 | void |
a687059c |
487 | str_magic(str, stab, how, name, namlen) |
8d063cd8 |
488 | register STR *str; |
a687059c |
489 | STAB *stab; |
490 | int how; |
491 | char *name; |
e929a76b |
492 | STRLEN namlen; |
a687059c |
493 | { |
395c3793 |
494 | if (str == &str_undef || str->str_magic) |
a687059c |
495 | return; |
496 | str->str_magic = Str_new(75,namlen); |
497 | str = str->str_magic; |
498 | str->str_u.str_stab = stab; |
499 | str->str_rare = how; |
500 | if (name) |
501 | str_nset(str,name,namlen); |
502 | } |
503 | |
504 | void |
505 | str_insert(bigstr,offset,len,little,littlelen) |
506 | STR *bigstr; |
e929a76b |
507 | STRLEN offset; |
508 | STRLEN len; |
a687059c |
509 | char *little; |
e929a76b |
510 | STRLEN littlelen; |
8d063cd8 |
511 | { |
a687059c |
512 | register char *big; |
513 | register char *mid; |
514 | register char *midend; |
515 | register char *bigend; |
516 | register int i; |
517 | |
395c3793 |
518 | if (bigstr == &str_undef) |
519 | return; |
79a0689e |
520 | bigstr->str_nok = 0; |
521 | bigstr->str_pok = SP_VALID; /* disable possible screamer */ |
522 | |
a687059c |
523 | i = littlelen - len; |
524 | if (i > 0) { /* string might grow */ |
525 | STR_GROW(bigstr, bigstr->str_cur + i + 1); |
526 | big = bigstr->str_ptr; |
527 | mid = big + offset + len; |
528 | midend = bigend = big + bigstr->str_cur; |
529 | bigend += i; |
530 | *bigend = '\0'; |
531 | while (midend > mid) /* shove everything down */ |
532 | *--bigend = *--midend; |
533 | (void)bcopy(little,big+offset,littlelen); |
534 | bigstr->str_cur += i; |
35c8bce7 |
535 | STABSET(bigstr); |
a687059c |
536 | return; |
537 | } |
538 | else if (i == 0) { |
539 | (void)bcopy(little,bigstr->str_ptr+offset,len); |
35c8bce7 |
540 | STABSET(bigstr); |
a687059c |
541 | return; |
542 | } |
543 | |
544 | big = bigstr->str_ptr; |
545 | mid = big + offset; |
546 | midend = mid + len; |
547 | bigend = big + bigstr->str_cur; |
548 | |
549 | if (midend > bigend) |
550 | fatal("panic: str_insert"); |
551 | |
a687059c |
552 | if (mid - big > bigend - midend) { /* faster to shorten from end */ |
553 | if (littlelen) { |
554 | (void)bcopy(little, mid, littlelen); |
555 | mid += littlelen; |
556 | } |
557 | i = bigend - midend; |
558 | if (i > 0) { |
559 | (void)bcopy(midend, mid, i); |
560 | mid += i; |
561 | } |
562 | *mid = '\0'; |
563 | bigstr->str_cur = mid - big; |
564 | } |
f0fcb552 |
565 | /*SUPPRESS 560*/ |
a687059c |
566 | else if (i = mid - big) { /* faster from front */ |
567 | midend -= littlelen; |
568 | mid = midend; |
569 | str_chop(bigstr,midend-i); |
570 | big += i; |
571 | while (i--) |
572 | *--midend = *--big; |
573 | if (littlelen) |
574 | (void)bcopy(little, mid, littlelen); |
575 | } |
576 | else if (littlelen) { |
577 | midend -= littlelen; |
578 | str_chop(bigstr,midend); |
579 | (void)bcopy(little,midend,littlelen); |
580 | } |
581 | else { |
582 | str_chop(bigstr,midend); |
583 | } |
584 | STABSET(bigstr); |
8d063cd8 |
585 | } |
586 | |
587 | /* make str point to what nstr did */ |
588 | |
589 | void |
590 | str_replace(str,nstr) |
591 | register STR *str; |
592 | register STR *nstr; |
593 | { |
395c3793 |
594 | if (str == &str_undef) |
595 | return; |
a687059c |
596 | if (str->str_state == SS_INCR) |
e929a76b |
597 | Str_Grow(str,0); /* just force copy down */ |
a687059c |
598 | if (nstr->str_state == SS_INCR) |
e929a76b |
599 | Str_Grow(nstr,0); |
a687059c |
600 | if (str->str_ptr) |
601 | Safefree(str->str_ptr); |
8d063cd8 |
602 | str->str_ptr = nstr->str_ptr; |
603 | str->str_len = nstr->str_len; |
604 | str->str_cur = nstr->str_cur; |
605 | str->str_pok = nstr->str_pok; |
a687059c |
606 | str->str_nok = nstr->str_nok; |
607 | #ifdef STRUCTCOPY |
608 | str->str_u = nstr->str_u; |
609 | #else |
610 | str->str_u.str_nval = nstr->str_u.str_nval; |
611 | #endif |
612 | #ifdef TAINT |
613 | str->str_tainted = nstr->str_tainted; |
614 | #endif |
34de22dd |
615 | if (nstr->str_magic) |
616 | str_free(nstr->str_magic); |
a687059c |
617 | Safefree(nstr); |
8d063cd8 |
618 | } |
619 | |
620 | void |
621 | str_free(str) |
622 | register STR *str; |
623 | { |
395c3793 |
624 | if (!str || str == &str_undef) |
8d063cd8 |
625 | return; |
a687059c |
626 | if (str->str_state) { |
627 | if (str->str_state == SS_FREE) /* already freed */ |
628 | return; |
629 | if (str->str_state == SS_INCR && !(str->str_pok & 2)) { |
630 | str->str_ptr -= str->str_u.str_useful; |
631 | str->str_len += str->str_u.str_useful; |
632 | } |
633 | } |
634 | if (str->str_magic) |
635 | str_free(str->str_magic); |
fe14fcc3 |
636 | str->str_magic = freestrroot; |
a687059c |
637 | #ifdef LEAKTEST |
fe14fcc3 |
638 | if (str->str_len) { |
a687059c |
639 | Safefree(str->str_ptr); |
fe14fcc3 |
640 | str->str_ptr = Nullch; |
641 | } |
a687059c |
642 | if ((str->str_pok & SP_INTRP) && str->str_u.str_args) |
643 | arg_free(str->str_u.str_args); |
644 | Safefree(str); |
645 | #else /* LEAKTEST */ |
646 | if (str->str_len) { |
647 | if (str->str_len > 127) { /* next user not likely to want more */ |
648 | Safefree(str->str_ptr); /* so give it back to malloc */ |
649 | str->str_ptr = Nullch; |
650 | str->str_len = 0; |
651 | } |
652 | else |
653 | str->str_ptr[0] = '\0'; |
654 | } |
655 | if ((str->str_pok & SP_INTRP) && str->str_u.str_args) |
656 | arg_free(str->str_u.str_args); |
8d063cd8 |
657 | str->str_cur = 0; |
658 | str->str_nok = 0; |
659 | str->str_pok = 0; |
a687059c |
660 | str->str_state = SS_FREE; |
661 | #ifdef TAINT |
662 | str->str_tainted = 0; |
663 | #endif |
8d063cd8 |
664 | freestrroot = str; |
a687059c |
665 | #endif /* LEAKTEST */ |
8d063cd8 |
666 | } |
667 | |
e929a76b |
668 | STRLEN |
8d063cd8 |
669 | str_len(str) |
670 | register STR *str; |
671 | { |
672 | if (!str) |
673 | return 0; |
674 | if (!(str->str_pok)) |
a687059c |
675 | (void)str_2ptr(str); |
676 | if (str->str_ptr) |
8d063cd8 |
677 | return str->str_cur; |
678 | else |
679 | return 0; |
680 | } |
681 | |
a687059c |
682 | str_eq(str1,str2) |
683 | register STR *str1; |
684 | register STR *str2; |
685 | { |
395c3793 |
686 | if (!str1 || str1 == &str_undef) |
687 | return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur); |
688 | if (!str2 || str2 == &str_undef) |
689 | return !str1->str_cur; |
a687059c |
690 | |
691 | if (!str1->str_pok) |
692 | (void)str_2ptr(str1); |
693 | if (!str2->str_pok) |
694 | (void)str_2ptr(str2); |
695 | |
696 | if (str1->str_cur != str2->str_cur) |
697 | return 0; |
698 | |
699 | return !bcmp(str1->str_ptr, str2->str_ptr, str1->str_cur); |
700 | } |
701 | |
702 | str_cmp(str1,str2) |
703 | register STR *str1; |
704 | register STR *str2; |
705 | { |
706 | int retval; |
707 | |
395c3793 |
708 | if (!str1 || str1 == &str_undef) |
709 | return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur)?0:-1; |
710 | if (!str2 || str2 == &str_undef) |
711 | return str1->str_cur != 0; |
a687059c |
712 | |
713 | if (!str1->str_pok) |
714 | (void)str_2ptr(str1); |
715 | if (!str2->str_pok) |
716 | (void)str_2ptr(str2); |
717 | |
718 | if (str1->str_cur < str2->str_cur) { |
f0fcb552 |
719 | /*SUPPRESS 560*/ |
a687059c |
720 | if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur)) |
27e2fb84 |
721 | return retval < 0 ? -1 : 1; |
a687059c |
722 | else |
03a14243 |
723 | return -1; |
a687059c |
724 | } |
f0fcb552 |
725 | /*SUPPRESS 560*/ |
a687059c |
726 | else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur)) |
27e2fb84 |
727 | return retval < 0 ? -1 : 1; |
a687059c |
728 | else if (str1->str_cur == str2->str_cur) |
729 | return 0; |
730 | else |
03a14243 |
731 | return 1; |
a687059c |
732 | } |
733 | |
8d063cd8 |
734 | char * |
a687059c |
735 | str_gets(str,fp,append) |
8d063cd8 |
736 | register STR *str; |
737 | register FILE *fp; |
a687059c |
738 | int append; |
8d063cd8 |
739 | { |
8d063cd8 |
740 | register char *bp; /* we're going to steal some values */ |
741 | register int cnt; /* from the stdio struct and put EVERYTHING */ |
36ce8bec |
742 | register STDCHAR *ptr; /* in the innermost loop into registers */ |
fe14fcc3 |
743 | register int newline = rschar;/* (assuming >= 6 registers) */ |
8d063cd8 |
744 | int i; |
e929a76b |
745 | STRLEN bpx; |
34de22dd |
746 | int shortbuffered; |
8d063cd8 |
747 | |
395c3793 |
748 | if (str == &str_undef) |
749 | return Nullch; |
03a14243 |
750 | #ifdef STDSTDIO /* Here is some breathtakingly efficient cheating */ |
8d063cd8 |
751 | cnt = fp->_cnt; /* get count into register */ |
752 | str->str_nok = 0; /* invalidate number */ |
753 | str->str_pok = 1; /* validate pointer */ |
f0fcb552 |
754 | if (str->str_len - append <= cnt + 1) { /* make sure we have the room */ |
35c8bce7 |
755 | if (cnt > 80 && str->str_len > append) { |
756 | shortbuffered = cnt - str->str_len + append + 1; |
757 | cnt -= shortbuffered; |
34de22dd |
758 | } |
759 | else { |
760 | shortbuffered = 0; |
761 | STR_GROW(str, append+cnt+2);/* (remembering cnt can be -1) */ |
762 | } |
763 | } |
764 | else |
765 | shortbuffered = 0; |
a687059c |
766 | bp = str->str_ptr + append; /* move these two too to registers */ |
8d063cd8 |
767 | ptr = fp->_ptr; |
768 | for (;;) { |
769 | screamer: |
770 | while (--cnt >= 0) { /* this */ /* eat */ |
771 | if ((*bp++ = *ptr++) == newline) /* really */ /* dust */ |
772 | goto thats_all_folks; /* screams */ /* sed :-) */ |
773 | } |
774 | |
34de22dd |
775 | if (shortbuffered) { /* oh well, must extend */ |
776 | cnt = shortbuffered; |
777 | shortbuffered = 0; |
34de22dd |
778 | bpx = bp - str->str_ptr; /* prepare for possible relocation */ |
27e2fb84 |
779 | str->str_cur = bpx; |
34de22dd |
780 | STR_GROW(str, str->str_len + append + cnt + 2); |
781 | bp = str->str_ptr + bpx; /* reconstitute our pointer */ |
34de22dd |
782 | continue; |
783 | } |
784 | |
8d063cd8 |
785 | fp->_cnt = cnt; /* deregisterize cnt and ptr */ |
786 | fp->_ptr = ptr; |
787 | i = _filbuf(fp); /* get more characters */ |
788 | cnt = fp->_cnt; |
789 | ptr = fp->_ptr; /* reregisterize cnt and ptr */ |
790 | |
791 | bpx = bp - str->str_ptr; /* prepare for possible relocation */ |
ffed7fef |
792 | str->str_cur = bpx; |
a687059c |
793 | STR_GROW(str, bpx + cnt + 2); |
8d063cd8 |
794 | bp = str->str_ptr + bpx; /* reconstitute our pointer */ |
8d063cd8 |
795 | |
796 | if (i == newline) { /* all done for now? */ |
797 | *bp++ = i; |
798 | goto thats_all_folks; |
799 | } |
800 | else if (i == EOF) /* all done for ever? */ |
801 | goto thats_really_all_folks; |
802 | *bp++ = i; /* now go back to screaming loop */ |
803 | } |
804 | |
805 | thats_all_folks: |
fe14fcc3 |
806 | if (rslen > 1 && (bp - str->str_ptr < rslen || bcmp(bp - rslen, rs, rslen))) |
807 | goto screamer; /* go back to the fray */ |
8d063cd8 |
808 | thats_really_all_folks: |
34de22dd |
809 | if (shortbuffered) |
810 | cnt += shortbuffered; |
8d063cd8 |
811 | fp->_cnt = cnt; /* put these back or we're in trouble */ |
812 | fp->_ptr = ptr; |
813 | *bp = '\0'; |
814 | str->str_cur = bp - str->str_ptr; /* set length */ |
815 | |
816 | #else /* !STDSTDIO */ /* The big, slow, and stupid way */ |
817 | |
03a14243 |
818 | { |
819 | static char buf[8192]; |
820 | char * bpe = buf + sizeof(buf) - 3; |
821 | |
822 | screamer: |
823 | bp = buf; |
fe14fcc3 |
824 | while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe) ; |
8d063cd8 |
825 | |
03a14243 |
826 | *bp = '\0'; |
a687059c |
827 | if (append) |
828 | str_cat(str, buf); |
829 | else |
830 | str_set(str, buf); |
fe14fcc3 |
831 | if (i != EOF /* joy */ |
832 | && |
833 | (i != newline |
834 | || |
835 | (rslen > 1 |
836 | && |
837 | (str->str_cur < rslen |
838 | || |
839 | bcmp(str->str_ptr + str->str_cur - rslen, rs, rslen) |
840 | ) |
841 | ) |
842 | ) |
843 | ) |
844 | { |
03a14243 |
845 | append = -1; |
846 | goto screamer; |
847 | } |
a687059c |
848 | } |
8d063cd8 |
849 | |
850 | #endif /* STDSTDIO */ |
851 | |
a687059c |
852 | return str->str_cur - append ? str->str_ptr : Nullch; |
8d063cd8 |
853 | } |
854 | |
a687059c |
855 | ARG * |
856 | parselist(str) |
857 | STR *str; |
858 | { |
859 | register CMD *cmd; |
860 | register ARG *arg; |
e929a76b |
861 | CMD *oldcurcmd = curcmd; |
395c3793 |
862 | int oldperldb = perldb; |
a687059c |
863 | int retval; |
8d063cd8 |
864 | |
395c3793 |
865 | perldb = 0; |
a687059c |
866 | str_sset(linestr,str); |
867 | in_eval++; |
868 | oldoldbufptr = oldbufptr = bufptr = str_get(linestr); |
869 | bufend = bufptr + linestr->str_cur; |
9f68db38 |
870 | if (++loop_ptr >= loop_max) { |
871 | loop_max += 128; |
872 | Renew(loop_stack, loop_max, struct loop); |
873 | } |
874 | loop_stack[loop_ptr].loop_label = "_EVAL_"; |
875 | loop_stack[loop_ptr].loop_sp = 0; |
876 | #ifdef DEBUGGING |
877 | if (debug & 4) { |
878 | deb("(Pushing label #%d _EVAL_)\n", loop_ptr); |
879 | } |
880 | #endif |
881 | if (setjmp(loop_stack[loop_ptr].loop_env)) { |
882 | in_eval--; |
883 | loop_ptr--; |
395c3793 |
884 | perldb = oldperldb; |
a687059c |
885 | fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr); |
886 | } |
9f68db38 |
887 | #ifdef DEBUGGING |
888 | if (debug & 4) { |
e929a76b |
889 | char *tmps = loop_stack[loop_ptr].loop_label; |
9f68db38 |
890 | deb("(Popping label #%d %s)\n",loop_ptr, |
891 | tmps ? tmps : "" ); |
892 | } |
893 | #endif |
894 | loop_ptr--; |
a687059c |
895 | error_count = 0; |
e929a76b |
896 | curcmd = &compiling; |
897 | curcmd->c_line = oldcurcmd->c_line; |
a687059c |
898 | retval = yyparse(); |
e929a76b |
899 | curcmd = oldcurcmd; |
395c3793 |
900 | perldb = oldperldb; |
a687059c |
901 | in_eval--; |
902 | if (retval || error_count) |
903 | fatal("Invalid component in string or format"); |
904 | cmd = eval_root; |
905 | arg = cmd->c_expr; |
906 | if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST) |
907 | fatal("panic: error in parselist %d %x %d", cmd->c_type, |
908 | cmd->c_next, arg ? arg->arg_type : -1); |
a687059c |
909 | Safefree(cmd); |
fe14fcc3 |
910 | eval_root = Nullcmd; |
a687059c |
911 | return arg; |
912 | } |
913 | |
914 | void |
915 | intrpcompile(src) |
916 | STR *src; |
8d063cd8 |
917 | { |
a687059c |
918 | register char *s = str_get(src); |
919 | register char *send = s + src->str_cur; |
920 | register STR *str; |
921 | register char *t; |
922 | STR *toparse; |
e929a76b |
923 | STRLEN len; |
a687059c |
924 | register int brackets; |
925 | register char *d; |
926 | STAB *stab; |
927 | char *checkpoint; |
fe14fcc3 |
928 | int sawcase = 0; |
8d063cd8 |
929 | |
a687059c |
930 | toparse = Str_new(76,0); |
931 | str = Str_new(77,0); |
932 | |
933 | str_nset(str,"",0); |
934 | str_nset(toparse,"",0); |
935 | t = s; |
936 | while (s < send) { |
fe14fcc3 |
937 | if (*s == '\\' && s[1] && index("$@[{\\]}lLuUE",s[1])) { |
a687059c |
938 | str_ncat(str, t, s - t); |
939 | ++s; |
f0fcb552 |
940 | if (isALPHA(*s)) { |
fe14fcc3 |
941 | str_ncat(str, "$c", 2); |
942 | sawcase = (*s != 'E'); |
943 | } |
944 | else { |
f0fcb552 |
945 | if (*nointrp) { /* in a regular expression */ |
946 | if (*s == '@') /* always strip \@ */ /*SUPPRESS 530*/ |
947 | ; |
948 | else if (*s == '$') { |
949 | if (s+1 >= send || index(nointrp, s[1])) |
950 | str_ncat(str,s-1,1); /* only strip \$ for vars */ |
951 | } |
952 | else /* don't strip \\, \[, \{ etc. */ |
fe14fcc3 |
953 | str_ncat(str,s-1,1); |
f0fcb552 |
954 | } |
fe14fcc3 |
955 | str_ncat(str, "$b", 2); |
956 | } |
a687059c |
957 | str_ncat(str, s, 1); |
958 | ++s; |
959 | t = s; |
8d063cd8 |
960 | } |
1462b684 |
961 | else if (*s == '$' && s+1 < send && *nointrp && index(nointrp,s[1])) { |
962 | str_ncat(str, t, s - t); |
963 | str_ncat(str, "$b", 2); |
964 | str_ncat(str, s, 2); |
965 | s += 2; |
966 | t = s; |
967 | } |
968 | else if ((*s == '@' || *s == '$') && s+1 < send) { |
8d063cd8 |
969 | str_ncat(str,t,s-t); |
8d063cd8 |
970 | t = s; |
f0fcb552 |
971 | if (*s == '$' && s[1] == '#' && (isALPHA(s[2]) || s[2] == '_')) |
a687059c |
972 | s++; |
fe14fcc3 |
973 | s = scanident(s,send,tokenbuf); |
a687059c |
974 | if (*t == '@' && |
9f68db38 |
975 | (!(stab = stabent(tokenbuf,FALSE)) || |
976 | (*s == '{' ? !stab_xhash(stab) : !stab_xarray(stab)) )) { |
a687059c |
977 | str_ncat(str,"@",1); |
978 | s = ++t; |
979 | continue; /* grandfather @ from old scripts */ |
980 | } |
981 | str_ncat(str,"$a",2); |
982 | str_ncat(toparse,",",1); |
983 | if (t[1] != '{' && (*s == '[' || *s == '{' /* }} */ ) && |
984 | (stab = stabent(tokenbuf,FALSE)) && |
985 | ((*s == '[') ? (stab_xarray(stab) != 0) : (stab_xhash(stab) != 0)) ) { |
986 | brackets = 0; |
987 | checkpoint = s; |
988 | do { |
989 | switch (*s) { |
9f68db38 |
990 | case '[': |
991 | if (s[-1] != '$') |
992 | brackets++; |
993 | break; |
994 | case '{': |
a687059c |
995 | brackets++; |
996 | break; |
9f68db38 |
997 | case ']': |
998 | if (s[-1] != '$') |
999 | brackets--; |
1000 | break; |
1001 | case '}': |
a687059c |
1002 | brackets--; |
1003 | break; |
1004 | case '\'': |
1005 | case '"': |
1006 | if (s[-1] != '$') { |
f0fcb552 |
1007 | /*SUPPRESS 68*/ |
a687059c |
1008 | s = cpytill(tokenbuf,s+1,send,*s,&len); |
1009 | if (s >= send) |
1010 | fatal("Unterminated string"); |
1011 | } |
1012 | break; |
1013 | } |
1014 | s++; |
1015 | } while (brackets > 0 && s < send); |
1016 | if (s > send) |
1017 | fatal("Unmatched brackets in string"); |
1018 | if (*nointrp) { /* we're in a regular expression */ |
1019 | d = checkpoint; |
1020 | if (*d == '{' && s[-1] == '}') { /* maybe {n,m} */ |
1021 | ++d; |
f0fcb552 |
1022 | if (isDIGIT(*d)) { /* matches /^{\d,?\d*}$/ */ |
a687059c |
1023 | if (*++d == ',') |
1024 | ++d; |
f0fcb552 |
1025 | while (isDIGIT(*d)) |
a687059c |
1026 | d++; |
1027 | if (d == s - 1) |
1028 | s = checkpoint; /* Is {n,m}! Backoff! */ |
1029 | } |
1030 | } |
1031 | else if (*d == '[' && s[-1] == ']') { /* char class? */ |
1032 | int weight = 2; /* let's weigh the evidence */ |
1033 | char seen[256]; |
ffed7fef |
1034 | unsigned char un_char = 0, last_un_char; |
a687059c |
1035 | |
1036 | Zero(seen,256,char); |
1037 | *--s = '\0'; |
1038 | if (d[1] == '^') |
1039 | weight += 150; |
1040 | else if (d[1] == '$') |
1041 | weight -= 3; |
f0fcb552 |
1042 | if (isDIGIT(d[1])) { |
a687059c |
1043 | if (d[2]) { |
f0fcb552 |
1044 | if (isDIGIT(d[2]) && !d[3]) |
a687059c |
1045 | weight -= 10; |
1046 | } |
1047 | else |
1048 | weight -= 100; |
1049 | } |
1050 | for (d++; d < s; d++) { |
ffed7fef |
1051 | last_un_char = un_char; |
1052 | un_char = (unsigned char)*d; |
a687059c |
1053 | switch (*d) { |
1054 | case '&': |
1055 | case '$': |
ffed7fef |
1056 | weight -= seen[un_char] * 10; |
f0fcb552 |
1057 | if (isALNUM(d[1])) { |
fe14fcc3 |
1058 | d = scanident(d,s,tokenbuf); |
a687059c |
1059 | if (stabent(tokenbuf,FALSE)) |
1060 | weight -= 100; |
1061 | else |
1062 | weight -= 10; |
1063 | } |
1064 | else if (*d == '$' && d[1] && |
1065 | index("[#!%*<>()-=",d[1])) { |
1066 | if (!d[2] || /*{*/ index("])} =",d[2])) |
1067 | weight -= 10; |
1068 | else |
1069 | weight -= 1; |
1070 | } |
1071 | break; |
1072 | case '\\': |
ffed7fef |
1073 | un_char = 254; |
a687059c |
1074 | if (d[1]) { |
1075 | if (index("wds",d[1])) |
1076 | weight += 100; |
1077 | else if (seen['\''] || seen['"']) |
1078 | weight += 1; |
1079 | else if (index("rnftb",d[1])) |
1080 | weight += 40; |
f0fcb552 |
1081 | else if (isDIGIT(d[1])) { |
a687059c |
1082 | weight += 40; |
f0fcb552 |
1083 | while (d[1] && isDIGIT(d[1])) |
a687059c |
1084 | d++; |
1085 | } |
1086 | } |
1087 | else |
1088 | weight += 100; |
1089 | break; |
1090 | case '-': |
395c3793 |
1091 | if (last_un_char < (unsigned char) d[1] |
1092 | || d[1] == '\\') { |
ffed7fef |
1093 | if (index("aA01! ",last_un_char)) |
a687059c |
1094 | weight += 30; |
1095 | if (index("zZ79~",d[1])) |
1096 | weight += 30; |
1097 | } |
1098 | else |
1099 | weight -= 1; |
1100 | default: |
f0fcb552 |
1101 | if (isALPHA(*d) && d[1] && isALPHA(d[1])) { |
a687059c |
1102 | bufptr = d; |
1103 | if (yylex() != WORD) |
1104 | weight -= 150; |
1105 | d = bufptr; |
1106 | } |
ffed7fef |
1107 | if (un_char == last_un_char + 1) |
a687059c |
1108 | weight += 5; |
ffed7fef |
1109 | weight -= seen[un_char]; |
a687059c |
1110 | break; |
1111 | } |
ffed7fef |
1112 | seen[un_char]++; |
a687059c |
1113 | } |
1114 | #ifdef DEBUGGING |
1115 | if (debug & 512) |
1116 | fprintf(stderr,"[%s] weight %d\n", |
1117 | checkpoint+1,weight); |
1118 | #endif |
1119 | *s++ = ']'; |
1120 | if (weight >= 0) /* probably a character class */ |
1121 | s = checkpoint; |
1122 | } |
1123 | } |
1124 | } |
1125 | if (*t == '@') |
1126 | str_ncat(toparse, "join($\",", 8); |
1127 | if (t[1] == '{' && s[-1] == '}') { |
1128 | str_ncat(toparse, t, 1); |
1129 | str_ncat(toparse, t+2, s - t - 3); |
1130 | } |
1131 | else |
1132 | str_ncat(toparse, t, s - t); |
1133 | if (*t == '@') |
1134 | str_ncat(toparse, ")", 1); |
1135 | t = s; |
1136 | } |
1137 | else |
1138 | s++; |
1139 | } |
1140 | str_ncat(str,t,s-t); |
fe14fcc3 |
1141 | if (sawcase) |
1142 | str_ncat(str, "$cE", 3); |
a687059c |
1143 | if (toparse->str_ptr && *toparse->str_ptr == ',') { |
1144 | *toparse->str_ptr = '('; |
1145 | str_ncat(toparse,",$$);",5); |
1146 | str->str_u.str_args = parselist(toparse); |
1147 | str->str_u.str_args->arg_len--; /* ignore $$ reference */ |
1148 | } |
1149 | else |
1150 | str->str_u.str_args = Nullarg; |
1151 | str_free(toparse); |
1152 | str->str_pok |= SP_INTRP; |
1153 | str->str_nok = 0; |
1154 | str_replace(src,str); |
1155 | } |
1156 | |
1157 | STR * |
1158 | interp(str,src,sp) |
1159 | register STR *str; |
1160 | STR *src; |
1161 | int sp; |
1162 | { |
1163 | register char *s; |
1164 | register char *t; |
1165 | register char *send; |
1166 | register STR **elem; |
fe14fcc3 |
1167 | int docase = 0; |
1168 | int l = 0; |
1169 | int u = 0; |
1170 | int L = 0; |
1171 | int U = 0; |
a687059c |
1172 | |
395c3793 |
1173 | if (str == &str_undef) |
1174 | return Nullstr; |
a687059c |
1175 | if (!(src->str_pok & SP_INTRP)) { |
1176 | int oldsave = savestack->ary_fill; |
1177 | |
1178 | (void)savehptr(&curstash); |
395c3793 |
1179 | curstash = curcmd->c_stash; /* so stabent knows right package */ |
a687059c |
1180 | intrpcompile(src); |
1181 | restorelist(oldsave); |
1182 | } |
1183 | s = src->str_ptr; /* assumed valid since str_pok set */ |
1184 | t = s; |
1185 | send = s + src->str_cur; |
1186 | |
1187 | if (src->str_u.str_args) { |
1188 | (void)eval(src->str_u.str_args,G_ARRAY,sp); |
1189 | /* Assuming we have correct # of args */ |
1190 | elem = stack->ary_array + sp; |
1191 | } |
1192 | |
1193 | str_nset(str,"",0); |
1194 | while (s < send) { |
1195 | if (*s == '$' && s+1 < send) { |
fe14fcc3 |
1196 | if (s-t > 0) |
1197 | str_ncat(str,t,s-t); |
a687059c |
1198 | switch(*++s) { |
1462b684 |
1199 | default: |
1200 | fatal("panic: unknown interp cookie\n"); |
1201 | break; |
a687059c |
1202 | case 'a': |
1203 | str_scat(str,*++elem); |
1204 | break; |
1205 | case 'b': |
1206 | str_ncat(str,++s,1); |
1207 | break; |
fe14fcc3 |
1208 | case 'c': |
1209 | if (docase && str->str_cur >= docase) { |
1210 | char *b = str->str_ptr + --docase; |
1211 | |
1212 | if (L) |
1213 | lcase(b, str->str_ptr + str->str_cur); |
1214 | else if (U) |
1215 | ucase(b, str->str_ptr + str->str_cur); |
1216 | |
1217 | if (u) /* note that l & u are independent of L & U */ |
1218 | ucase(b, b+1); |
1219 | else if (l) |
1220 | lcase(b, b+1); |
1221 | l = u = 0; |
1222 | } |
1223 | docase = str->str_cur + 1; |
1224 | switch (*++s) { |
1225 | case 'u': |
1226 | u = 1; |
1227 | l = 0; |
1228 | break; |
1229 | case 'U': |
1230 | U = 1; |
1231 | L = 0; |
1232 | break; |
1233 | case 'l': |
1234 | l = 1; |
1235 | u = 0; |
1236 | break; |
1237 | case 'L': |
1238 | L = 1; |
1239 | U = 0; |
1240 | break; |
1241 | case 'E': |
1242 | docase = L = U = l = u = 0; |
1243 | break; |
1244 | } |
1245 | break; |
a687059c |
1246 | } |
1247 | t = ++s; |
8d063cd8 |
1248 | } |
1249 | else |
1250 | s++; |
1251 | } |
fe14fcc3 |
1252 | if (s-t > 0) |
1253 | str_ncat(str,t,s-t); |
8d063cd8 |
1254 | return str; |
1255 | } |
1256 | |
fe14fcc3 |
1257 | ucase(s,send) |
1258 | register char *s; |
1259 | register char *send; |
1260 | { |
1261 | while (s < send) { |
f0fcb552 |
1262 | if (isLOWER(*s)) |
fe14fcc3 |
1263 | *s = toupper(*s); |
1264 | s++; |
1265 | } |
1266 | } |
1267 | |
1268 | lcase(s,send) |
1269 | register char *s; |
1270 | register char *send; |
1271 | { |
1272 | while (s < send) { |
f0fcb552 |
1273 | if (isUPPER(*s)) |
fe14fcc3 |
1274 | *s = tolower(*s); |
1275 | s++; |
1276 | } |
1277 | } |
1278 | |
8d063cd8 |
1279 | void |
1280 | str_inc(str) |
1281 | register STR *str; |
1282 | { |
1283 | register char *d; |
1284 | |
395c3793 |
1285 | if (!str || str == &str_undef) |
8d063cd8 |
1286 | return; |
1287 | if (str->str_nok) { |
a687059c |
1288 | str->str_u.str_nval += 1.0; |
8d063cd8 |
1289 | str->str_pok = 0; |
1290 | return; |
1291 | } |
378cc40b |
1292 | if (!str->str_pok || !*str->str_ptr) { |
a687059c |
1293 | str->str_u.str_nval = 1.0; |
8d063cd8 |
1294 | str->str_nok = 1; |
13281fa4 |
1295 | str->str_pok = 0; |
8d063cd8 |
1296 | return; |
1297 | } |
378cc40b |
1298 | d = str->str_ptr; |
f0fcb552 |
1299 | while (isALPHA(*d)) d++; |
1300 | while (isDIGIT(*d)) d++; |
378cc40b |
1301 | if (*d) { |
8d063cd8 |
1302 | str_numset(str,atof(str->str_ptr) + 1.0); /* punt */ |
1303 | return; |
1304 | } |
378cc40b |
1305 | d--; |
8d063cd8 |
1306 | while (d >= str->str_ptr) { |
f0fcb552 |
1307 | if (isDIGIT(*d)) { |
378cc40b |
1308 | if (++*d <= '9') |
1309 | return; |
1310 | *(d--) = '0'; |
1311 | } |
1312 | else { |
1313 | ++*d; |
f0fcb552 |
1314 | if (isALPHA(*d)) |
378cc40b |
1315 | return; |
1316 | *(d--) -= 'z' - 'a' + 1; |
1317 | } |
8d063cd8 |
1318 | } |
1319 | /* oh,oh, the number grew */ |
a687059c |
1320 | STR_GROW(str, str->str_cur + 2); |
8d063cd8 |
1321 | str->str_cur++; |
1322 | for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--) |
1323 | *d = d[-1]; |
f0fcb552 |
1324 | if (isDIGIT(d[1])) |
378cc40b |
1325 | *d = '1'; |
1326 | else |
1327 | *d = d[1]; |
8d063cd8 |
1328 | } |
1329 | |
1330 | void |
1331 | str_dec(str) |
1332 | register STR *str; |
1333 | { |
395c3793 |
1334 | if (!str || str == &str_undef) |
8d063cd8 |
1335 | return; |
1336 | if (str->str_nok) { |
a687059c |
1337 | str->str_u.str_nval -= 1.0; |
8d063cd8 |
1338 | str->str_pok = 0; |
1339 | return; |
1340 | } |
1341 | if (!str->str_pok) { |
a687059c |
1342 | str->str_u.str_nval = -1.0; |
8d063cd8 |
1343 | str->str_nok = 1; |
1344 | return; |
1345 | } |
378cc40b |
1346 | str_numset(str,atof(str->str_ptr) - 1.0); |
8d063cd8 |
1347 | } |
1348 | |
a687059c |
1349 | /* Make a string that will exist for the duration of the expression |
1350 | * evaluation. Actually, it may have to last longer than that, but |
1351 | * hopefully cmd_exec won't free it until it has been assigned to a |
1352 | * permanent location. */ |
1353 | |
1354 | static long tmps_size = -1; |
8d063cd8 |
1355 | |
1356 | STR * |
fe14fcc3 |
1357 | str_mortal(oldstr) |
8d063cd8 |
1358 | STR *oldstr; |
1359 | { |
a687059c |
1360 | register STR *str = Str_new(78,0); |
8d063cd8 |
1361 | |
1362 | str_sset(str,oldstr); |
1363 | if (++tmps_max > tmps_size) { |
1364 | tmps_size = tmps_max; |
1365 | if (!(tmps_size & 127)) { |
1366 | if (tmps_size) |
a687059c |
1367 | Renew(tmps_list, tmps_size + 128, STR*); |
8d063cd8 |
1368 | else |
a687059c |
1369 | New(702,tmps_list, 128, STR*); |
8d063cd8 |
1370 | } |
1371 | } |
1372 | tmps_list[tmps_max] = str; |
34de22dd |
1373 | if (str->str_pok) |
1374 | str->str_pok |= SP_TEMP; |
8d063cd8 |
1375 | return str; |
1376 | } |
1377 | |
a687059c |
1378 | /* same thing without the copying */ |
1379 | |
8d063cd8 |
1380 | STR * |
fe14fcc3 |
1381 | str_2mortal(str) |
a687059c |
1382 | register STR *str; |
1383 | { |
395c3793 |
1384 | if (str == &str_undef) |
1385 | return str; |
a687059c |
1386 | if (++tmps_max > tmps_size) { |
1387 | tmps_size = tmps_max; |
1388 | if (!(tmps_size & 127)) { |
1389 | if (tmps_size) |
1390 | Renew(tmps_list, tmps_size + 128, STR*); |
1391 | else |
1392 | New(704,tmps_list, 128, STR*); |
1393 | } |
1394 | } |
1395 | tmps_list[tmps_max] = str; |
34de22dd |
1396 | if (str->str_pok) |
1397 | str->str_pok |= SP_TEMP; |
a687059c |
1398 | return str; |
1399 | } |
1400 | |
1401 | STR * |
1402 | str_make(s,len) |
8d063cd8 |
1403 | char *s; |
e929a76b |
1404 | STRLEN len; |
8d063cd8 |
1405 | { |
a687059c |
1406 | register STR *str = Str_new(79,0); |
8d063cd8 |
1407 | |
a687059c |
1408 | if (!len) |
1409 | len = strlen(s); |
1410 | str_nset(str,s,len); |
8d063cd8 |
1411 | return str; |
1412 | } |
1413 | |
1414 | STR * |
1415 | str_nmake(n) |
1416 | double n; |
1417 | { |
a687059c |
1418 | register STR *str = Str_new(80,0); |
8d063cd8 |
1419 | |
1420 | str_numset(str,n); |
1421 | return str; |
1422 | } |
a687059c |
1423 | |
1424 | /* make an exact duplicate of old */ |
1425 | |
1426 | STR * |
1427 | str_smake(old) |
1428 | register STR *old; |
1429 | { |
1430 | register STR *new = Str_new(81,0); |
1431 | |
1432 | if (!old) |
1433 | return Nullstr; |
1434 | if (old->str_state == SS_FREE) { |
1435 | warn("semi-panic: attempt to dup freed string"); |
1436 | return Nullstr; |
1437 | } |
1438 | if (old->str_state == SS_INCR && !(old->str_pok & 2)) |
e929a76b |
1439 | Str_Grow(old,0); |
a687059c |
1440 | if (new->str_ptr) |
1441 | Safefree(new->str_ptr); |
1442 | Copy(old,new,1,STR); |
27e2fb84 |
1443 | if (old->str_ptr) { |
a687059c |
1444 | new->str_ptr = nsavestr(old->str_ptr,old->str_len); |
27e2fb84 |
1445 | new->str_pok &= ~SP_TEMP; |
1446 | } |
a687059c |
1447 | return new; |
1448 | } |
1449 | |
1450 | str_reset(s,stash) |
1451 | register char *s; |
1452 | HASH *stash; |
1453 | { |
1454 | register HENT *entry; |
1455 | register STAB *stab; |
1456 | register STR *str; |
1457 | register int i; |
1458 | register SPAT *spat; |
1459 | register int max; |
1460 | |
1461 | if (!*s) { /* reset ?? searches */ |
1462 | for (spat = stash->tbl_spatroot; |
1463 | spat != Nullspat; |
1464 | spat = spat->spat_next) { |
1465 | spat->spat_flags &= ~SPAT_USED; |
1466 | } |
1467 | return; |
1468 | } |
1469 | |
1470 | /* reset variables */ |
1471 | |
395c3793 |
1472 | if (!stash->tbl_array) |
1473 | return; |
a687059c |
1474 | while (*s) { |
1475 | i = *s; |
1476 | if (s[1] == '-') { |
1477 | s += 2; |
1478 | } |
1479 | max = *s++; |
1480 | for ( ; i <= max; i++) { |
1481 | for (entry = stash->tbl_array[i]; |
1482 | entry; |
1483 | entry = entry->hent_next) { |
1484 | stab = (STAB*)entry->hent_val; |
1485 | str = stab_val(stab); |
1486 | str->str_cur = 0; |
1487 | str->str_nok = 0; |
1488 | #ifdef TAINT |
1489 | str->str_tainted = tainted; |
1490 | #endif |
1491 | if (str->str_ptr != Nullch) |
1492 | str->str_ptr[0] = '\0'; |
1493 | if (stab_xarray(stab)) { |
1494 | aclear(stab_xarray(stab)); |
1495 | } |
1496 | if (stab_xhash(stab)) { |
395c3793 |
1497 | hclear(stab_xhash(stab), FALSE); |
a687059c |
1498 | if (stab == envstab) |
1499 | environ[0] = Nullch; |
1500 | } |
1501 | } |
1502 | } |
1503 | } |
1504 | } |
1505 | |
1506 | #ifdef TAINT |
1507 | taintproper(s) |
1508 | char *s; |
1509 | { |
1510 | #ifdef DEBUGGING |
1511 | if (debug & 2048) |
1512 | fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid); |
1513 | #endif |
e929a76b |
1514 | if (tainted && (!euid || euid != uid || egid != gid)) { |
a687059c |
1515 | if (!unsafe) |
1516 | fatal("%s", s); |
1517 | else if (dowarn) |
1518 | warn("%s", s); |
1519 | } |
1520 | } |
1521 | |
1522 | taintenv() |
1523 | { |
1524 | register STR *envstr; |
1525 | |
1526 | envstr = hfetch(stab_hash(envstab),"PATH",4,FALSE); |
395c3793 |
1527 | if (envstr == &str_undef || envstr->str_tainted) { |
a687059c |
1528 | tainted = 1; |
395c3793 |
1529 | if (envstr->str_tainted == 2) |
1530 | taintproper("Insecure directory in PATH"); |
1531 | else |
1532 | taintproper("Insecure PATH"); |
a687059c |
1533 | } |
1534 | envstr = hfetch(stab_hash(envstab),"IFS",3,FALSE); |
395c3793 |
1535 | if (envstr != &str_undef && envstr->str_tainted) { |
a687059c |
1536 | tainted = 1; |
1537 | taintproper("Insecure IFS"); |
1538 | } |
1539 | } |
1540 | #endif /* TAINT */ |