perl 4.0 patch 32: patch #20, continued
[p5sagit/p5-mst-13.2.git] / stab.c
diff --git a/stab.c b/stab.c
index f968dfc..f8e6f07 100644 (file)
--- a/stab.c
+++ b/stab.c
@@ -1,56 +1,40 @@
-/* $Header: stab.c,v 3.0.1.9 90/10/16 10:32:05 lwall Locked $
+/* $RCSfile: stab.c,v $$Revision: 4.0.1.4 $$Date: 92/06/08 15:32:19 $
  *
- *    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:       stab.c,v $
- * Revision 3.0.1.9  90/10/16  10:32:05  lwall
- * patch29: added -M, -A and -C
- * patch29: taintperl now checks for world writable PATH components
- * patch29: *foo now prints as *package'foo
- * patch29: scripts now run at almost full speed under the debugger
- * patch29: package behavior is now more consistent
+ * Revision 4.0.1.4  92/06/08  15:32:19  lwall
+ * patch20: fixed confusion between a *var's real name and its effective name
+ * patch20: the debugger now warns you on lines that can't set a breakpoint
+ * patch20: the debugger made perl forget the last pattern used by //
+ * patch20: paragraph mode now skips extra newlines automatically
+ * patch20: ($<,$>) = ... didn't work on some architectures
  * 
- * Revision 3.0.1.8  90/08/13  22:30:17  lwall
- * patch28: the NSIG hack didn't work right on Xenix
+ * Revision 4.0.1.3  91/11/05  18:35:33  lwall
+ * patch11: length($x) was sometimes wrong for numeric $x
+ * patch11: perl now issues warning if $SIG{'ALARM'} is referenced
+ * patch11: *foo = undef coredumped
+ * patch11: solitary subroutine references no longer trigger typo warnings
+ * patch11: local(*FILEHANDLE) had a memory leak
  * 
- * Revision 3.0.1.7  90/08/09  05:17:48  lwall
- * patch19: fixed double include of <signal.h>
- * patch19: $' broke on embedded nulls
- * patch19: $< and $> better supported on machines without setreuid
- * patch19: Added support for linked-in C subroutines
- * patch19: %ENV wasn't forced to be global like it should
- * patch19: $| didn't work before the filehandle was opened
- * patch19: $! now returns "" in string context if errno == 0
+ * Revision 4.0.1.2  91/06/07  11:55:53  lwall
+ * patch4: new copyright notice
+ * patch4: added $^P variable to control calling of perldb routines
+ * patch4: added $^F variable to specify maximum system fd, default 2
+ * patch4: $` was busted inside s///
+ * patch4: default top-of-form format is now FILEHANDLE_TOP
+ * patch4: length($`), length($&), length($') now optimized to avoid string copy
+ * patch4: $^D |= 1024 now does syntax tree dump at run-time
  * 
- * Revision 3.0.1.6  90/03/27  16:22:11  lwall
- * patch16: support for machines that can't cast negative floats to unsigned ints
+ * Revision 4.0.1.1  91/04/12  09:10:24  lwall
+ * patch1: Configure now differentiates getgroups() type from getgid() type
+ * patch1: you may now use "die" and "caller" in a signal handler
  * 
- * Revision 3.0.1.5  90/03/12  17:00:11  lwall
- * patch13: undef $/ didn't work as advertised
- * 
- * Revision 3.0.1.4  90/02/28  18:19:14  lwall
- * patch9: $0 is now always the command name
- * patch9: you may now undef $/ to have no input record separator
- * patch9: local($.) didn't work
- * patch9: sometimes perl thought ordinary data was a symbol table entry
- * patch9: stab_array() and stab_hash() weren't defined on MICROPORT
- * 
- * Revision 3.0.1.3  89/12/21  20:18:40  lwall
- * patch7: ANSI strerror() is now supported
- * patch7: errno may now be a macro with an lvalue
- * patch7: in stab.c, sighandler() may now return either void or int
- * 
- * Revision 3.0.1.2  89/11/17  15:35:37  lwall
- * patch5: sighandler() needed to be static
- * 
- * Revision 3.0.1.1  89/11/11  04:55:07  lwall
- * patch2: sys_errlist[sys_nerr] is illegal
- * 
- * Revision 3.0  89/10/18  15:23:23  lwall
- * 3.0 baseline
+ * Revision 4.0  91/03/20  01:39:41  lwall
+ * 4.0 baseline.
  * 
  */
 
@@ -71,6 +55,10 @@ static char *sig_name[] = {
 #define handlertype int
 #endif
 
+static handlertype sighandler();
+
+static int origalen = 0;
+
 STR *
 stab_str(str)
 STR *str;
@@ -84,13 +72,33 @@ STR *str;
        return stab_val(stab);
 
     switch (*stab->str_magic->str_ptr) {
+    case '\004':               /* ^D */
+#ifdef DEBUGGING
+       str_numset(stab_val(stab),(double)(debug & 32767));
+#endif
+       break;
+    case '\006':               /* ^F */
+       str_numset(stab_val(stab),(double)maxsysfd);
+       break;
+    case '\t':                 /* ^I */
+       if (inplace)
+           str_set(stab_val(stab), inplace);
+       else
+           str_sset(stab_val(stab),&str_undef);
+       break;
+    case '\020':               /* ^P */
+       str_numset(stab_val(stab),(double)perldb);
+       break;
     case '\024':               /* ^T */
        str_numset(stab_val(stab),(double)basetime);
        break;
+    case '\027':               /* ^W */
+       str_numset(stab_val(stab),(double)dowarn);
+       break;
     case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9': case '&':
        if (curspat) {
-           paren = atoi(stab_name(stab));
+           paren = atoi(stab_ename(stab));
          getparen:
            if (curspat->spat_regexp &&
              paren <= curspat->spat_regexp->nparens &&
@@ -114,7 +122,7 @@ STR *str;
     case '`':
        if (curspat) {
            if (curspat->spat_regexp &&
-             (s = curspat->spat_regexp->subbase) ) {
+             (s = curspat->spat_regexp->subbeg) ) {
                i = curspat->spat_regexp->startp[0] - s;
                if (i >= 0)
                    str_nset(stab_val(stab),s,i);
@@ -137,7 +145,7 @@ STR *str;
        break;
     case '.':
 #ifndef lint
-       if (last_in_stab) {
+       if (last_in_stab && stab_io(last_in_stab)) {
            str_numset(stab_val(stab),(double)stab_io(last_in_stab)->lines);
        }
 #endif
@@ -147,10 +155,17 @@ STR *str;
        break;
     case '^':
        s = stab_io(curoutstab)->top_name;
-       str_set(stab_val(stab),s);
+       if (s)
+           str_set(stab_val(stab),s);
+       else {
+           str_set(stab_val(stab),stab_ename(curoutstab));
+           str_cat(stab_val(stab),"_TOP");
+       }
        break;
     case '~':
        s = stab_io(curoutstab)->fmt_name;
+       if (!s)
+           s = stab_ename(curoutstab);
        str_set(stab_val(stab),s);
        break;
 #ifndef lint
@@ -164,12 +179,9 @@ STR *str;
        str_numset(stab_val(stab),(double)stab_io(curoutstab)->page);
        break;
 #endif
+    case ':':
+       break;
     case '/':
-       if (record_separator != 12345) {
-           *tokenbuf = record_separator;
-           tokenbuf[1] = '\0';
-           str_nset(stab_val(stab),tokenbuf,rslen);
-       }
        break;
     case '[':
        str_numset(stab_val(stab),(double)arybase);
@@ -209,12 +221,12 @@ STR *str;
        (void)sprintf(s,"%d",(int)egid);
       add_groups:
        while (*s) s++;
-#ifdef GETGROUPS
+#ifdef HAS_GETGROUPS
 #ifndef NGROUPS
 #define NGROUPS 32
 #endif
        {
-           GIDTYPE gary[NGROUPS];
+           GROUPSTYPE gary[NGROUPS];
 
            i = getgroups(NGROUPS,gary);
            while (--i >= 0) {
@@ -225,6 +237,10 @@ STR *str;
 #endif
        str_set(stab_val(stab),buf);
        break;
+    case '*':
+       break;
+    case '0':
+       break;
     default:
        {
            struct ufuncs *uf = (struct ufuncs *)str->str_ptr;
@@ -237,18 +253,88 @@ STR *str;
     return stab_val(stab);
 }
 
+STRLEN
+stab_len(str)
+STR *str;
+{
+    STAB *stab = str->str_u.str_stab;
+    int paren;
+    int i;
+    char *s;
+
+    if (str->str_rare)
+       return str_len(stab_val(stab));
+
+    switch (*stab->str_magic->str_ptr) {
+    case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9': case '&':
+       if (curspat) {
+           paren = atoi(stab_ename(stab));
+         getparen:
+           if (curspat->spat_regexp &&
+             paren <= curspat->spat_regexp->nparens &&
+             (s = curspat->spat_regexp->startp[paren]) ) {
+               i = curspat->spat_regexp->endp[paren] - s;
+               if (i >= 0)
+                   return i;
+               else
+                   return 0;
+           }
+           else
+               return 0;
+       }
+       break;
+    case '+':
+       if (curspat) {
+           paren = curspat->spat_regexp->lastparen;
+           goto getparen;
+       }
+       break;
+    case '`':
+       if (curspat) {
+           if (curspat->spat_regexp &&
+             (s = curspat->spat_regexp->subbeg) ) {
+               i = curspat->spat_regexp->startp[0] - s;
+               if (i >= 0)
+                   return i;
+               else
+                   return 0;
+           }
+           else
+               return 0;
+       }
+       break;
+    case '\'':
+       if (curspat) {
+           if (curspat->spat_regexp &&
+             (s = curspat->spat_regexp->endp[0]) ) {
+               return (STRLEN) (curspat->spat_regexp->subend - s);
+           }
+           else
+               return 0;
+       }
+       break;
+    case ',':
+       return (STRLEN)ofslen;
+    case '\\':
+       return (STRLEN)orslen;
+    default:
+       return str_len(stab_str(str));
+    }
+}
+
+void
 stabset(mstr,str)
 register STR *mstr;
 STR *str;
 {
-    STAB *stab = mstr->str_u.str_stab;
-    char *s;
+    STAB *stab;
+    register char *s;
     int i;
-    static handlertype sighandler();
 
     switch (mstr->str_rare) {
     case 'E':
-       setenv(mstr->str_ptr,str_get(str));
+       my_setenv(mstr->str_ptr,str_get(str));
                                /* And you'll never guess what the dog had */
                                /*   in its mouth... */
 #ifdef TAINT
@@ -269,6 +355,8 @@ STR *str;
     case 'S':
        s = str_get(str);
        i = whichsig(mstr->str_ptr);    /* ...no, a brick */
+       if (!i && (dowarn || strEQ(mstr->str_ptr,"ALARM")))
+           warn("No such signal: SIG%s", mstr->str_ptr);
        if (strEQ(s,"IGNORE"))
 #ifndef lint
            (void)signal(i,SIG_IGN);
@@ -287,6 +375,7 @@ STR *str;
        break;
 #ifdef SOME_DBM
     case 'D':
+       stab = mstr->str_u.str_stab;
        hdbmstore(stab_hash(stab),mstr->str_ptr,mstr->str_cur,str);
        break;
 #endif
@@ -294,24 +383,31 @@ STR *str;
        {
            CMD *cmd;
 
+           stab = mstr->str_u.str_stab;
            i = str_true(str);
-           str = afetch(stab_xarray(stab),atoi(mstr->str_ptr));
-           cmd = str->str_magic->str_u.str_cmd;
-           cmd->c_flags &= ~CF_OPTIMIZE;
-           cmd->c_flags |= i? CFT_D1 : CFT_D0;
+           str = afetch(stab_xarray(stab),atoi(mstr->str_ptr), FALSE);
+           if (str->str_magic && (cmd = str->str_magic->str_u.str_cmd)) {
+               cmd->c_flags &= ~CF_OPTIMIZE;
+               cmd->c_flags |= i? CFT_D1 : CFT_D0;
+           }
+           else
+               warn("Can't break at that line\n");
        }
        break;
     case '#':
+       stab = mstr->str_u.str_stab;
        afill(stab_array(stab), (int)str_gnum(str) - arybase);
        break;
     case 'X':  /* merely a copy of a * string */
        break;
     case '*':
-       s = str_get(str);
+       s = str->str_pok ? str_get(str) : "";
        if (strNE(s,"StB") || str->str_cur != sizeof(STBP)) {
+           stab = mstr->str_u.str_stab;
            if (!*s) {
                STBP *stbp;
 
+               /*SUPPRESS 701*/
                (void)savenostab(stab); /* schedule a free of this stab */
                if (stab->str_len)
                    Safefree(stab->str_ptr);
@@ -322,6 +418,7 @@ STR *str;
                strcpy(stab_magic(stab),"StB");
                stab_val(stab) = Str_new(70,0);
                stab_line(stab) = curcmd->c_line;
+               stab_estab(stab) = stab;
            }
            else {
                stab = stabent(s,TRUE);
@@ -332,16 +429,18 @@ STR *str;
                if (!stab_io(stab))
                    stab_io(stab) = stio_new();
            }
-           str_sset(str,stab);
+           str_sset(str, (STR*) stab);
        }
        break;
     case 's': {
            struct lstring *lstr = (struct lstring*)str;
+           char *tmps;
 
            mstr->str_rare = 0;
            str->str_magic = Nullstr;
+           tmps = str_get(str);
            str_insert(mstr,lstr->lstr_offset,lstr->lstr_len,
-             str->str_ptr,str->str_cur);
+             tmps,str->str_cur);
        }
        break;
 
@@ -350,9 +449,45 @@ STR *str;
        break;
 
     case 0:
+       /*SUPPRESS 560*/
+       if (!(stab = mstr->str_u.str_stab))
+           break;
        switch (*stab->str_magic->str_ptr) {
+       case '\004':    /* ^D */
+#ifdef DEBUGGING
+           debug = (int)(str_gnum(str)) | 32768;
+           if (debug & 1024)
+               dump_all();
+#endif
+           break;
+       case '\006':    /* ^F */
+           maxsysfd = (int)str_gnum(str);
+           break;
+       case '\t':      /* ^I */
+           if (inplace)
+               Safefree(inplace);
+           if (str->str_pok || str->str_nok)
+               inplace = savestr(str_get(str));
+           else
+               inplace = Nullch;
+           break;
+       case '\020':    /* ^P */
+           i = (int)str_gnum(str);
+           if (i != perldb) {
+               static SPAT *oldlastspat;
+
+               if (perldb)
+                   oldlastspat = lastspat;
+               else
+                   lastspat = oldlastspat;
+           }
+           perldb = i;
+           break;
        case '\024':    /* ^T */
-           basetime = (long)str_gnum(str);
+           basetime = (time_t)str_gnum(str);
+           break;
+       case '\027':    /* ^W */
+           dowarn = (bool)str_gnum(str);
            break;
        case '.':
            if (localizing)
@@ -393,11 +528,16 @@ STR *str;
            break;
        case '/':
            if (str->str_pok) {
-               record_separator = *str_get(str);
+               rs = str_get(str);
                rslen = str->str_cur;
+               if (rspara = !rslen) {
+                   rs = "\n\n";
+                   rslen = 2;
+               }
+               rschar = rs[rslen - 1];
            }
            else {
-               record_separator = 12345;       /* fake a non-existent char */
+               rschar = 0777;  /* fake a non-existent char */
                rslen = 1;
            }
            break;
@@ -429,42 +569,35 @@ STR *str;
            break;
        case '<':
            uid = (int)str_gnum(str);
-#ifdef SETREUID
            if (delaymagic) {
-               delaymagic |= DM_REUID;
+               delaymagic |= DM_RUID;
                break;                          /* don't do magic till later */
            }
-#endif /* SETREUID */
-#ifdef SETRUID
-           if (setruid((UIDTYPE)uid) < 0)
-               uid = (int)getuid();
+#ifdef HAS_SETRUID
+           (void)setruid((UIDTYPE)uid);
 #else
-#ifdef SETREUID
-           if (setreuid((UIDTYPE)uid, (UIDTYPE)-1) < 0)
-               uid = (int)getuid();
+#ifdef HAS_SETREUID
+           (void)setreuid((UIDTYPE)uid, (UIDTYPE)-1);
 #else
            if (uid == euid)            /* special case $< = $> */
-               setuid(uid);
+               (void)setuid(uid);
            else
                fatal("setruid() not implemented");
 #endif
 #endif
+           uid = (int)getuid();
            break;
        case '>':
            euid = (int)str_gnum(str);
-#ifdef SETREUID
            if (delaymagic) {
-               delaymagic |= DM_REUID;
+               delaymagic |= DM_EUID;
                break;                          /* don't do magic till later */
            }
-#endif /* SETREUID */
-#ifdef SETEUID
-           if (seteuid((UIDTYPE)euid) < 0)
-               euid = (int)geteuid();
+#ifdef HAS_SETEUID
+           (void)seteuid((UIDTYPE)euid);
 #else
-#ifdef SETREUID
-           if (setreuid((UIDTYPE)-1, (UIDTYPE)euid) < 0)
-               euid = (int)geteuid();
+#ifdef HAS_SETREUID
+           (void)setreuid((UIDTYPE)-1, (UIDTYPE)euid);
 #else
            if (euid == uid)            /* special case $> = $< */
                setuid(euid);
@@ -472,46 +605,85 @@ STR *str;
                fatal("seteuid() not implemented");
 #endif
 #endif
+           euid = (int)geteuid();
            break;
        case '(':
            gid = (int)str_gnum(str);
-#ifdef SETREGID
            if (delaymagic) {
-               delaymagic |= DM_REGID;
+               delaymagic |= DM_RGID;
                break;                          /* don't do magic till later */
            }
-#endif /* SETREGID */
-#ifdef SETRGID
+#ifdef HAS_SETRGID
            (void)setrgid((GIDTYPE)gid);
 #else
-#ifdef SETREGID
+#ifdef HAS_SETREGID
            (void)setregid((GIDTYPE)gid, (GIDTYPE)-1);
 #else
-           fatal("setrgid() not implemented");
+           if (gid == egid)                    /* special case $( = $) */
+               (void)setgid(gid);
+           else
+               fatal("setrgid() not implemented");
 #endif
 #endif
+           gid = (int)getgid();
            break;
        case ')':
            egid = (int)str_gnum(str);
-#ifdef SETREGID
            if (delaymagic) {
-               delaymagic |= DM_REGID;
+               delaymagic |= DM_EGID;
                break;                          /* don't do magic till later */
            }
-#endif /* SETREGID */
-#ifdef SETEGID
+#ifdef HAS_SETEGID
            (void)setegid((GIDTYPE)egid);
 #else
-#ifdef SETREGID
+#ifdef HAS_SETREGID
            (void)setregid((GIDTYPE)-1, (GIDTYPE)egid);
 #else
-           fatal("setegid() not implemented");
+           if (egid == gid)                    /* special case $) = $( */
+               (void)setgid(egid);
+           else
+               fatal("setegid() not implemented");
 #endif
 #endif
+           egid = (int)getegid();
            break;
        case ':':
            chopset = str_get(str);
            break;
+       case '0':
+           if (!origalen) {
+               s = origargv[0];
+               s += strlen(s);
+               /* See if all the arguments are contiguous in memory */
+               for (i = 1; i < origargc; i++) {
+                   if (origargv[i] == s + 1)
+                       s += strlen(++s);       /* this one is ok too */
+               }
+               if (origenviron[0] == s + 1) {  /* can grab env area too? */
+                   my_setenv("NoNeSuCh", Nullch);
+                                               /* force copy of environment */
+                   for (i = 0; origenviron[i]; i++)
+                       if (origenviron[i] == s + 1)
+                           s += strlen(++s);
+               }
+               origalen = s - origargv[0];
+           }
+           s = str_get(str);
+           i = str->str_cur;
+           if (i >= origalen) {
+               i = origalen;
+               str->str_cur = i;
+               str->str_ptr[i] = '\0';
+               Copy(s, origargv[0], i, char);
+           }
+           else {
+               Copy(s, origargv[0], i, char);
+               s = origargv[0]+i;
+               *s++ = '\0';
+               while (++i < origalen)
+                   *s++ = ' ';
+           }
+           break;
        default:
            {
                struct ufuncs *uf = (struct ufuncs *)str->str_magic->str_ptr;
@@ -525,6 +697,7 @@ STR *str;
     }
 }
 
+int
 whichsig(sig)
 char *sig;
 {
@@ -549,18 +722,15 @@ sighandler(sig)
 int sig;
 {
     STAB *stab;
-    ARRAY *savearray;
     STR *str;
-    CMD *oldcurcmd = curcmd;
     int oldsave = savestack->ary_fill;
-    ARRAY *oldstack = stack;
-    CSV *oldcurcsv = curcsv;
+    int oldtmps_base = tmps_base;
+    register CSV *csv;
     SUBR *sub;
 
 #ifdef OS2             /* or anybody else who requires SIG_ACK */
     signal(sig, SIG_ACK);
 #endif
-    curcsv = Nullcsv;
     stab = stabent(
        str_get(hfetch(stab_hash(sigstab),sig_name[sig],strlen(sig_name[sig]),
          TRUE)), TRUE);
@@ -577,33 +747,41 @@ int sig;
     if (!sub) {
        if (dowarn)
            warn("SIG%s handler \"%s\" not defined.\n",
-               sig_name[sig], stab_name(stab) );
+               sig_name[sig], stab_ename(stab) );
        return;
     }
-    savearray = stab_xarray(defstab);
-    stab_xarray(defstab) = stack = anew(defstab);
+    /*SUPPRESS 701*/
+    saveaptr(&stack);
+    str = Str_new(15, sizeof(CSV));
+    str->str_state = SS_SCSV;
+    (void)apush(savestack,str);
+    csv = (CSV*)str->str_ptr;
+    csv->sub = sub;
+    csv->stab = stab;
+    csv->curcsv = curcsv;
+    csv->curcmd = curcmd;
+    csv->depth = sub->depth;
+    csv->wantarray = G_SCALAR;
+    csv->hasargs = TRUE;
+    csv->savearray = stab_xarray(defstab);
+    csv->argarray = stab_xarray(defstab) = stack = anew(defstab);
     stack->ary_flags = 0;
-    str = Str_new(71,0);
+    curcsv = csv;
+    str = str_mortal(&str_undef);
     str_set(str,sig_name[sig]);
     (void)apush(stab_xarray(defstab),str);
     sub->depth++;
     if (sub->depth >= 2) {     /* save temporaries on recursion? */
        if (sub->depth == 100 && dowarn)
-           warn("Deep recursion on subroutine \"%s\"",stab_name(stab));
+           warn("Deep recursion on subroutine \"%s\"",stab_ename(stab));
        savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
     }
 
-    (void)cmd_exec(sub->cmd,G_SCALAR,1);               /* so do it already */
-
-    sub->depth--;      /* assuming no longjumps out of here */
-    str_free(stack->ary_array[0]);     /* free the one real string */
-    afree(stab_xarray(defstab));  /* put back old $_[] */
-    stab_xarray(defstab) = savearray;
-    stack = oldstack;
-    if (savestack->ary_fill > oldsave)
-       restorelist(oldsave);
-    curcmd = oldcurcmd;
-    curcsv = oldcurcsv;
+    tmps_base = tmps_max;              /* protect our mortal string */
+    (void)cmd_exec(sub->cmd,G_SCALAR,0);               /* so do it already */
+    tmps_base = oldtmps_base;
+
+    restorelist(oldsave);              /* put everything back */
 }
 
 STAB *
@@ -653,7 +831,7 @@ int add;
     char *prevquote = Nullch;
     bool global = FALSE;
 
-    if (isascii(*name) && isupper(*name)) {
+    if (isUPPER(*name)) {
        if (*name > 'I') {
            if (*name == 'S' && (
              strEQ(name, "SIG") ||
@@ -684,9 +862,9 @@ int add;
        sawquote = Nullch;
        name++;
     }
-    else if (!isalpha(*name) || global)
+    else if (!isALPHA(*name) || global)
        stash = defstash;
-    else if (curcmd == &compiling)
+    else if ((CMD*)curcmd == &compiling)
        stash = curstash;
     else
        stash = curcmd->c_stash;
@@ -695,6 +873,7 @@ int add;
        char *s, *d;
 
        *sawquote = '\0';
+       /*SUPPRESS 560*/
        if (s = prevquote) {
            strncpy(tmpbuf,name,s-name+1);
            d = tmpbuf+(s-name+1);
@@ -731,21 +910,47 @@ int add;
        strcpy(stab_magic(stab),"StB");
        stab_val(stab) = Str_new(72,0);
        stab_line(stab) = curcmd->c_line;
-       str_magic(stab,stab,'*',name,len);
+       stab_estab(stab) = stab;
+       str_magic((STR*)stab, stab, '*', name, len);
        stab_stash(stab) = stash;
+       if (isDIGIT(*name) && *name != '0') {
+           stab_flags(stab) = SF_VMAGIC;
+           str_magic(stab_val(stab), stab, 0, Nullch, 0);
+       }
+       if (add & 2)
+           stab->str_pok |= SP_MULTI;
        return stab;
     }
 }
 
+void
 stab_fullname(str,stab)
 STR *str;
 STAB *stab;
 {
-    str_set(str,stab_stash(stab)->tbl_name);
+    HASH *tb = stab_stash(stab);
+
+    if (!tb)
+       return;
+    str_set(str,tb->tbl_name);
     str_ncat(str,"'", 1);
     str_scat(str,stab->str_magic);
 }
 
+void
+stab_efullname(str,stab)
+STR *str;
+STAB *stab;
+{
+    HASH *tb = stab_estash(stab);
+
+    if (!tb)
+       return;
+    str_set(str,tb->tbl_name);
+    str_ncat(str,"'", 1);
+    str_scat(str,stab_estab(stab)->str_magic);
+}
+
 STIO *
 stio_new()
 {
@@ -756,6 +961,7 @@ stio_new()
     return stio;
 }
 
+void
 stab_check(min,max)
 int min;
 register int max;
@@ -793,14 +999,22 @@ register STAB *stab;
     STIO *stio;
     SUBR *sub;
 
+    if (!stab || !stab->str_ptr)
+       return;
     afree(stab_xarray(stab));
+    stab_xarray(stab) = Null(ARRAY*);
     (void)hfree(stab_xhash(stab), FALSE);
+    stab_xhash(stab) = Null(HASH*);
     str_free(stab_val(stab));
+    stab_val(stab) = Nullstr;
+    /*SUPPRESS 560*/
     if (stio = stab_io(stab)) {
        do_close(stab,FALSE);
        Safefree(stio->top_name);
        Safefree(stio->fmt_name);
+       Safefree(stio);
     }
+    /*SUPPRESS 560*/
     if (sub = stab_sub(stab)) {
        afree(sub->tosave);
        cmd_free(sub->cmd);