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