perl 4.0 patch 14: patch #11, continued
[p5sagit/p5-mst-13.2.git] / dolist.c
index 1e9b3e7..345c5ac 100644 (file)
--- a/dolist.c
+++ b/dolist.c
@@ -1,76 +1,35 @@
-/* $Header: dolist.c,v 3.0.1.12 91/01/11 17:54:58 lwall Locked $
+/* $RCSfile: dolist.c,v $$Revision: 4.0.1.3 $$Date: 91/11/05 17:07:02 $
  *
- *    Copyright (c) 1989, Larry Wall
+ *    Copyright (c) 1991, Larry Wall
  *
- *    You may distribute under the terms of the GNU General Public License
- *    as specified in the README file that comes with the perl 3.0 kit.
+ *    You may distribute under the terms of either the GNU General Public
+ *    License or the Artistic License, as specified in the README file.
  *
  * $Log:       dolist.c,v $
- * Revision 3.0.1.12  91/01/11  17:54:58  lwall
- * patch42: added binary and hex pack/unpack options
- * patch42: sort subroutines didn't allow copying $a or $b to other variables.
- * patch42: caller() coredumped when called outside the debugger.
+ * Revision 4.0.1.3  91/11/05  17:07:02  lwall
+ * patch11: prepared for ctype implementations that don't define isascii()
+ * patch11: /$foo/o optimizer could access deallocated data
+ * patch11: certain optimizations of //g in array context returned too many values
+ * patch11: regexp with no parens in array context returned wacky $`, $& and $'
+ * patch11: $' not set right on some //g
+ * patch11: added some support for 64-bit integers
+ * patch11: grep of a split lost its values
+ * patch11: added sort {} LIST
+ * patch11: multiple reallocations now avoided in 1 .. 100000
  * 
- * Revision 3.0.1.11  90/11/10  01:29:49  lwall
- * patch38: temp string values are now copied less often
- * patch38: sort parameters are now in the right package
+ * Revision 4.0.1.2  91/06/10  01:22:15  lwall
+ * patch10: //g only worked first time through
  * 
- * Revision 3.0.1.10  90/10/15  16:19:48  lwall
- * patch29: added caller
- * patch29: added scalar reverse
- * patch29: sort undefined_subroutine @array is now a fatal error
+ * Revision 4.0.1.1  91/06/07  10:58:28  lwall
+ * patch4: new copyright notice
+ * patch4: added global modifier for pattern matches
+ * patch4: // wouldn't use previous pattern if it started with a null character
+ * patch4: //o and s///o now optimize themselves fully at runtime
+ * patch4: $` was busted inside s///
+ * patch4: caller($arg) didn't work except under debugger
  * 
- * Revision 3.0.1.9  90/08/13  22:15:35  lwall
- * patch28: defined(@array) and defined(%array) didn't work right
- * 
- * Revision 3.0.1.8  90/08/09  03:15:56  lwall
- * patch19: certain kinds of matching cause "panic: hint"
- * patch19: $' broke on embedded nulls
- * patch19: split on /\s+/, /^/ and ' ' is now special cased for speed
- * patch19: split on /x/i didn't work
- * patch19: couldn't unpack an 'A' or 'a' field in a scalar context
- * patch19: unpack called bcopy on each character of a C/c field
- * patch19: pack/unpack know about uudecode lines
- * patch19: fixed sort on undefined strings and sped up slightly
- * patch19: each and keys returned garbage on null key in DBM file
- * 
- * Revision 3.0.1.7  90/03/27  15:48:42  lwall
- * patch16: MSDOS support
- * patch16: use of $`, $& or $' sometimes causes memory leakage
- * patch16: splice(@array,0,$n) case cause duplicate free
- * patch16: grep blows up on undefined array values
- * patch16: .. now works using magical string increment
- * 
- * Revision 3.0.1.6  90/03/12  16:33:02  lwall
- * patch13: added list slice operator (LIST)[LIST]
- * patch13: added splice operator: @oldelems = splice(@array,$offset,$len,LIST)
- * patch13: made split('') act like split(//) rather than split(' ')
- * 
- * Revision 3.0.1.5  90/02/28  17:09:44  lwall
- * patch9: split now can split into more than 10000 elements
- * patch9: @_ clobbered by ($foo,$bar) = split
- * patch9: sped up pack and unpack
- * patch9: unpack of single item now works in a scalar context
- * patch9: slices ignored value of $[
- * patch9: grep now returns number of items matched in scalar context
- * patch9: grep iterations no longer in the regexp context of previous iteration
- * 
- * Revision 3.0.1.4  89/12/21  19:58:46  lwall
- * patch7: grep(1,@array) didn't work
- * patch7: /$pat/; //; wrongly freed runtime pattern twice
- * 
- * Revision 3.0.1.3  89/11/17  15:14:45  lwall
- * patch5: grep() occasionally loses arguments or dumps core
- * 
- * Revision 3.0.1.2  89/11/11  04:28:17  lwall
- * patch2: non-existent slice values are now undefined rather than null
- * 
- * Revision 3.0.1.1  89/10/26  23:11:51  lwall
- * patch1: split in a subroutine wrongly freed referenced arguments
- * patch1: reverse didn't work
- * 
- * Revision 3.0  89/10/18  15:11:02  lwall
- * 3.0 baseline
+ * Revision 4.0  91/03/20  01:08:03  lwall
+ * 4.0 baseline.
  * 
  */
 
@@ -98,6 +57,8 @@ int *arglast;
     char *strend = s + st[sp]->str_cur;
     STR *tmpstr;
     char *myhint = hint;
+    int global;
+    int safebase;
 
     hint = Nullch;
     if (!spat) {
@@ -108,6 +69,8 @@ int *arglast;
        st[sp] = str;
        return sp;
     }
+    global = spat->spat_flags & SPAT_GLOBAL;
+    safebase = (gimme == G_ARRAY) || global;
     if (!s)
        fatal("panic: do_match");
     if (spat->spat_flags & SPAT_USED) {
@@ -133,23 +96,36 @@ int *arglast;
        if (debug & 8)
            deb("2.SPAT /%s/\n",t);
 #endif
-       if (spat->spat_regexp)
+       if (spat->spat_regexp) {
            regfree(spat->spat_regexp);
+           spat->spat_regexp = Null(REGEXP*);  /* crucial if regcomp aborts */
+       }
        spat->spat_regexp = regcomp(t,t+tmpstr->str_cur,
            spat->spat_flags & SPAT_FOLD);
-       if (!*spat->spat_regexp->precomp && lastspat)
+       if (!spat->spat_regexp->prelen && lastspat)
            spat = lastspat;
        if (spat->spat_flags & SPAT_KEEP) {
+           scanconst(spat,spat->spat_regexp->precomp, spat->spat_regexp->prelen);
            if (spat->spat_runtime)
                arg_free(spat->spat_runtime);   /* it won't change, so */
            spat->spat_runtime = Nullarg;       /* no point compiling again */
+           hoistmust(spat);
+           if (curcmd->c_expr && (curcmd->c_flags & CF_OPTIMIZE) == CFT_EVAL) {
+               curcmd->c_flags &= ~CF_OPTIMIZE;
+               opt_arg(curcmd, 1, curcmd->c_type == C_EXPR);
+           }
+       }
+       if (global) {
+           if (spat->spat_regexp->startp[0]) {
+               s = spat->spat_regexp->endp[0];
+           }
        }
-       if (!spat->spat_regexp->nparens)
+       else if (!spat->spat_regexp->nparens)
            gimme = G_SCALAR;                   /* accidental array context? */
        if (regexec(spat->spat_regexp, s, strend, s, 0,
          srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
-         gimme == G_ARRAY)) {
-           if (spat->spat_regexp->subbase)
+         safebase)) {
+           if (spat->spat_regexp->subbase || global)
                curspat = spat;
            lastspat = spat;
            goto gotcha;
@@ -175,9 +151,12 @@ int *arglast;
            deb("2.SPAT %c%s%c\n",ch,spat->spat_regexp->precomp,ch);
        }
 #endif
-       if (!*spat->spat_regexp->precomp && lastspat)
+       if (!spat->spat_regexp->prelen && lastspat)
            spat = lastspat;
        t = s;
+    play_it_again:
+       if (global && spat->spat_regexp->startp[0])
+           t = s = spat->spat_regexp->endp[0];
        if (myhint) {
            if (myhint < s || myhint > strend)
                fatal("panic: hint in do_match");
@@ -224,12 +203,14 @@ int *arglast;
                spat->spat_short = Nullstr;     /* opt is being useless */
            }
        }
-       if (!spat->spat_regexp->nparens)
+       if (!spat->spat_regexp->nparens && !global) {
            gimme = G_SCALAR;                   /* accidental array context? */
+           safebase = FALSE;
+       }
        if (regexec(spat->spat_regexp, s, strend, t, 0,
          srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
-         gimme == G_ARRAY)) {
-           if (spat->spat_regexp->subbase)
+         safebase)) {
+           if (spat->spat_regexp->subbase || global)
                curspat = spat;
            lastspat = spat;
            if (spat->spat_flags & SPAT_ONCE)
@@ -237,6 +218,8 @@ int *arglast;
            goto gotcha;
        }
        else {
+           if (global)
+               spat->spat_regexp->startp[0] = Nullch;
            if (gimme == G_ARRAY)
                return sp;
            str_sset(str,&str_no);
@@ -252,19 +235,26 @@ int *arglast;
        int iters, i, len;
 
        iters = spat->spat_regexp->nparens;
-       if (sp + iters >= stack->ary_max) {
-           astore(stack,sp + iters, Nullstr);
+       if (global && !iters)
+           i = 1;
+       else
+           i = 0;
+       if (sp + iters + i >= stack->ary_max) {
+           astore(stack,sp + iters + i, Nullstr);
            st = stack->ary_array;              /* possibly realloced */
        }
 
-       for (i = 1; i <= iters; i++) {
-           st[++sp] = str_static(&str_no);
+       for (i = !i; i <= iters; i++) {
+           st[++sp] = str_mortal(&str_no);
+           /*SUPPRESS 560*/
            if (s = spat->spat_regexp->startp[i]) {
                len = spat->spat_regexp->endp[i] - s;
                if (len > 0)
                    str_nset(st[sp],s,len);
            }
        }
+       if (global)
+           goto play_it_again;
        return sp;
     }
     else {
@@ -279,12 +269,21 @@ yup:
     lastspat = spat;
     if (spat->spat_flags & SPAT_ONCE)
        spat->spat_flags |= SPAT_USED;
+    if (global) {
+       spat->spat_regexp->subbeg = t;
+       spat->spat_regexp->subend = strend;
+       spat->spat_regexp->startp[0] = s;
+       spat->spat_regexp->endp[0] = s + spat->spat_short->str_cur;
+       curspat = spat;
+       goto gotcha;
+    }
     if (sawampersand) {
        char *tmps;
 
        if (spat->spat_regexp->subbase)
            Safefree(spat->spat_regexp->subbase);
        tmps = spat->spat_regexp->subbase = nsavestr(t,strend-t);
+       spat->spat_regexp->subbeg = tmps;
        spat->spat_regexp->subend = tmps + (strend-t);
        tmps = spat->spat_regexp->startp[0] = tmps + (s - t);
        spat->spat_regexp->endp[0] = tmps + spat->spat_short->str_cur;
@@ -296,7 +295,10 @@ yup:
     return sp;
 
 nope:
+    spat->spat_regexp->startp[0] = Nullch;
     ++spat->spat_short->str_u.str_useful;
+    if (global)
+       spat->spat_regexp->startp[0] = Nullch;
     if (gimme == G_ARRAY)
        return sp;
     str_sset(str,&str_no);
@@ -344,8 +346,10 @@ int *arglast;
            m = dstr->str_ptr;
            spat->spat_flags |= SPAT_SKIPWHITE;
        }
-       if (spat->spat_regexp)
+       if (spat->spat_regexp) {
            regfree(spat->spat_regexp);
+           spat->spat_regexp = Null(REGEXP*);  /* avoid possible double free */
+       }
        spat->spat_regexp = regcomp(m,m+dstr->str_cur,
            spat->spat_flags & SPAT_FOLD);
        if (spat->spat_flags & SPAT_KEEP ||
@@ -375,26 +379,29 @@ int *arglast;
        ary = stack;
     orig = s;
     if (spat->spat_flags & SPAT_SKIPWHITE) {
-       while (isspace(*s))
+       while (isSPACE(*s))
            s++;
     }
     if (!limit)
        limit = maxiters + 2;
     if (strEQ("\\s+",spat->spat_regexp->precomp)) {
        while (--limit) {
-           for (m = s; m < strend && !isspace(*m); m++) ;
+           /*SUPPRESS 530*/
+           for (m = s; m < strend && !isSPACE(*m); m++) ;
            if (m >= strend)
                break;
            dstr = Str_new(30,m-s);
            str_nset(dstr,s,m-s);
            if (!realarray)
-               str_2static(dstr);
+               str_2mortal(dstr);
            (void)astore(ary, ++sp, dstr);
-           for (s = m + 1; s < strend && isspace(*s); s++) ;
+           /*SUPPRESS 530*/
+           for (s = m + 1; s < strend && isSPACE(*s); s++) ;
        }
     }
     else if (strEQ("^",spat->spat_regexp->precomp)) {
        while (--limit) {
+           /*SUPPRESS 530*/
            for (m = s; m < strend && *m != '\n'; m++) ;
            m++;
            if (m >= strend)
@@ -402,7 +409,7 @@ int *arglast;
            dstr = Str_new(30,m-s);
            str_nset(dstr,s,m-s);
            if (!realarray)
-               str_2static(dstr);
+               str_2mortal(dstr);
            (void)astore(ary, ++sp, dstr);
            s = m;
        }
@@ -413,24 +420,24 @@ int *arglast;
            int fold = (spat->spat_flags & SPAT_FOLD);
 
            i = *spat->spat_short->str_ptr;
-           if (fold && isupper(i))
+           if (fold && isUPPER(i))
                i = tolower(i);
            while (--limit) {
                if (fold) {
                    for ( m = s;
                          m < strend && *m != i &&
-                           (!isupper(*m) || tolower(*m) != i);
-                         m++)
+                           (!isUPPER(*m) || tolower(*m) != i);
+                         m++)                  /*SUPPRESS 530*/
                        ;
                }
-               else
+               else                            /*SUPPRESS 530*/
                    for (m = s; m < strend && *m != i; m++) ;
                if (m >= strend)
                    break;
                dstr = Str_new(30,m-s);
                str_nset(dstr,s,m-s);
                if (!realarray)
-                   str_2static(dstr);
+                   str_2mortal(dstr);
                (void)astore(ary, ++sp, dstr);
                s = m + 1;
            }
@@ -445,7 +452,7 @@ int *arglast;
                dstr = Str_new(31,m-s);
                str_nset(dstr,s,m-s);
                if (!realarray)
-                   str_2static(dstr);
+                   str_2mortal(dstr);
                (void)astore(ary, ++sp, dstr);
                s = m + i;
            }
@@ -467,7 +474,7 @@ int *arglast;
            dstr = Str_new(32,m-s);
            str_nset(dstr,s,m-s);
            if (!realarray)
-               str_2static(dstr);
+               str_2mortal(dstr);
            (void)astore(ary, ++sp, dstr);
            if (spat->spat_regexp->nparens) {
                for (i = 1; i <= spat->spat_regexp->nparens; i++) {
@@ -476,7 +483,7 @@ int *arglast;
                    dstr = Str_new(33,m-s);
                    str_nset(dstr,s,m-s);
                    if (!realarray)
-                       str_2static(dstr);
+                       str_2mortal(dstr);
                    (void)astore(ary, ++sp, dstr);
                }
            }
@@ -493,7 +500,7 @@ int *arglast;
        dstr = Str_new(34,strend-s);
        str_nset(dstr,s,strend-s);
        if (!realarray)
-           str_2static(dstr);
+           str_2mortal(dstr);
        (void)astore(ary, ++sp, dstr);
        iters++;
     }
@@ -555,15 +562,20 @@ int *arglast;
     int datumtype;
     register int len;
     register int bits;
-    static char hexchar[] = "0123456789abcdef";
 
     /* These must not be in registers: */
     short ashort;
     int aint;
     long along;
+#ifdef QUAD
+    quad aquad;
+#endif
     unsigned short aushort;
     unsigned int auint;
     unsigned long aulong;
+#ifdef QUAD
+    unsigned quad auquad;
+#endif
     char *aptr;
     float afloat;
     double adouble;
@@ -572,10 +584,11 @@ int *arglast;
     double cdouble;
 
     if (gimme != G_ARRAY) {            /* arrange to do first one only */
-       for (patend = pat; !isalpha(*patend); patend++);
+       /*SUPPRESS 530*/
+       for (patend = pat; !isALPHA(*patend) || *patend == 'x'; patend++) ;
        if (index("aAbBhH", *patend) || *pat == '%') {
            patend++;
-           while (isdigit(*patend) || *patend == '*')
+           while (isDIGIT(*patend) || *patend == '*')
                patend++;
        }
        else
@@ -591,9 +604,9 @@ int *arglast;
            len = strend - strbeg;      /* long enough */
            pat++;
        }
-       else if (isdigit(*pat)) {
+       else if (isDIGIT(*pat)) {
            len = *pat++ - '0';
-           while (isdigit(*pat))
+           while (isDIGIT(*pat))
                len = (len * 10) + (*pat++ - '0');
        }
        else
@@ -637,13 +650,13 @@ int *arglast;
            if (datumtype == 'A') {
                aptr = s;       /* borrow register */
                s = str->str_ptr + len - 1;
-               while (s >= str->str_ptr && (!*s || isspace(*s)))
+               while (s >= str->str_ptr && (!*s || isSPACE(*s)))
                    s--;
                *++s = '\0';
                str->str_cur = s - str->str_ptr;
                s = aptr;       /* unborrow register */
            }
-           (void)astore(stack, ++sp, str_2static(str));
+           (void)astore(stack, ++sp, str_2mortal(str));
            break;
        case 'B':
        case 'b':
@@ -657,7 +670,7 @@ int *arglast;
            if (datumtype == 'b') {
                aint = len;
                for (len = 0; len < aint; len++) {
-                   if (len & 7)
+                   if (len & 7)                /*SUPPRESS 595*/
                        bits >>= 1;
                    else
                        bits = *s++;
@@ -676,13 +689,13 @@ int *arglast;
            }
            *pat = '\0';
            pat = aptr;                 /* unborrow register */
-           (void)astore(stack, ++sp, str_2static(str));
+           (void)astore(stack, ++sp, str_2mortal(str));
            break;
        case 'H':
        case 'h':
            if (pat[-1] == '*' || len > (strend - s) * 2)
                len = (strend - s) * 2;
-           str = Str_new(35, len);
+           str = Str_new(35, len + 1);
            str->str_cur = len;
            str->str_pok = 1;
            aptr = pat;                 /* borrow register */
@@ -694,7 +707,7 @@ int *arglast;
                        bits >>= 4;
                    else
                        bits = *s++;
-                   *pat++ = hexchar[bits & 15];
+                   *pat++ = hexdigit[bits & 15];
                }
            }
            else {
@@ -704,12 +717,12 @@ int *arglast;
                        bits <<= 4;
                    else
                        bits = *s++;
-                   *pat++ = hexchar[(bits >> 4) & 15];
+                   *pat++ = hexdigit[(bits >> 4) & 15];
                }
            }
            *pat = '\0';
            pat = aptr;                 /* unborrow register */
-           (void)astore(stack, ++sp, str_2static(str));
+           (void)astore(stack, ++sp, str_2mortal(str));
            break;
        case 'c':
            if (len > strend - s)
@@ -729,7 +742,7 @@ int *arglast;
                        aint -= 256;
                    str = Str_new(36,0);
                    str_numset(str,(double)aint);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -748,7 +761,7 @@ int *arglast;
                    auint = *s++ & 255;
                    str = Str_new(37,0);
                    str_numset(str,(double)auint);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -769,7 +782,7 @@ int *arglast;
                    s += sizeof(short);
                    str = Str_new(38,0);
                    str_numset(str,(double)ashort);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -782,7 +795,7 @@ int *arglast;
                while (len-- > 0) {
                    bcopy(s,(char*)&aushort,sizeof(unsigned short));
                    s += sizeof(unsigned short);
-#ifdef NTOHS
+#ifdef HAS_NTOHS
                    if (datumtype == 'n')
                        aushort = ntohs(aushort);
 #endif
@@ -794,12 +807,12 @@ int *arglast;
                    bcopy(s,(char*)&aushort,sizeof(unsigned short));
                    s += sizeof(unsigned short);
                    str = Str_new(39,0);
-#ifdef NTOHS
+#ifdef HAS_NTOHS
                    if (datumtype == 'n')
                        aushort = ntohs(aushort);
 #endif
                    str_numset(str,(double)aushort);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -823,7 +836,7 @@ int *arglast;
                    s += sizeof(int);
                    str = Str_new(40,0);
                    str_numset(str,(double)aint);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -847,7 +860,7 @@ int *arglast;
                    s += sizeof(unsigned int);
                    str = Str_new(41,0);
                    str_numset(str,(double)auint);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -871,7 +884,7 @@ int *arglast;
                    s += sizeof(long);
                    str = Str_new(42,0);
                    str_numset(str,(double)along);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -884,7 +897,7 @@ int *arglast;
                while (len-- > 0) {
                    bcopy(s,(char*)&aulong,sizeof(unsigned long));
                    s += sizeof(unsigned long);
-#ifdef NTOHL
+#ifdef HAS_NTOHL
                    if (datumtype == 'N')
                        aulong = ntohl(aulong);
 #endif
@@ -899,12 +912,12 @@ int *arglast;
                    bcopy(s,(char*)&aulong,sizeof(unsigned long));
                    s += sizeof(unsigned long);
                    str = Str_new(43,0);
-#ifdef NTOHL
+#ifdef HAS_NTOHL
                    if (datumtype == 'N')
                        aulong = ntohl(aulong);
 #endif
                    str_numset(str,(double)aulong);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -922,9 +935,37 @@ int *arglast;
                str = Str_new(44,0);
                if (aptr)
                    str_set(str,aptr);
-               (void)astore(stack, ++sp, str_2static(str));
+               (void)astore(stack, ++sp, str_2mortal(str));
+           }
+           break;
+#ifdef QUAD
+       case 'q':
+           while (len-- > 0) {
+               if (s + sizeof(quad) > strend)
+                   aquad = 0;
+               else {
+                   bcopy(s,(char*)&aquad,sizeof(quad));
+                   s += sizeof(quad);
+               }
+               str = Str_new(42,0);
+               str_numset(str,(double)aquad);
+               (void)astore(stack, ++sp, str_2mortal(str));
            }
            break;
+       case 'Q':
+           while (len-- > 0) {
+               if (s + sizeof(unsigned quad) > strend)
+                   auquad = 0;
+               else {
+                   bcopy(s,(char*)&auquad,sizeof(unsigned quad));
+                   s += sizeof(unsigned quad);
+               }
+               str = Str_new(43,0);
+               str_numset(str,(double)auquad);
+               (void)astore(stack, ++sp, str_2mortal(str));
+           }
+           break;
+#endif
        /* float and double added gnb@melba.bby.oz.au 22/11/89 */
        case 'f':
        case 'F':
@@ -944,7 +985,7 @@ int *arglast;
                    s += sizeof(float);
                    str = Str_new(47, 0);
                    str_numset(str, (double)afloat);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -966,7 +1007,7 @@ int *arglast;
                    s += sizeof(double);
                    str = Str_new(48, 0);
                    str_numset(str, (double)adouble);
-                   (void)astore(stack, ++sp, str_2static(str));
+                   (void)astore(stack, ++sp, str_2mortal(str));
                }
            }
            break;
@@ -1007,7 +1048,7 @@ int *arglast;
                else if (s[1] == '\n')          /* possible checksum byte */
                    s += 2;
            }
-           (void)astore(stack, ++sp, str_2static(str));
+           (void)astore(stack, ++sp, str_2mortal(str));
            break;
        }
        if (checksum) {
@@ -1035,11 +1076,13 @@ int *arglast;
                str_numset(str,cdouble);
            }
            else {
-               along = (1 << checksum) - 1;
-               culong &= (unsigned long)along;
+               if (checksum < 32) {
+                   along = (1 << checksum) - 1;
+                   culong &= (unsigned long)along;
+               }
                str_numset(str,(double)culong);
            }
-           (void)astore(stack, ++sp, str_2static(str));
+           (void)astore(stack, ++sp, str_2mortal(str));
            checksum = 0;
        }
     }
@@ -1169,11 +1212,11 @@ int *arglast;
                length = 0;
        }
        else
-           length = ary->ary_max;              /* close enough to infinity */
+           length = ary->ary_max + 1;          /* close enough to infinity */
     }
     else {
        offset = 0;
-       length = ary->ary_max;
+       length = ary->ary_max + 1;
     }
     if (offset < 0) {
        length += offset;
@@ -1213,14 +1256,14 @@ int *arglast;
            Copy(ary->ary_array+offset, st+sp, length, STR*);
            if (ary->ary_flags & ARF_REAL) {
                for (i = length, dst = st+sp; i; i--)
-                   str_2static(*dst++);        /* free them eventualy */
+                   str_2mortal(*dst++);        /* free them eventualy */
            }
            sp += length - 1;
        }
        else {
            st[sp] = ary->ary_array[offset+length-1];
            if (ary->ary_flags & ARF_REAL)
-               str_2static(st[sp]);
+               str_2mortal(st[sp]);
        }
        ary->ary_fill += diff;
 
@@ -1303,7 +1346,7 @@ int *arglast;
                Copy(tmparyval, st+sp, length, STR*);
                if (ary->ary_flags & ARF_REAL) {
                    for (i = length, dst = st+sp; i; i--)
-                       str_2static(*dst++);    /* free them eventualy */
+                       str_2mortal(*dst++);    /* free them eventualy */
                }
                Safefree(tmparyval);
            }
@@ -1312,7 +1355,7 @@ int *arglast;
        else if (length) {
            st[sp] = tmparyval[length-1];
            if (ary->ary_flags & ARF_REAL)
-               str_2static(st[sp]);
+               str_2mortal(st[sp]);
            Safefree(tmparyval);
        }
        else
@@ -1346,10 +1389,12 @@ int *arglast;
     }
     arg = arg[1].arg_ptr.arg_arg;
     while (i-- > 0) {
-       if (st[src])
+       if (st[src]) {
+           st[src]->str_pok &= ~SP_TEMP;
            stab_val(defstab) = st[src];
+       }
        else
-           stab_val(defstab) = str_static(&str_undef);
+           stab_val(defstab) = str_mortal(&str_undef);
        (void)eval(arg,G_SCALAR,sp);
        st = stack->ary_array;
        if (str_true(st[sp+1]))
@@ -1418,9 +1463,9 @@ static STAB *firststab = Nullstab;
 static STAB *secondstab = Nullstab;
 
 int
-do_sort(str,stab,gimme,arglast)
+do_sort(str,arg,gimme,arglast)
 STR *str;
-STAB *stab;
+ARG *arg;
 int gimme;
 int *arglast;
 {
@@ -1434,6 +1479,7 @@ int *arglast;
     STR *oldfirst;
     STR *oldsecond;
     ARRAY *oldstack;
+    HASH *stash;
     static ARRAY *sortstack = Null(ARRAY*);
 
     if (gimme != G_ARRAY) {
@@ -1445,6 +1491,7 @@ int *arglast;
     up = &st[sp];
     st += sp;          /* temporarily make st point to args */
     for (i = 1; i <= max; i++) {
+       /*SUPPRESS 560*/
        if (*up = st[i]) {
            if (!(*up)->str_pok)
                (void)str_2ptr(*up);
@@ -1457,11 +1504,31 @@ int *arglast;
     max = up - &st[sp];
     sp--;
     if (max > 1) {
-       if (stab) {
+       STAB *stab;
+
+       if (arg[1].arg_type == (A_CMD|A_DONT)) {
+           sortcmd = arg[1].arg_ptr.arg_cmd;
+           stash = curcmd->c_stash;
+       }
+       else {
+           if ((arg[1].arg_type & A_MASK) == A_WORD)
+               stab = arg[1].arg_ptr.arg_stab;
+           else
+               stab = stabent(str_get(st[sp+1]),TRUE);
+
+           if (stab) {
+               if (!stab_sub(stab) || !(sortcmd = stab_sub(stab)->cmd))
+                   fatal("Undefined subroutine \"%s\" in sort", 
+                       stab_name(stab));
+               stash = stab_stash(stab);
+           }
+           else
+               sortcmd = Nullcmd;
+       }
+
+       if (sortcmd) {
            int oldtmps_base = tmps_base;
 
-           if (!stab_sub(stab) || !(sortcmd = stab_sub(stab)->cmd))
-               fatal("Undefined subroutine \"%s\" in sort", stab_name(stab));
            if (!sortstack) {
                sortstack = anew(Nullstab);
                astore(sortstack, 0, Nullstr);
@@ -1471,10 +1538,10 @@ int *arglast;
            oldstack = stack;
            stack = sortstack;
            tmps_base = tmps_max;
-           if (sortstash != stab_stash(stab)) {
+           if (sortstash != stash) {
                firststab = stabent("a",TRUE);
                secondstab = stabent("b",TRUE);
-               sortstash = stab_stash(stab);
+               sortstash = stash;
            }
            oldfirst = stab_val(firststab);
            oldsecond = stab_val(secondstab);
@@ -1516,11 +1583,13 @@ STR **strp2;
     int retval;
 
     if (str1->str_cur < str2->str_cur) {
+       /*SUPPRESS 560*/
        if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
            return retval;
        else
            return -1;
     }
+    /*SUPPRESS 560*/
     else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
        return retval;
     else if (str1->str_cur == str2->str_cur)
@@ -1544,24 +1613,26 @@ int *arglast;
     if (gimme != G_ARRAY)
        fatal("panic: do_range");
 
-    if (st[sp+1]->str_nok ||
+    if (st[sp+1]->str_nok || !st[sp+1]->str_pok ||
       (looks_like_number(st[sp+1]) && *st[sp+1]->str_ptr != '0') ) {
        i = (int)str_gnum(st[sp+1]);
        max = (int)str_gnum(st[sp+2]);
+       if (max > i)
+           (void)astore(ary, sp + max - i + 1, Nullstr);
        while (i <= max) {
-           (void)astore(ary, ++sp, str = str_static(&str_no));
+           (void)astore(ary, ++sp, str = str_mortal(&str_no));
            str_numset(str,(double)i++);
        }
     }
     else {
-       STR *final = str_static(st[sp+2]);
+       STR *final = str_mortal(st[sp+2]);
        char *tmps = str_get(final);
 
-       str = str_static(st[sp+1]);
+       str = str_mortal(st[sp+1]);
        while (!str->str_nok && str->str_cur <= final->str_cur &&
            strNE(str->str_ptr,tmps) ) {
            (void)astore(ary, ++sp, str);
-           str = str_2static(str_smake(str));
+           str = str_2mortal(str_smake(str));
            str_inc(str);
        }
        if (strEQ(str->str_ptr,tmps))
@@ -1571,6 +1642,33 @@ int *arglast;
 }
 
 int
+do_repeatary(arglast)
+int *arglast;
+{
+    STR **st = stack->ary_array;
+    register int sp = arglast[0];
+    register int items = arglast[1] - sp;
+    register int count = (int) str_gnum(st[arglast[2]]);
+    register int i;
+    int max;
+
+    max = items * count;
+    if (max > 0 && sp + max > stack->ary_max) {
+       astore(stack, sp + max, Nullstr);
+       st = stack->ary_array;
+    }
+    if (count > 1) {
+       for (i = arglast[1]; i > sp; i--)
+           st[i]->str_pok &= ~SP_TEMP;
+       repeatcpy((char*)&st[arglast[1]+1], (char*)&st[sp+1],
+           items * sizeof(STR*), count);
+    }
+    sp += max;
+
+    return sp;
+}
+
+int
 do_caller(arg,maxarg,gimme,arglast)
 ARG *arg;
 int maxarg;
@@ -1606,23 +1704,25 @@ int *arglast;
 
 #ifndef lint
     (void)astore(stack,++sp,
-      str_2static(str_make(csv->curcmd->c_stash->tbl_name,0)) );
+      str_2mortal(str_make(csv->curcmd->c_stash->tbl_name,0)) );
     (void)astore(stack,++sp,
-      str_2static(str_make(stab_val(csv->curcmd->c_filestab)->str_ptr,0)) );
+      str_2mortal(str_make(stab_val(csv->curcmd->c_filestab)->str_ptr,0)) );
     (void)astore(stack,++sp,
-      str_2static(str_nmake((double)csv->curcmd->c_line)) );
+      str_2mortal(str_nmake((double)csv->curcmd->c_line)) );
     if (!maxarg)
        return sp;
     str = Str_new(49,0);
     stab_fullname(str, csv->stab);
-    (void)astore(stack,++sp, str_2static(str));
+    (void)astore(stack,++sp, str_2mortal(str));
     (void)astore(stack,++sp,
-      str_2static(str_nmake((double)csv->hasargs)) );
+      str_2mortal(str_nmake((double)csv->hasargs)) );
     (void)astore(stack,++sp,
-      str_2static(str_nmake((double)csv->wantarray)) );
+      str_2mortal(str_nmake((double)csv->wantarray)) );
     if (csv->hasargs) {
        ARRAY *ary = csv->argarray;
 
+       if (!dbargs)
+           dbargs = stab_xarray(aadd(stabent("DB'args", TRUE)));
        if (dbargs->ary_max < ary->ary_fill)
            astore(dbargs,ary->ary_fill,Nullstr);
        Copy(ary->ary_array, dbargs->ary_array, ary->ary_fill+1, STR*);
@@ -1630,7 +1730,7 @@ int *arglast;
     }
 #else
     (void)astore(stack,++sp,
-      str_2static(str_make("",0)));
+      str_2mortal(str_make("",0)));
 #endif
     return sp;
 }
@@ -1661,16 +1761,16 @@ int *arglast;
 
 #ifndef lint
     (void)astore(stack,++sp,
-      str_2static(str_nmake(((double)timesbuf.tms_utime)/HZ)));
+      str_2mortal(str_nmake(((double)timesbuf.tms_utime)/HZ)));
     (void)astore(stack,++sp,
-      str_2static(str_nmake(((double)timesbuf.tms_stime)/HZ)));
+      str_2mortal(str_nmake(((double)timesbuf.tms_stime)/HZ)));
     (void)astore(stack,++sp,
-      str_2static(str_nmake(((double)timesbuf.tms_cutime)/HZ)));
+      str_2mortal(str_nmake(((double)timesbuf.tms_cutime)/HZ)));
     (void)astore(stack,++sp,
-      str_2static(str_nmake(((double)timesbuf.tms_cstime)/HZ)));
+      str_2mortal(str_nmake(((double)timesbuf.tms_cstime)/HZ)));
 #else
     (void)astore(stack,++sp,
-      str_2static(str_nmake(0.0)));
+      str_2mortal(str_nmake(0.0)));
 #endif
     return sp;
 #endif
@@ -1693,15 +1793,15 @@ int *arglast;
        st[++sp] = str;
        return sp;
     }
-    (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_sec)));
-    (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_min)));
-    (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_hour)));
-    (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mday)));
-    (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mon)));
-    (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_year)));
-    (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_wday)));
-    (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_yday)));
-    (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_isdst)));
+    (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_sec)));
+    (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_min)));
+    (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_hour)));
+    (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_mday)));
+    (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_mon)));
+    (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_year)));
+    (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_wday)));
+    (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_yday)));
+    (void)astore(ary,++sp,str_2mortal(str_nmake((double)tmbuf->tm_isdst)));
     return sp;
 }
 
@@ -1730,12 +1830,13 @@ int *arglast;
        return sp;
     }
     (void)hiterinit(hash);
+    /*SUPPRESS 560*/
     while (entry = hiternext(hash)) {
        if (dokeys) {
            tmps = hiterkey(entry,&i);
            if (!i)
                tmps = "";
-           (void)astore(ary,++sp,str_2static(str_make(tmps,i)));
+           (void)astore(ary,++sp,str_2mortal(str_make(tmps,i)));
        }
        if (dovalues) {
            tmpstr = Str_new(45,0);
@@ -1748,7 +1849,7 @@ int *arglast;
            else
 #endif
            str_sset(tmpstr,hiterval(hash,entry));
-           (void)astore(ary,++sp,str_2static(tmpstr));
+           (void)astore(ary,++sp,str_2mortal(tmpstr));
        }
     }
     return sp;