perl 3.0 patch #14 patch #13, continued
[p5sagit/p5-mst-13.2.git] / stab.c
diff --git a/stab.c b/stab.c
index 73d6f39..9d252bb 100644 (file)
--- a/stab.c
+++ b/stab.c
@@ -1,8 +1,34 @@
-/* $Header: stab.c,v 2.0 88/06/05 00:11:01 root Exp $
+/* $Header: stab.c,v 3.0.1.5 90/03/12 17:00:11 lwall Locked $
+ *
+ *    Copyright (c) 1989, 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.
  *
  * $Log:       stab.c,v $
- * Revision 2.0  88/06/05  00:11:01  root
- * Baseline version 2.0.
+ * 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
  * 
  */
 
 #include <signal.h>
 
 static char *sig_name[] = {
-    "",
-    "HUP",
-    "INT",
-    "QUIT",
-    "ILL",
-    "TRAP",
-    "IOT",
-    "EMT",
-    "FPE",
-    "KILL",
-    "BUS",
-    "SEGV",
-    "SYS",
-    "PIPE",
-    "ALRM",
-    "TERM",
-    "???"
-#ifdef SIGTSTP
-    ,"STOP",
-    "TSTP",
-    "CONT",
-    "CHLD",
-    "TTIN",
-    "TTOU",
-    "TINT",
-    "XCPU",
-    "XFSZ"
-#ifdef SIGPROF
-    ,"VTALARM",
-    "PROF"
-#ifdef SIGWINCH
-    ,"WINCH"
-#ifdef SIGLOST
-    ,"LOST"
-#ifdef SIGUSR1
-    ,"USR1"
+    SIG_NAME,0
+};
+
+#ifdef VOIDSIG
+#define handlertype void
+#else
+#define handlertype int
 #endif
-#ifdef SIGUSR2
-    ,"USR2"
-#endif /* SIGUSR2 */
-#endif /* SIGLOST */
-#endif /* SIGWINCH */
-#endif /* SIGPROF */
-#endif /* SIGTSTP */
-    ,0
-    };
-
-extern int errno;
-extern int sys_nerr;
-extern char *sys_errlist[];
 
 STR *
-stab_str(stab)
-STAB *stab;
+stab_str(str)
+STR *str;
 {
+    STAB *stab = str->str_u.str_stab;
     register int paren;
     register char *s;
     register int i;
 
-    switch (*stab->stab_name) {
-    case '0': case '1': case '2': case '3': case '4':
+    if (str->str_rare)
+       return 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->stab_name);
+           paren = atoi(stab_name(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)
-                   str_nset(stab->stab_val,s,i);
+                   str_nset(stab_val(stab),s,i);
                else
-                   str_nset(stab->stab_val,"",0);
+                   str_sset(stab_val(stab),&str_undef);
            }
            else
-               str_nset(stab->stab_val,"",0);
+               str_sset(stab_val(stab),&str_undef);
        }
        break;
     case '+':
@@ -96,71 +84,100 @@ STAB *stab;
            goto getparen;
        }
        break;
+    case '`':
+       if (curspat) {
+           if (curspat->spat_regexp &&
+             (s = curspat->spat_regexp->subbase) ) {
+               i = curspat->spat_regexp->startp[0] - s;
+               if (i >= 0)
+                   str_nset(stab_val(stab),s,i);
+               else
+                   str_nset(stab_val(stab),"",0);
+           }
+           else
+               str_nset(stab_val(stab),"",0);
+       }
+       break;
+    case '\'':
+       if (curspat) {
+           if (curspat->spat_regexp &&
+             (s = curspat->spat_regexp->endp[0]) ) {
+               str_set(stab_val(stab),s);
+           }
+           else
+               str_nset(stab_val(stab),"",0);
+       }
+       break;
     case '.':
+#ifndef lint
        if (last_in_stab) {
-           str_numset(stab->stab_val,(double)last_in_stab->stab_io->lines);
+           str_numset(stab_val(stab),(double)stab_io(last_in_stab)->lines);
        }
+#endif
        break;
     case '?':
-       str_numset(stab->stab_val,(double)statusvalue);
+       str_numset(stab_val(stab),(double)statusvalue);
        break;
     case '^':
-       s = curoutstab->stab_io->top_name;
-       str_set(stab->stab_val,s);
+       s = stab_io(curoutstab)->top_name;
+       str_set(stab_val(stab),s);
        break;
     case '~':
-       s = curoutstab->stab_io->fmt_name;
-       str_set(stab->stab_val,s);
+       s = stab_io(curoutstab)->fmt_name;
+       str_set(stab_val(stab),s);
        break;
+#ifndef lint
     case '=':
-       str_numset(stab->stab_val,(double)curoutstab->stab_io->page_len);
+       str_numset(stab_val(stab),(double)stab_io(curoutstab)->page_len);
        break;
     case '-':
-       str_numset(stab->stab_val,(double)curoutstab->stab_io->lines_left);
+       str_numset(stab_val(stab),(double)stab_io(curoutstab)->lines_left);
        break;
     case '%':
-       str_numset(stab->stab_val,(double)curoutstab->stab_io->page);
+       str_numset(stab_val(stab),(double)stab_io(curoutstab)->page);
        break;
+#endif
     case '/':
-       *tokenbuf = record_separator;
-       tokenbuf[1] = '\0';
-       str_set(stab->stab_val,tokenbuf);
+       if (record_separator != 12345) {
+           *tokenbuf = record_separator;
+           tokenbuf[1] = '\0';
+           str_nset(stab_val(stab),tokenbuf,rslen);
+       }
        break;
     case '[':
-       str_numset(stab->stab_val,(double)arybase);
+       str_numset(stab_val(stab),(double)arybase);
        break;
     case '|':
-       str_numset(stab->stab_val,
-          (double)((curoutstab->stab_io->flags & IOF_FLUSH) != 0) );
+       str_numset(stab_val(stab),
+          (double)((stab_io(curoutstab)->flags & IOF_FLUSH) != 0) );
        break;
     case ',':
-       str_set(stab->stab_val,ofs);
+       str_nset(stab_val(stab),ofs,ofslen);
        break;
     case '\\':
-       str_set(stab->stab_val,ors);
+       str_nset(stab_val(stab),ors,orslen);
        break;
     case '#':
-       str_set(stab->stab_val,ofmt);
+       str_set(stab_val(stab),ofmt);
        break;
     case '!':
-       str_numset(stab->stab_val, (double)errno);
-       str_set(stab->stab_val,
-         errno < 0 || errno > sys_nerr ? "(unknown)" : sys_errlist[errno]);
-       stab->stab_val->str_nok = 1;    /* what a wonderful hack! */
+       str_numset(stab_val(stab), (double)errno);
+       str_set(stab_val(stab), strerror(errno));
+       stab_val(stab)->str_nok = 1;    /* what a wonderful hack! */
        break;
     case '<':
-       str_numset(stab->stab_val,(double)uid);
+       str_numset(stab_val(stab),(double)uid);
        break;
     case '>':
-       str_numset(stab->stab_val,(double)euid);
+       str_numset(stab_val(stab),(double)euid);
        break;
     case '(':
-       s = tokenbuf;
-       sprintf(s,"%d",(int)getgid());
+       s = buf;
+       (void)sprintf(s,"%d",(int)gid);
        goto add_groups;
     case ')':
-       s = tokenbuf;
-       sprintf(s,"%d",(int)getegid());
+       s = buf;
+       (void)sprintf(s,"%d",(int)egid);
       add_groups:
        while (*s) s++;
 #ifdef GETGROUPS
@@ -172,71 +189,153 @@ STAB *stab;
 
            i = getgroups(NGROUPS,gary);
            while (--i >= 0) {
-               sprintf(s," %ld", (long)gary[i]);
+               (void)sprintf(s," %ld", (long)gary[i]);
                while (*s) s++;
            }
        }
 #endif
-       str_set(stab->stab_val,tokenbuf);
+       str_set(stab_val(stab),buf);
        break;
     }
-    return stab->stab_val;
+    return stab_val(stab);
 }
 
-stabset(stab,str)
-register STAB *stab;
+stabset(mstr,str)
+register STR *mstr;
 STR *str;
 {
+    STAB *stab = mstr->str_u.str_stab;
     char *s;
     int i;
-    int sighandler();
+    static handlertype sighandler();
+
+    switch (mstr->str_rare) {
+    case 'E':
+       setenv(mstr->str_ptr,str_get(str));
+                               /* And you'll never guess what the dog had */
+       break;                  /*   in its mouth... */
+    case 'S':
+       s = str_get(str);
+       i = whichsig(mstr->str_ptr);    /* ...no, a brick */
+       if (strEQ(s,"IGNORE"))
+#ifndef lint
+           (void)signal(i,SIG_IGN);
+#else
+           ;
+#endif
+       else if (strEQ(s,"DEFAULT") || !*s)
+           (void)signal(i,SIG_DFL);
+       else
+           (void)signal(i,sighandler);
+       break;
+#ifdef SOME_DBM
+    case 'D':
+       hdbmstore(stab_hash(stab),mstr->str_ptr,mstr->str_cur,str);
+       break;
+#endif
+    case '#':
+       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 (strNE(s,"StB") || str->str_cur != sizeof(STBP)) {
+           if (!*s) {
+               STBP *stbp;
+
+               (void)savenostab(stab); /* schedule a free of this stab */
+               if (stab->str_len)
+                   Safefree(stab->str_ptr);
+               Newz(601,stbp, 1, STBP);
+               stab->str_ptr = stbp;
+               stab->str_len = stab->str_cur = sizeof(STBP);
+               stab->str_pok = 1;
+               strcpy(stab_magic(stab),"StB");
+               stab_val(stab) = Str_new(70,0);
+               stab_line(stab) = line;
+           }
+           else
+               stab = stabent(s,TRUE);
+           str_sset(str,stab);
+       }
+       break;
+    case 's': {
+           struct lstring *lstr = (struct lstring*)str;
+
+           mstr->str_rare = 0;
+           str->str_magic = Nullstr;
+           str_insert(mstr,lstr->lstr_offset,lstr->lstr_len,
+             str->str_ptr,str->str_cur);
+       }
+       break;
+
+    case 'v':
+       do_vecset(mstr,str);
+       break;
 
-    if (stab->stab_flags & SF_VMAGIC) {
-       switch (stab->stab_name[0]) {
+    case 0:
+       switch (*stab->str_magic->str_ptr) {
+       case '.':
+           if (localizing)
+               savesptr((STR**)&last_in_stab);
+           break;
        case '^':
-           safefree(curoutstab->stab_io->top_name);
-           curoutstab->stab_io->top_name = s = savestr(str_get(str));
-           curoutstab->stab_io->top_stab = stabent(s,TRUE);
+           Safefree(stab_io(curoutstab)->top_name);
+           stab_io(curoutstab)->top_name = s = savestr(str_get(str));
+           stab_io(curoutstab)->top_stab = stabent(s,TRUE);
            break;
        case '~':
-           safefree(curoutstab->stab_io->fmt_name);
-           curoutstab->stab_io->fmt_name = s = savestr(str_get(str));
-           curoutstab->stab_io->fmt_stab = stabent(s,TRUE);
+           Safefree(stab_io(curoutstab)->fmt_name);
+           stab_io(curoutstab)->fmt_name = s = savestr(str_get(str));
+           stab_io(curoutstab)->fmt_stab = stabent(s,TRUE);
            break;
        case '=':
-           curoutstab->stab_io->page_len = (long)str_gnum(str);
+           stab_io(curoutstab)->page_len = (long)str_gnum(str);
            break;
        case '-':
-           curoutstab->stab_io->lines_left = (long)str_gnum(str);
+           stab_io(curoutstab)->lines_left = (long)str_gnum(str);
+           if (stab_io(curoutstab)->lines_left < 0L)
+               stab_io(curoutstab)->lines_left = 0L;
            break;
        case '%':
-           curoutstab->stab_io->page = (long)str_gnum(str);
+           stab_io(curoutstab)->page = (long)str_gnum(str);
            break;
        case '|':
-           curoutstab->stab_io->flags &= ~IOF_FLUSH;
+           stab_io(curoutstab)->flags &= ~IOF_FLUSH;
            if (str_gnum(str) != 0.0) {
-               curoutstab->stab_io->flags |= IOF_FLUSH;
+               stab_io(curoutstab)->flags |= IOF_FLUSH;
            }
            break;
        case '*':
-           multiline = (int)str_gnum(str) != 0;
+           i = (int)str_gnum(str);
+           multiline = (i != 0);
            break;
        case '/':
-           record_separator = *str_get(str);
+           if (str->str_pok) {
+               record_separator = *str_get(str);
+               rslen = str->str_cur;
+           }
+           else {
+               record_separator = 12345;       /* fake a non-existent char */
+               rslen = 1;
+           }
            break;
        case '\\':
            if (ors)
-               safefree(ors);
+               Safefree(ors);
            ors = savestr(str_get(str));
+           orslen = str->str_cur;
            break;
        case ',':
            if (ofs)
-               safefree(ofs);
+               Safefree(ofs);
            ofs = savestr(str_get(str));
+           ofslen = str->str_cur;
            break;
        case '#':
            if (ofmt)
-               safefree(ofmt);
+               Safefree(ofmt);
            ofmt = savestr(str_get(str));
            break;
        case '[':
@@ -249,73 +348,86 @@ STR *str;
            errno = (int)str_gnum(str);         /* will anyone ever use this? */
            break;
        case '<':
-#ifdef SETRUID
            uid = (int)str_gnum(str);
-           if (setruid(uid) < 0)
+#ifdef SETREUID
+           if (delaymagic) {
+               delaymagic |= DM_REUID;
+               break;                          /* don't do magic till later */
+           }
+#endif /* SETREUID */
+#ifdef SETRUID
+           if (setruid((UIDTYPE)uid) < 0)
+               uid = (int)getuid();
+#else
+#ifdef SETREUID
+           if (setreuid((UIDTYPE)uid, (UIDTYPE)-1) < 0)
                uid = (int)getuid();
 #else
            fatal("setruid() not implemented");
 #endif
+#endif
            break;
        case '>':
-#ifdef SETEUID
            euid = (int)str_gnum(str);
-           if (seteuid(euid) < 0)
+#ifdef SETREUID
+           if (delaymagic) {
+               delaymagic |= DM_REUID;
+               break;                          /* don't do magic till later */
+           }
+#endif /* SETREUID */
+#ifdef SETEUID
+           if (seteuid((UIDTYPE)euid) < 0)
+               euid = (int)geteuid();
+#else
+#ifdef SETREUID
+           if (setreuid((UIDTYPE)-1, (UIDTYPE)euid) < 0)
                euid = (int)geteuid();
 #else
            fatal("seteuid() not implemented");
 #endif
+#endif
            break;
        case '(':
+           gid = (int)str_gnum(str);
+#ifdef SETREGID
+           if (delaymagic) {
+               delaymagic |= DM_REGID;
+               break;                          /* don't do magic till later */
+           }
+#endif /* SETREGID */
 #ifdef SETRGID
-           setrgid((int)str_gnum(str));
+           (void)setrgid((GIDTYPE)gid);
+#else
+#ifdef SETREGID
+           (void)setregid((GIDTYPE)gid, (GIDTYPE)-1);
 #else
            fatal("setrgid() not implemented");
 #endif
+#endif
            break;
        case ')':
+           egid = (int)str_gnum(str);
+#ifdef SETREGID
+           if (delaymagic) {
+               delaymagic |= DM_REGID;
+               break;                          /* don't do magic till later */
+           }
+#endif /* SETREGID */
 #ifdef SETEGID
-           setegid((int)str_gnum(str));
+           (void)setegid((GIDTYPE)egid);
+#else
+#ifdef SETREGID
+           (void)setregid((GIDTYPE)-1, (GIDTYPE)egid);
 #else
            fatal("setegid() not implemented");
 #endif
+#endif
+           break;
+       case ':':
+           chopset = str_get(str);
            break;
-       case '.':
-       case '+':
-       case '&':
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-       case '8':
-       case '9':
-           break;              /* "read-only" registers */
        }
-    }
-    else if (stab == envstab && envname) {
-       setenv(envname,str_get(str));
-                               /* And you'll never guess what the dog had */
-       safefree(envname);      /*   in its mouth... */
-       envname = Nullch;
-    }
-    else if (stab == sigstab && signame) {
-       s = str_get(str);
-       i = whichsig(signame);  /* ...no, a brick */
-       if (strEQ(s,"IGNORE"))
-           signal(i,SIG_IGN);
-       else if (strEQ(s,"DEFAULT") || !*s)
-           signal(i,SIG_DFL);
-       else
-           signal(i,sighandler);
-       safefree(signame);
-       signame = Nullch;
-    }
-    else if (stab->stab_array) {
-       afill(stab->stab_array, (int)str_gnum(str) - arybase);
+       break;
     }
 }
 
@@ -327,9 +439,18 @@ char *sig;
     for (sigv = sig_name+1; *sigv; sigv++)
        if (strEQ(sig,*sigv))
            return sigv - sig_name;
+#ifdef SIGCLD
+    if (strEQ(sig,"CHLD"))
+       return SIGCLD;
+#endif
+#ifdef SIGCHLD
+    if (strEQ(sig,"CLD"))
+       return SIGCHLD;
+#endif
     return 0;
 }
 
+static handlertype
 sighandler(sig)
 int sig;
 {
@@ -338,61 +459,60 @@ int sig;
     STR *str;
     char *oldfile = filename;
     int oldsave = savestack->ary_fill;
+    ARRAY *oldstack = stack;
     SUBR *sub;
 
-    stab = stabent(str_get(hfetch(sigstab->stab_hash,sig_name[sig])),TRUE);
-    sub = stab->stab_sub;
+    stab = stabent(
+       str_get(hfetch(stab_hash(sigstab),sig_name[sig],strlen(sig_name[sig]),
+         TRUE)), TRUE);
+    sub = stab_sub(stab);
+    if (!sub && *sig_name[sig] == 'C' && instr(sig_name[sig],"LD")) {
+       if (sig_name[sig][1] == 'H')
+           stab = stabent(str_get(hfetch(stab_hash(sigstab),"CLD",3,TRUE)),
+             TRUE);
+       else
+           stab = stabent(str_get(hfetch(stab_hash(sigstab),"CHLD",4,TRUE)),
+             TRUE);
+       sub = stab_sub(stab);   /* gag */
+    }
     if (!sub) {
        if (dowarn)
            warn("SIG%s handler \"%s\" not defined.\n",
-               sig_name[sig], stab->stab_name );
+               sig_name[sig], stab_name(stab) );
        return;
     }
-    savearray = defstab->stab_array;
-    defstab->stab_array = anew(defstab);
-    str = str_new(0);
+    savearray = stab_xarray(defstab);
+    stab_xarray(defstab) = stack = anew(defstab);
+    stack->ary_flags = 0;
+    str = Str_new(71,0);
     str_set(str,sig_name[sig]);
-    apush(defstab->stab_array,str);
+    (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->stab_name);
+           warn("Deep recursion on subroutine \"%s\"",stab_name(stab));
        savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
     }
     filename = sub->filename;
 
-    str = cmd_exec(sub->cmd);          /* so do it already */
+    (void)cmd_exec(sub->cmd,G_SCALAR,1);               /* so do it already */
 
     sub->depth--;      /* assuming no longjumps out of here */
-    afree(defstab->stab_array);  /* put back old $_[] */
-    defstab->stab_array = savearray;
+    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);
 }
 
-char *
-reg_get(name)
-char *name;
-{
-    return STAB_GET(stabent(name,TRUE));
-}
-
-#ifdef NOTUSED
-reg_set(name,value)
-char *name;
-char *value;
-{
-    str_set(STAB_STR(stabent(name,TRUE)),value);
-}
-#endif
-
 STAB *
 aadd(stab)
 register STAB *stab;
 {
-    if (!stab->stab_array)
-       stab->stab_array = anew(stab);
+    if (!stab_xarray(stab))
+       stab_xarray(stab) = anew(stab);
     return stab;
 }
 
@@ -400,8 +520,8 @@ STAB *
 hadd(stab)
 register STAB *stab;
 {
-    if (!stab->stab_hash)
-       stab->stab_hash = hnew();
+    if (!stab_xhash(stab))
+       stab_xhash(stab) = hnew(COEFFSIZE);
     return stab;
 }
 
@@ -411,34 +531,99 @@ register char *name;
 int add;
 {
     register STAB *stab;
+    register STBP *stbp;
+    int len;
+    register char *namend;
+    HASH *stash;
+    char *sawquote = Nullch;
+    char *prevquote = Nullch;
+    bool global = FALSE;
+
+    if (isascii(*name) && isupper(*name)) {
+       if (*name > 'I') {
+           if (*name == 'S' && (
+             strEQ(name, "SIG") ||
+             strEQ(name, "STDIN") ||
+             strEQ(name, "STDOUT") ||
+             strEQ(name, "STDERR") ))
+               global = TRUE;
+       }
+       else if (*name > 'E') {
+           if (*name == 'I' && strEQ(name, "INC"))
+               global = TRUE;
+       }
+       else if (*name >= 'A') {
+           if (*name == 'E' && strEQ(name, "ENV"))
+               global = TRUE;
+       }
+       else if (*name == 'A' && (
+         strEQ(name, "ARGV") ||
+         strEQ(name, "ARGVOUT") ))
+           global = TRUE;
+    }
+    for (namend = name; *namend; namend++) {
+       if (*namend == '\'' && namend[1])
+           prevquote = sawquote, sawquote = namend;
+    }
+    if (sawquote == name && name[1]) {
+       stash = defstash;
+       sawquote = Nullch;
+       name++;
+    }
+    else if (!isalpha(*name) || global)
+       stash = defstash;
+    else
+       stash = curstash;
+    if (sawquote) {
+       char tmpbuf[256];
+       char *s, *d;
 
-    for (stab = stab_index[*name]; stab; stab = stab->stab_next) {
-       if (strEQ(name,stab->stab_name)) {
-           stab->stab_flags |= SF_MULTI;       /* is okay, probably */
-           return stab;
+       *sawquote = '\0';
+       if (s = prevquote) {
+           strncpy(tmpbuf,name,s-name+1);
+           d = tmpbuf+(s-name+1);
+           *d++ = '_';
+           strcpy(d,s+1);
        }
+       else {
+           *tmpbuf = '_';
+           strcpy(tmpbuf+1,name);
+       }
+       stab = stabent(tmpbuf,TRUE);
+       if (!(stash = stab_xhash(stab)))
+           stash = stab_xhash(stab) = hnew(0);
+       name = sawquote+1;
+       *sawquote = '\'';
     }
-    
-    /* no entry--should we add one? */
-
-    if (add) {
-       stab = (STAB *) safemalloc(sizeof(STAB));
-       bzero((char*)stab, sizeof(STAB));
-       stab->stab_name = savestr(name);
-       stab->stab_val = str_new(0);
-       stab->stab_next = stab_index[*name];
-       stab_index[*name] = stab;
+    len = namend - name;
+    stab = (STAB*)hfetch(stash,name,len,add);
+    if (!stab)
+       return Nullstab;
+    if (stab->str_pok) {
+       stab->str_pok |= SP_MULTI;
+       return stab;
+    }
+    else {
+       if (stab->str_len)
+           Safefree(stab->str_ptr);
+       Newz(602,stbp, 1, STBP);
+       stab->str_ptr = stbp;
+       stab->str_len = stab->str_cur = sizeof(STBP);
+       stab->str_pok = 1;
+       strcpy(stab_magic(stab),"StB");
+       stab_val(stab) = Str_new(72,0);
+       stab_line(stab) = line;
+       str_magic(stab,stab,'*',name,len);
        return stab;
     }
-    return Nullstab;
 }
 
 STIO *
 stio_new()
 {
-    STIO *stio = (STIO *) safemalloc(sizeof(STIO));
+    STIO *stio;
 
-    bzero((char*)stio, sizeof(STIO));
+    Newz(603,stio,1,STIO);
     stio->page_len = 60;
     return stio;
 }
@@ -447,22 +632,77 @@ stab_check(min,max)
 int min;
 register int max;
 {
+    register HENT *entry;
     register int i;
     register STAB *stab;
 
     for (i = min; i <= max; i++) {
-       for (stab = stab_index[i]; stab; stab = stab->stab_next) {
-           if (stab->stab_flags & SF_MULTI)
-               continue;
-           if (i == 'A' && strEQ(stab->stab_name, "ARGV"))
-               continue;
-           if (i == 'E' && strEQ(stab->stab_name, "ENV"))
-               continue;
-           if (i == 'S' && strEQ(stab->stab_name, "SIG"))
+       for (entry = defstash->tbl_array[i]; entry; entry = entry->hent_next) {
+           stab = (STAB*)entry->hent_val;
+           if (stab->str_pok & SP_MULTI)
                continue;
-           if (i == 'I' && strEQ(stab->stab_name, "INC"))
-               continue;
-           warn("Possible typo: %s,", stab->stab_name);
+           line = stab_line(stab);
+           warn("Possible typo: \"%s\"", stab_name(stab));
        }
     }
 }
+
+static int gensym = 0;
+
+STAB *
+genstab()
+{
+    (void)sprintf(tokenbuf,"_GEN_%d",gensym++);
+    return stabent(tokenbuf,TRUE);
+}
+
+/* hopefully this is only called on local symbol table entries */
+
+void
+stab_clear(stab)
+register STAB *stab;
+{
+    STIO *stio;
+    SUBR *sub;
+
+    afree(stab_xarray(stab));
+    (void)hfree(stab_xhash(stab));
+    str_free(stab_val(stab));
+    if (stio = stab_io(stab)) {
+       do_close(stab,FALSE);
+       Safefree(stio->top_name);
+       Safefree(stio->fmt_name);
+    }
+    if (sub = stab_sub(stab)) {
+       afree(sub->tosave);
+       cmd_free(sub->cmd);
+    }
+    Safefree(stab->str_ptr);
+    stab->str_ptr = Null(STBP*);
+    stab->str_len = 0;
+    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 */