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