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