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