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 d1f3571..f8e6f07 100644 (file)
--- a/stab.c
+++ b/stab.c
@@ -1,33 +1,63 @@
-/* $Header: stab.c,v 3.0.1.1 89/11/11 04:55:07 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.1  89/11/11  04:55:07  lwall
- * patch2: sys_errlist[sys_nerr] is illegal
+ * 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  89/10/18  15:23:23  lwall
- * 3.0 baseline
+ * 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 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 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 4.0  91/03/20  01:39:41  lwall
+ * 4.0 baseline.
  * 
  */
 
 #include "EXTERN.h"
 #include "perl.h"
 
+#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
 #include <signal.h>
-
-/* This oughta be generated by Configure. */
+#endif
 
 static char *sig_name[] = {
     SIG_NAME,0
 };
 
-extern int errno;
-extern int sys_nerr;
-extern char *sys_errlist[];
+#ifdef VOIDSIG
+#define handlertype void
+#else
+#define handlertype int
+#endif
+
+static handlertype sighandler();
+
+static int origalen = 0;
 
 STR *
 stab_str(str)
@@ -42,10 +72,33 @@ STR *str;
        return stab_val(stab);
 
     switch (*stab->str_magic->str_ptr) {
-    case '0': case '1': case '2': case '3': case '4':
+    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 &&
@@ -69,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);
@@ -84,7 +137,7 @@ STR *str;
        if (curspat) {
            if (curspat->spat_regexp &&
              (s = curspat->spat_regexp->endp[0]) ) {
-               str_set(stab_val(stab),s);
+               str_nset(stab_val(stab),s, curspat->spat_regexp->subend - s);
            }
            else
                str_nset(stab_val(stab),"",0);
@@ -92,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
@@ -102,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
@@ -119,15 +179,16 @@ STR *str;
        str_numset(stab_val(stab),(double)stab_io(curoutstab)->page);
        break;
 #endif
+    case ':':
+       break;
     case '/':
-       *tokenbuf = record_separator;
-       tokenbuf[1] = '\0';
-       str_nset(stab_val(stab),tokenbuf,rslen);
        break;
     case '[':
        str_numset(stab_val(stab),(double)arybase);
        break;
     case '|':
+       if (!stab_io(curoutstab))
+           stab_io(curoutstab) = stio_new();
        str_numset(stab_val(stab),
           (double)((stab_io(curoutstab)->flags & IOF_FLUSH) != 0) );
        break;
@@ -142,8 +203,7 @@ STR *str;
        break;
     case '!':
        str_numset(stab_val(stab), (double)errno);
-       str_set(stab_val(stab),
-         errno < 0 || errno >= sys_nerr ? "(unknown)" : sys_errlist[errno]);
+       str_set(stab_val(stab), errno ? strerror(errno) : "");
        stab_val(stab)->str_nok = 1;    /* what a wonderful hack! */
        break;
     case '<':
@@ -161,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) {
@@ -177,27 +237,126 @@ STR *str;
 #endif
        str_set(stab_val(stab),buf);
        break;
+    case '*':
+       break;
+    case '0':
+       break;
+    default:
+       {
+           struct ufuncs *uf = (struct ufuncs *)str->str_ptr;
+
+           if (uf && uf->uf_val)
+               (*uf->uf_val)(uf->uf_index, stab_val(stab));
+       }
+       break;
     }
     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;
-    int 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 */
-       break;                  /*   in its mouth... */
+                               /*   in its mouth... */
+#ifdef TAINT
+       if (strEQ(mstr->str_ptr,"PATH")) {
+           char *strend = str->str_ptr + str->str_cur;
+
+           s = str->str_ptr;
+           while (s < strend) {
+               s = cpytill(tokenbuf,s,strend,':',&i);
+               s++;
+               if (*tokenbuf != '/'
+                 || (stat(tokenbuf,&statbuf) && (statbuf.st_mode & 2)) )
+                   str->str_tainted = 2;
+           }
+       }
+#endif
+       break;
     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);
@@ -206,25 +365,49 @@ STR *str;
 #endif
        else if (strEQ(s,"DEFAULT") || !*s)
            (void)signal(i,SIG_DFL);
-       else
+       else {
            (void)signal(i,sighandler);
+           if (!index(s,'\'')) {
+               sprintf(tokenbuf, "main'%s",s);
+               str_set(str,tokenbuf);
+           }
+       }
        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
+    case 'L':
+       {
+           CMD *cmd;
+
+           stab = mstr->str_u.str_stab;
+           i = str_true(str);
+           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);
-       if (strnNE(s,"Stab",4) || str->str_cur != sizeof(STBP)) {
+       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);
@@ -232,22 +415,32 @@ STR *str;
                stab->str_ptr = stbp;
                stab->str_len = stab->str_cur = sizeof(STBP);
                stab->str_pok = 1;
-               strncpy(stab_magic(stab),"Stab",4);
+               strcpy(stab_magic(stab),"StB");
                stab_val(stab) = Str_new(70,0);
-               stab_line(stab) = line;
+               stab_line(stab) = curcmd->c_line;
+               stab_estab(stab) = stab;
            }
-           else
+           else {
                stab = stabent(s,TRUE);
-           str_sset(str,stab);
+               if (!stab_xarray(stab))
+                   aadd(stab);
+               if (!stab_xhash(stab))
+                   hadd(stab);
+               if (!stab_io(stab))
+                   stab_io(stab) = stio_new();
+           }
+           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;
 
@@ -256,7 +449,50 @@ 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 = (time_t)str_gnum(str);
+           break;
+       case '\027':    /* ^W */
+           dowarn = (bool)str_gnum(str);
+           break;
+       case '.':
+           if (localizing)
+               savesptr((STR**)&last_in_stab);
+           break;
        case '^':
            Safefree(stab_io(curoutstab)->top_name);
            stab_io(curoutstab)->top_name = s = savestr(str_get(str));
@@ -279,6 +515,8 @@ STR *str;
            stab_io(curoutstab)->page = (long)str_gnum(str);
            break;
        case '|':
+           if (!stab_io(curoutstab))
+               stab_io(curoutstab) = stio_new();
            stab_io(curoutstab)->flags &= ~IOF_FLUSH;
            if (str_gnum(str) != 0.0) {
                stab_io(curoutstab)->flags |= IOF_FLUSH;
@@ -289,8 +527,19 @@ STR *str;
            multiline = (i != 0);
            break;
        case '/':
-           record_separator = *str_get(str);
-           rslen = str->str_cur;
+           if (str->str_pok) {
+               rs = str_get(str);
+               rslen = str->str_cur;
+               if (rspara = !rslen) {
+                   rs = "\n\n";
+                   rslen = 2;
+               }
+               rschar = rs[rslen - 1];
+           }
+           else {
+               rschar = 0777;  /* fake a non-existent char */
+               rslen = 1;
+           }
            break;
        case '\\':
            if (ors)
@@ -313,95 +562,142 @@ STR *str;
            arybase = (int)str_gnum(str);
            break;
        case '?':
-           statusvalue = (unsigned short)str_gnum(str);
+           statusvalue = U_S(str_gnum(str));
            break;
        case '!':
            errno = (int)str_gnum(str);         /* will anyone ever use this? */
            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
-           fatal("setruid() not implemented");
+           if (uid == euid)            /* special case $< = $> */
+               (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
-           fatal("seteuid() not implemented");
+           if (euid == uid)            /* special case $> = $< */
+               setuid(euid);
+           else
+               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;
+
+               if (uf && uf->uf_set)
+                   (*uf->uf_set)(uf->uf_index, str);
+           }
+           break;
        }
        break;
     }
 }
 
+int
 whichsig(sig)
 char *sig;
 {
@@ -421,17 +717,20 @@ char *sig;
     return 0;
 }
 
+static handlertype
 sighandler(sig)
 int sig;
 {
     STAB *stab;
-    ARRAY *savearray;
     STR *str;
-    char *oldfile = filename;
     int oldsave = savestack->ary_fill;
-    ARRAY *oldstack = stack;
+    int oldtmps_base = tmps_base;
+    register CSV *csv;
     SUBR *sub;
 
+#ifdef OS2             /* or anybody else who requires SIG_ACK */
+    signal(sig, SIG_ACK);
+#endif
     stab = stabent(
        str_get(hfetch(stab_hash(sigstab),sig_name[sig],strlen(sig_name[sig]),
          TRUE)), TRUE);
@@ -448,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);
     }
-    filename = sub->filename;
-
-    (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;
-    filename = oldfile;
-    if (savestack->ary_fill > oldsave)
-       restorelist(oldsave);
+
+    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 *
@@ -496,6 +803,21 @@ register STAB *stab;
 }
 
 STAB *
+fstab(name)
+char *name;
+{
+    char tmpbuf[1200];
+    STAB *stab;
+
+    sprintf(tmpbuf,"'_<%s", name);
+    stab = stabent(tmpbuf, TRUE);
+    str_set(stab_val(stab), name);
+    if (perldb)
+       (void)hadd(aadd(stab));
+    return stab;
+}
+
+STAB *
 stabent(name,add)
 register char *name;
 int add;
@@ -509,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") ||
@@ -522,7 +844,7 @@ int add;
            if (*name == 'I' && strEQ(name, "INC"))
                global = TRUE;
        }
-       else if (*name >= 'A') {
+       else if (*name > 'A') {
            if (*name == 'E' && strEQ(name, "ENV"))
                global = TRUE;
        }
@@ -540,15 +862,18 @@ int add;
        sawquote = Nullch;
        name++;
     }
-    else if (!isalpha(*name) || global)
+    else if (!isALPHA(*name) || global)
        stash = defstash;
-    else
+    else if ((CMD*)curcmd == &compiling)
        stash = curstash;
+    else
+       stash = curcmd->c_stash;
     if (sawquote) {
        char tmpbuf[256];
        char *s, *d;
 
        *sawquote = '\0';
+       /*SUPPRESS 560*/
        if (s = prevquote) {
            strncpy(tmpbuf,name,s-name+1);
            d = tmpbuf+(s-name+1);
@@ -562,12 +887,14 @@ int add;
        stab = stabent(tmpbuf,TRUE);
        if (!(stash = stab_xhash(stab)))
            stash = stab_xhash(stab) = hnew(0);
+       if (!stash->tbl_name)
+           stash->tbl_name = savestr(name);
        name = sawquote+1;
        *sawquote = '\'';
     }
     len = namend - name;
     stab = (STAB*)hfetch(stash,name,len,add);
-    if (!stab)
+    if (stab == (STAB*)&str_undef)
        return Nullstab;
     if (stab->str_pok) {
        stab->str_pok |= SP_MULTI;
@@ -580,14 +907,50 @@ int add;
        stab->str_ptr = stbp;
        stab->str_len = stab->str_cur = sizeof(STBP);
        stab->str_pok = 1;
-       strncpy(stab_magic(stab),"Stab",4);
+       strcpy(stab_magic(stab),"StB");
        stab_val(stab) = Str_new(72,0);
-       stab_line(stab) = line;
-       str_magic(stab,stab,'*',name,len);
+       stab_line(stab) = curcmd->c_line;
+       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;
+{
+    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()
 {
@@ -598,6 +961,7 @@ stio_new()
     return stio;
 }
 
+void
 stab_check(min,max)
 int min;
 register int max;
@@ -611,7 +975,7 @@ register int max;
            stab = (STAB*)entry->hent_val;
            if (stab->str_pok & SP_MULTI)
                continue;
-           line = stab_line(stab);
+           curcmd->c_line = stab_line(stab);
            warn("Possible typo: \"%s\"", stab_name(stab));
        }
     }
@@ -635,14 +999,22 @@ register STAB *stab;
     STIO *stio;
     SUBR *sub;
 
+    if (!stab || !stab->str_ptr)
+       return;
     afree(stab_xarray(stab));
-    (void)hfree(stab_xhash(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);
@@ -653,3 +1025,26 @@ register STAB *stab;
     stab->str_cur = 0;
 }
 
+#if defined(CRIPPLED_CC) && (defined(iAPX286) || defined(M_I286) || defined(I80286))
+#define MICROPORT
+#endif
+
+#ifdef MICROPORT       /* Microport 2.4 hack */
+ARRAY *stab_array(stab)
+register STAB *stab;
+{
+    if (((STBP*)(stab->str_ptr))->stbp_array) 
+       return ((STBP*)(stab->str_ptr))->stbp_array;
+    else
+       return ((STBP*)(aadd(stab)->str_ptr))->stbp_array;
+}
+
+HASH *stab_hash(stab)
+register STAB *stab;
+{
+    if (((STBP*)(stab->str_ptr))->stbp_hash)
+       return ((STBP*)(stab->str_ptr))->stbp_hash;
+    else
+       return ((STBP*)(hadd(stab)->str_ptr))->stbp_hash;
+}
+#endif                 /* Microport 2.4 hack */