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