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