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