source: trunk/third/perl/str.c @ 9009

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