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