perl 3.0 patch #26 patch #19, continued
[p5sagit/p5-mst-13.2.git] / str.c
diff --git a/str.c b/str.c
index 06d185e..0b6dfea 100644 (file)
--- a/str.c
+++ b/str.c
@@ -1,4 +1,4 @@
-/* $Header: str.c,v 3.0.1.3 89/11/17 15:38:23 lwall Locked $
+/* $Header: str.c,v 3.0.1.8 90/08/09 05:22:18 lwall Locked $
  *
  *    Copyright (c) 1989, Larry Wall
  *
@@ -6,6 +6,30 @@
  *    as specified in the README file that comes with the perl 3.0 kit.
  *
  * $Log:       str.c,v $
+ * Revision 3.0.1.8  90/08/09  05:22:18  lwall
+ * patch19: the number to string converter wasn't allocating enough space
+ * patch19: tainting didn't work on setgid scripts
+ * 
+ * Revision 3.0.1.7  90/03/27  16:24:11  lwall
+ * patch16: strings with prefix chopped off sometimes freed wrong
+ * patch16: taint check blows up on undefined array element
+ * 
+ * Revision 3.0.1.6  90/03/12  17:02:14  lwall
+ * patch13: substr as lvalue didn't invalidate old numeric value
+ * 
+ * Revision 3.0.1.5  90/02/28  18:30:38  lwall
+ * patch9: you may now undef $/ to have no input record separator
+ * patch9: nested evals clobbered their longjmp environment
+ * patch9: sometimes perl thought ordinary data was a symbol table entry
+ * patch9: insufficient space allocated for numeric string on sun4
+ * patch9: underscore in an array name in a double-quoted string not recognized
+ * patch9: "@foo{}" not recognized unless %foo defined
+ * patch9: "$foo[$[]" gives error
+ * 
+ * Revision 3.0.1.4  89/12/21  20:21:35  lwall
+ * patch7: errno may now be a macro with an lvalue
+ * patch7: made nested or recursive foreach work right
+ * 
  * Revision 3.0.1.3  89/11/17  15:38:23  lwall
  * patch5: some machines typedef unchar too
  * patch5: substitution on leading components occasionally caused <> corruption
@@ -77,10 +101,20 @@ STR *Str;
 char *
 str_grow(str,newlen)
 register STR *str;
+#ifndef MSDOS
 register int newlen;
+#else
+unsigned long newlen;
+#endif
 {
     register char *s = str->str_ptr;
 
+#ifdef MSDOS
+    if (newlen >= 0x10000) {
+       fprintf(stderr, "Allocation too large: %lx\n", newlen);
+       exit(1);
+    }
+#endif /* MSDOS */
     if (str->str_state == SS_INCR) {           /* data before str_ptr? */
        str->str_len += str->str_u.str_useful;
        str->str_ptr -= str->str_u.str_useful;
@@ -106,17 +140,19 @@ str_numset(str,num)
 register STR *str;
 double num;
 {
+    if (str->str_pok) {
+       str->str_pok = 0;       /* invalidate pointer */
+       if (str->str_state == SS_INCR)
+           Str_Grow(str,0);
+    }
     str->str_u.str_nval = num;
     str->str_state = SS_NORM;
-    str->str_pok = 0;  /* invalidate pointer */
     str->str_nok = 1;                  /* validate number */
 #ifdef TAINT
     str->str_tainted = tainted;
 #endif
 }
 
-extern int errno;
-
 char *
 str_2ptr(str)
 register STR *str;
@@ -127,7 +163,7 @@ register STR *str;
     if (!str)
        return "";
     if (str->str_nok) {
-       STR_GROW(str, 24);
+       STR_GROW(str, 30);
        s = str->str_ptr;
        olderrno = errno;       /* some Xenix systems wipe out errno here */
 #if defined(scs) && defined(ns32000)
@@ -142,13 +178,17 @@ register STR *str;
 #endif /*scs*/
        errno = olderrno;
        while (*s) s++;
+#ifdef hcx
+       if (s[-1] == '.')
+           s--;
+#endif
     }
     else {
        if (str == &str_undef)
            return No;
        if (dowarn)
            warn("Use of uninitialized variable");
-       STR_GROW(str, 24);
+       STR_GROW(str, 30);
        s = str->str_ptr;
     }
     *s = '\0';
@@ -167,6 +207,8 @@ register STR *str;
 {
     if (!str)
        return 0.0;
+    if (str->str_state == SS_INCR)
+       Str_Grow(str,0);       /* just force copy down */
     str->str_state = SS_NORM;
     if (str->str_len && str->str_pok)
        str->str_u.str_nval = atof(str->str_ptr);
@@ -190,8 +232,11 @@ STR *dstr;
 register STR *sstr;
 {
 #ifdef TAINT
-    tainted |= sstr->str_tainted;
+    if (sstr)
+       tainted |= sstr->str_tainted;
 #endif
+    if (sstr == dstr)
+       return;
     if (!sstr)
        dstr->str_pok = dstr->str_nok = 0;
     else if (sstr->str_pok) {
@@ -204,7 +249,7 @@ register STR *sstr;
        else if (sstr->str_cur == sizeof(STBP)) {
            char *tmps = sstr->str_ptr;
 
-           if (*tmps == 'S' && bcmp(tmps,"Stab",4) == 0) {
+           if (*tmps == 'S' && bcmp(tmps,"StB",4) == 0) {
                dstr->str_magic = str_smake(sstr->str_magic);
                dstr->str_magic->str_rare = 'X';
            }
@@ -212,17 +257,27 @@ register STR *sstr;
     }
     else if (sstr->str_nok)
        str_numset(dstr,sstr->str_u.str_nval);
-    else
+    else {
+       if (dstr->str_state == SS_INCR)
+           Str_Grow(dstr,0);       /* just force copy down */
+
+#ifdef STRUCTCOPY
+       dstr->str_u = sstr->str_u;
+#else
+       dstr->str_u.str_nval = sstr->str_u.str_nval;
+#endif
        dstr->str_pok = dstr->str_nok = 0;
+    }
 }
 
 str_nset(str,ptr,len)
 register STR *str;
 register char *ptr;
-register int len;
+register STRLEN len;
 {
     STR_GROW(str, len + 1);
-    (void)bcopy(ptr,str->str_ptr,len);
+    if (ptr)
+       (void)bcopy(ptr,str->str_ptr,len);
     str->str_cur = len;
     *(str->str_ptr+str->str_cur) = '\0';
     str->str_nok = 0;          /* invalidate number */
@@ -236,7 +291,7 @@ str_set(str,ptr)
 register STR *str;
 register char *ptr;
 {
-    register int len;
+    register STRLEN len;
 
     if (!ptr)
        ptr = "";
@@ -255,7 +310,7 @@ str_chop(str,ptr)   /* like set but assuming ptr is in str */
 register STR *str;
 register char *ptr;
 {
-    register int delta;
+    register STRLEN delta;
 
     if (!(str->str_pok))
        fatal("str_chop: internal inconsistency");
@@ -276,7 +331,7 @@ register char *ptr;
 str_ncat(str,ptr,len)
 register STR *str;
 register char *ptr;
-register int len;
+register STRLEN len;
 {
     if (!(str->str_pok))
        (void)str_2ptr(str);
@@ -310,7 +365,7 @@ str_cat(str,ptr)
 register STR *str;
 register char *ptr;
 {
-    register int len;
+    register STRLEN len;
 
     if (!ptr)
        return;
@@ -336,7 +391,7 @@ register int delim;
 char *keeplist;
 {
     register char *to;
-    register int len;
+    register STRLEN len;
 
     if (!from)
        return Nullch;
@@ -374,7 +429,7 @@ int x;
 #else
 str_new(len)
 #endif
-int len;
+STRLEN len;
 {
     register STR *str;
     
@@ -398,7 +453,7 @@ register STR *str;
 STAB *stab;
 int how;
 char *name;
-int namlen;
+STRLEN namlen;
 {
     if (str->str_magic)
        return;
@@ -413,10 +468,10 @@ int namlen;
 void
 str_insert(bigstr,offset,len,little,littlelen)
 STR *bigstr;
-int offset;
-int len;
+STRLEN offset;
+STRLEN len;
 char *little;
-int littlelen;
+STRLEN littlelen;
 {
     register char *big;
     register char *mid;
@@ -424,6 +479,9 @@ int littlelen;
     register char *bigend;
     register int i;
 
+    bigstr->str_nok = 0;
+    bigstr->str_pok = SP_VALID;        /* disable possible screamer */
+
     i = littlelen - len;
     if (i > 0) {                       /* string might grow */
        STR_GROW(bigstr, bigstr->str_cur + i + 1);
@@ -451,8 +509,6 @@ int littlelen;
     if (midend > bigend)
        fatal("panic: str_insert");
 
-    bigstr->str_pok = SP_VALID;        /* disable possible screamer */
-
     if (mid - big > bigend - midend) { /* faster to shorten from end */
        if (littlelen) {
            (void)bcopy(little, mid, littlelen);
@@ -495,9 +551,9 @@ register STR *str;
 register STR *nstr;
 {
     if (str->str_state == SS_INCR)
-       str_grow(str,0);        /* just force copy down */
+       Str_Grow(str,0);        /* just force copy down */
     if (nstr->str_state == SS_INCR)
-       str_grow(nstr,0);
+       Str_Grow(nstr,0);
     if (str->str_ptr)
        Safefree(str->str_ptr);
     str->str_ptr = nstr->str_ptr;
@@ -562,6 +618,7 @@ register STR *str;
 #endif /* LEAKTEST */
 }
 
+STRLEN
 str_len(str)
 register STR *str;
 {
@@ -634,10 +691,10 @@ int append;
     register char *bp;         /* we're going to steal some values */
     register int cnt;          /*  from the stdio struct and put EVERYTHING */
     register STDCHAR *ptr;     /*   in the innermost loop into registers */
-    register char newline = record_separator;/* (assuming >= 6 registers) */
+    register int newline = record_separator;/* (assuming >= 6 registers) */
     int i;
-    int bpx;
-    int obpx;
+    STRLEN bpx;
+    STRLEN obpx;
     register int get_paragraph;
     register char *oldbp;
 
@@ -732,19 +789,42 @@ STR *str;
 {
     register CMD *cmd;
     register ARG *arg;
-    line_t oldline = line;
+    CMD *oldcurcmd = curcmd;
     int retval;
 
     str_sset(linestr,str);
     in_eval++;
     oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
     bufend = bufptr + linestr->str_cur;
-    if (setjmp(eval_env)) {
-       in_eval = 0;
+    if (++loop_ptr >= loop_max) {
+        loop_max += 128;
+        Renew(loop_stack, loop_max, struct loop);
+    }
+    loop_stack[loop_ptr].loop_label = "_EVAL_";
+    loop_stack[loop_ptr].loop_sp = 0;
+#ifdef DEBUGGING
+    if (debug & 4) {
+        deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
+    }
+#endif
+    if (setjmp(loop_stack[loop_ptr].loop_env)) {
+       in_eval--;
+       loop_ptr--;
        fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr);
     }
+#ifdef DEBUGGING
+    if (debug & 4) {
+       char *tmps = loop_stack[loop_ptr].loop_label;
+       deb("(Popping label #%d %s)\n",loop_ptr,
+           tmps ? tmps : "" );
+    }
+#endif
+    loop_ptr--;
     error_count = 0;
+    curcmd = &compiling;
+    curcmd->c_line = oldcurcmd->c_line;
     retval = yyparse();
+    curcmd = oldcurcmd;
     in_eval--;
     if (retval || error_count)
        fatal("Invalid component in string or format");
@@ -753,7 +833,6 @@ STR *str;
     if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST)
        fatal("panic: error in parselist %d %x %d", cmd->c_type,
          cmd->c_next, arg ? arg->arg_type : -1);
-    line = oldline;
     Safefree(cmd);
     return arg;
 }
@@ -767,7 +846,7 @@ STR *src;
     register STR *str;
     register char *t;
     STR *toparse;
-    int len;
+    STRLEN len;
     register int brackets;
     register char *d;
     STAB *stab;
@@ -795,11 +874,12 @@ STR *src;
          s+1 < send) {
            str_ncat(str,t,s-t);
            t = s;
-           if (*s == '$' && s[1] == '#' && isalpha(s[2]) || s[2] == '_')
+           if (*s == '$' && s[1] == '#' && (isalpha(s[2]) || s[2] == '_'))
                s++;
            s = scanreg(s,send,tokenbuf);
            if (*t == '@' &&
-             (!(stab = stabent(tokenbuf,FALSE)) || !stab_xarray(stab)) ) {
+             (!(stab = stabent(tokenbuf,FALSE)) || 
+                (*s == '{' ? !stab_xhash(stab) : !stab_xarray(stab)) )) {
                str_ncat(str,"@",1);
                s = ++t;
                continue;       /* grandfather @ from old scripts */
@@ -813,10 +893,18 @@ STR *src;
                checkpoint = s;
                do {
                    switch (*s) {
-                   case '[': case '{':
+                   case '[':
+                       if (s[-1] != '$')
+                           brackets++;
+                       break;
+                   case '{':
                        brackets++;
                        break;
-                   case ']': case '}':
+                   case ']':
+                       if (s[-1] != '$')
+                           brackets--;
+                       break;
+                   case '}':
                        brackets--;
                        break;
                    case '\'':
@@ -1138,7 +1226,7 @@ register STR *str;
 STR *
 str_make(s,len)
 char *s;
-int len;
+STRLEN len;
 {
     register STR *str = Str_new(79,0);
 
@@ -1173,7 +1261,7 @@ register STR *old;
        return Nullstr;
     }
     if (old->str_state == SS_INCR && !(old->str_pok & 2))
-       str_grow(old,0);
+       Str_Grow(old,0);
     if (new->str_ptr)
        Safefree(new->str_ptr);
     Copy(old,new,1,STR);
@@ -1244,7 +1332,7 @@ char *s;
     if (debug & 2048)
        fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid);
 #endif
-    if (tainted && (!euid || euid != uid)) {
+    if (tainted && (!euid || euid != uid || egid != gid)) {
        if (!unsafe)
            fatal("%s", s);
        else if (dowarn)