perl 4.0 patch 36: (combined patch)
[p5sagit/p5-mst-13.2.git] / stab.c
1 /* $RCSfile: stab.c,v $$Revision: 4.0.1.4 $$Date: 92/06/08 15:32:19 $
2  *
3  *    Copyright (c) 1991, Larry Wall
4  *
5  *    You may distribute under the terms of either the GNU General Public
6  *    License or the Artistic License, as specified in the README file.
7  *
8  * $Log:        stab.c,v $
9  * Revision 4.0.1.4  92/06/08  15:32:19  lwall
10  * patch20: fixed confusion between a *var's real name and its effective name
11  * patch20: the debugger now warns you on lines that can't set a breakpoint
12  * patch20: the debugger made perl forget the last pattern used by //
13  * patch20: paragraph mode now skips extra newlines automatically
14  * patch20: ($<,$>) = ... didn't work on some architectures
15  * 
16  * Revision 4.0.1.3  91/11/05  18:35:33  lwall
17  * patch11: length($x) was sometimes wrong for numeric $x
18  * patch11: perl now issues warning if $SIG{'ALARM'} is referenced
19  * patch11: *foo = undef coredumped
20  * patch11: solitary subroutine references no longer trigger typo warnings
21  * patch11: local(*FILEHANDLE) had a memory leak
22  * 
23  * Revision 4.0.1.2  91/06/07  11:55:53  lwall
24  * patch4: new copyright notice
25  * patch4: added $^P variable to control calling of perldb routines
26  * patch4: added $^F variable to specify maximum system fd, default 2
27  * patch4: $` was busted inside s///
28  * patch4: default top-of-form format is now FILEHANDLE_TOP
29  * patch4: length($`), length($&), length($') now optimized to avoid string copy
30  * patch4: $^D |= 1024 now does syntax tree dump at run-time
31  * 
32  * Revision 4.0.1.1  91/04/12  09:10:24  lwall
33  * patch1: Configure now differentiates getgroups() type from getgid() type
34  * patch1: you may now use "die" and "caller" in a signal handler
35  * 
36  * Revision 4.0  91/03/20  01:39:41  lwall
37  * 4.0 baseline.
38  * 
39  */
40
41 #include "EXTERN.h"
42 #include "perl.h"
43
44 #if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
45 #include <signal.h>
46 #endif
47
48 static char *sig_name[] = {
49     SIG_NAME,0
50 };
51
52 #ifdef VOIDSIG
53 #define handlertype void
54 #else
55 #define handlertype int
56 #endif
57
58 static handlertype sighandler();
59
60 static int origalen = 0;
61
62 STR *
63 stab_str(str)
64 STR *str;
65 {
66     STAB *stab = str->str_u.str_stab;
67     register int paren;
68     register char *s;
69     register int i;
70
71     if (str->str_rare)
72         return stab_val(stab);
73
74     switch (*stab->str_magic->str_ptr) {
75     case '\004':                /* ^D */
76 #ifdef DEBUGGING
77         str_numset(stab_val(stab),(double)(debug & 32767));
78 #endif
79         break;
80     case '\006':                /* ^F */
81         str_numset(stab_val(stab),(double)maxsysfd);
82         break;
83     case '\t':                  /* ^I */
84         if (inplace)
85             str_set(stab_val(stab), inplace);
86         else
87             str_sset(stab_val(stab),&str_undef);
88         break;
89     case '\020':                /* ^P */
90         str_numset(stab_val(stab),(double)perldb);
91         break;
92     case '\024':                /* ^T */
93         str_numset(stab_val(stab),(double)basetime);
94         break;
95     case '\027':                /* ^W */
96         str_numset(stab_val(stab),(double)dowarn);
97         break;
98     case '1': case '2': case '3': case '4':
99     case '5': case '6': case '7': case '8': case '9': case '&':
100         if (curspat) {
101             paren = atoi(stab_ename(stab));
102           getparen:
103             if (curspat->spat_regexp &&
104               paren <= curspat->spat_regexp->nparens &&
105               (s = curspat->spat_regexp->startp[paren]) ) {
106                 i = curspat->spat_regexp->endp[paren] - s;
107                 if (i >= 0)
108                     str_nset(stab_val(stab),s,i);
109                 else
110                     str_sset(stab_val(stab),&str_undef);
111             }
112             else
113                 str_sset(stab_val(stab),&str_undef);
114         }
115         break;
116     case '+':
117         if (curspat) {
118             paren = curspat->spat_regexp->lastparen;
119             goto getparen;
120         }
121         break;
122     case '`':
123         if (curspat) {
124             if (curspat->spat_regexp &&
125               (s = curspat->spat_regexp->subbeg) ) {
126                 i = curspat->spat_regexp->startp[0] - s;
127                 if (i >= 0)
128                     str_nset(stab_val(stab),s,i);
129                 else
130                     str_nset(stab_val(stab),"",0);
131             }
132             else
133                 str_nset(stab_val(stab),"",0);
134         }
135         break;
136     case '\'':
137         if (curspat) {
138             if (curspat->spat_regexp &&
139               (s = curspat->spat_regexp->endp[0]) ) {
140                 str_nset(stab_val(stab),s, curspat->spat_regexp->subend - s);
141             }
142             else
143                 str_nset(stab_val(stab),"",0);
144         }
145         break;
146     case '.':
147 #ifndef lint
148         if (last_in_stab && stab_io(last_in_stab)) {
149             str_numset(stab_val(stab),(double)stab_io(last_in_stab)->lines);
150         }
151 #endif
152         break;
153     case '?':
154         str_numset(stab_val(stab),(double)statusvalue);
155         break;
156     case '^':
157         s = stab_io(curoutstab)->top_name;
158         if (s)
159             str_set(stab_val(stab),s);
160         else {
161             str_set(stab_val(stab),stab_ename(curoutstab));
162             str_cat(stab_val(stab),"_TOP");
163         }
164         break;
165     case '~':
166         s = stab_io(curoutstab)->fmt_name;
167         if (!s)
168             s = stab_ename(curoutstab);
169         str_set(stab_val(stab),s);
170         break;
171 #ifndef lint
172     case '=':
173         str_numset(stab_val(stab),(double)stab_io(curoutstab)->page_len);
174         break;
175     case '-':
176         str_numset(stab_val(stab),(double)stab_io(curoutstab)->lines_left);
177         break;
178     case '%':
179         str_numset(stab_val(stab),(double)stab_io(curoutstab)->page);
180         break;
181 #endif
182     case ':':
183         break;
184     case '/':
185         break;
186     case '[':
187         str_numset(stab_val(stab),(double)arybase);
188         break;
189     case '|':
190         if (!stab_io(curoutstab))
191             stab_io(curoutstab) = stio_new();
192         str_numset(stab_val(stab),
193            (double)((stab_io(curoutstab)->flags & IOF_FLUSH) != 0) );
194         break;
195     case ',':
196         str_nset(stab_val(stab),ofs,ofslen);
197         break;
198     case '\\':
199         str_nset(stab_val(stab),ors,orslen);
200         break;
201     case '#':
202         str_set(stab_val(stab),ofmt);
203         break;
204     case '!':
205         str_numset(stab_val(stab), (double)errno);
206         str_set(stab_val(stab), errno ? strerror(errno) : "");
207         stab_val(stab)->str_nok = 1;    /* what a wonderful hack! */
208         break;
209     case '<':
210         str_numset(stab_val(stab),(double)uid);
211         break;
212     case '>':
213         str_numset(stab_val(stab),(double)euid);
214         break;
215     case '(':
216         s = buf;
217         (void)sprintf(s,"%d",(int)gid);
218         goto add_groups;
219     case ')':
220         s = buf;
221         (void)sprintf(s,"%d",(int)egid);
222       add_groups:
223         while (*s) s++;
224 #ifdef HAS_GETGROUPS
225 #ifndef NGROUPS
226 #define NGROUPS 32
227 #endif
228         {
229             GROUPSTYPE gary[NGROUPS];
230
231             i = getgroups(NGROUPS,gary);
232             while (--i >= 0) {
233                 (void)sprintf(s," %ld", (long)gary[i]);
234                 while (*s) s++;
235             }
236         }
237 #endif
238         str_set(stab_val(stab),buf);
239         break;
240     case '*':
241         break;
242     case '0':
243         break;
244     default:
245         {
246             struct ufuncs *uf = (struct ufuncs *)str->str_ptr;
247
248             if (uf && uf->uf_val)
249                 (*uf->uf_val)(uf->uf_index, stab_val(stab));
250         }
251         break;
252     }
253     return stab_val(stab);
254 }
255
256 STRLEN
257 stab_len(str)
258 STR *str;
259 {
260     STAB *stab = str->str_u.str_stab;
261     int paren;
262     int i;
263     char *s;
264
265     if (str->str_rare)
266         return str_len(stab_val(stab));
267
268     switch (*stab->str_magic->str_ptr) {
269     case '1': case '2': case '3': case '4':
270     case '5': case '6': case '7': case '8': case '9': case '&':
271         if (curspat) {
272             paren = atoi(stab_ename(stab));
273           getparen:
274             if (curspat->spat_regexp &&
275               paren <= curspat->spat_regexp->nparens &&
276               (s = curspat->spat_regexp->startp[paren]) ) {
277                 i = curspat->spat_regexp->endp[paren] - s;
278                 if (i >= 0)
279                     return i;
280                 else
281                     return 0;
282             }
283             else
284                 return 0;
285         }
286         break;
287     case '+':
288         if (curspat) {
289             paren = curspat->spat_regexp->lastparen;
290             goto getparen;
291         }
292         break;
293     case '`':
294         if (curspat) {
295             if (curspat->spat_regexp &&
296               (s = curspat->spat_regexp->subbeg) ) {
297                 i = curspat->spat_regexp->startp[0] - s;
298                 if (i >= 0)
299                     return i;
300                 else
301                     return 0;
302             }
303             else
304                 return 0;
305         }
306         break;
307     case '\'':
308         if (curspat) {
309             if (curspat->spat_regexp &&
310               (s = curspat->spat_regexp->endp[0]) ) {
311                 return (STRLEN) (curspat->spat_regexp->subend - s);
312             }
313             else
314                 return 0;
315         }
316         break;
317     case ',':
318         return (STRLEN)ofslen;
319     case '\\':
320         return (STRLEN)orslen;
321     }
322     return str_len(stab_str(str));
323 }
324
325 void
326 stabset(mstr,str)
327 register STR *mstr;
328 STR *str;
329 {
330     STAB *stab;
331     register char *s;
332     int i;
333
334     switch (mstr->str_rare) {
335     case 'E':
336         my_setenv(mstr->str_ptr,str_get(str));
337                                 /* And you'll never guess what the dog had */
338                                 /*   in its mouth... */
339 #ifdef TAINT
340         if (strEQ(mstr->str_ptr,"PATH")) {
341             char *strend = str->str_ptr + str->str_cur;
342
343             s = str->str_ptr;
344             while (s < strend) {
345                 s = cpytill(tokenbuf,s,strend,':',&i);
346                 s++;
347                 if (*tokenbuf != '/'
348                   || (stat(tokenbuf,&statbuf) && (statbuf.st_mode & 2)) )
349                     str->str_tainted = 2;
350             }
351         }
352 #endif
353         break;
354     case 'S':
355         s = str_get(str);
356         i = whichsig(mstr->str_ptr);    /* ...no, a brick */
357         if (!i && (dowarn || strEQ(mstr->str_ptr,"ALARM")))
358             warn("No such signal: SIG%s", mstr->str_ptr);
359         if (strEQ(s,"IGNORE"))
360 #ifndef lint
361             (void)signal(i,SIG_IGN);
362 #else
363             ;
364 #endif
365         else if (strEQ(s,"DEFAULT") || !*s)
366             (void)signal(i,SIG_DFL);
367         else {
368             (void)signal(i,sighandler);
369             if (!index(s,'\'')) {
370                 sprintf(tokenbuf, "main'%s",s);
371                 str_set(str,tokenbuf);
372             }
373         }
374         break;
375 #ifdef SOME_DBM
376     case 'D':
377         stab = mstr->str_u.str_stab;
378         hdbmstore(stab_hash(stab),mstr->str_ptr,mstr->str_cur,str);
379         break;
380 #endif
381     case 'L':
382         {
383             CMD *cmd;
384
385             stab = mstr->str_u.str_stab;
386             i = str_true(str);
387             str = afetch(stab_xarray(stab),atoi(mstr->str_ptr), FALSE);
388             if (str->str_magic && (cmd = str->str_magic->str_u.str_cmd)) {
389                 cmd->c_flags &= ~CF_OPTIMIZE;
390                 cmd->c_flags |= i? CFT_D1 : CFT_D0;
391             }
392             else
393                 warn("Can't break at that line\n");
394         }
395         break;
396     case '#':
397         stab = mstr->str_u.str_stab;
398         afill(stab_array(stab), (int)str_gnum(str) - arybase);
399         break;
400     case 'X':   /* merely a copy of a * string */
401         break;
402     case '*':
403         s = str->str_pok ? str_get(str) : "";
404         if (strNE(s,"StB") || str->str_cur != sizeof(STBP)) {
405             stab = mstr->str_u.str_stab;
406             if (!*s) {
407                 STBP *stbp;
408
409                 /*SUPPRESS 701*/
410                 (void)savenostab(stab); /* schedule a free of this stab */
411                 if (stab->str_len)
412                     Safefree(stab->str_ptr);
413                 Newz(601,stbp, 1, STBP);
414                 stab->str_ptr = stbp;
415                 stab->str_len = stab->str_cur = sizeof(STBP);
416                 stab->str_pok = 1;
417                 strcpy(stab_magic(stab),"StB");
418                 stab_val(stab) = Str_new(70,0);
419                 stab_line(stab) = curcmd->c_line;
420                 stab_estab(stab) = stab;
421             }
422             else {
423                 stab = stabent(s,TRUE);
424                 if (!stab_xarray(stab))
425                     aadd(stab);
426                 if (!stab_xhash(stab))
427                     hadd(stab);
428                 if (!stab_io(stab))
429                     stab_io(stab) = stio_new();
430             }
431             str_sset(str, (STR*) stab);
432         }
433         break;
434     case 's': {
435             struct lstring *lstr = (struct lstring*)str;
436             char *tmps;
437
438             mstr->str_rare = 0;
439             str->str_magic = Nullstr;
440             tmps = str_get(str);
441             str_insert(mstr,lstr->lstr_offset,lstr->lstr_len,
442               tmps,str->str_cur);
443         }
444         break;
445
446     case 'v':
447         do_vecset(mstr,str);
448         break;
449
450     case 0:
451         /*SUPPRESS 560*/
452         if (!(stab = mstr->str_u.str_stab))
453             break;
454         switch (*stab->str_magic->str_ptr) {
455         case '\004':    /* ^D */
456 #ifdef DEBUGGING
457             debug = (int)(str_gnum(str)) | 32768;
458             if (debug & 1024)
459                 dump_all();
460 #endif
461             break;
462         case '\006':    /* ^F */
463             maxsysfd = (int)str_gnum(str);
464             break;
465         case '\t':      /* ^I */
466             if (inplace)
467                 Safefree(inplace);
468             if (str->str_pok || str->str_nok)
469                 inplace = savestr(str_get(str));
470             else
471                 inplace = Nullch;
472             break;
473         case '\020':    /* ^P */
474             i = (int)str_gnum(str);
475             if (i != perldb) {
476                 static SPAT *oldlastspat;
477
478                 if (perldb)
479                     oldlastspat = lastspat;
480                 else
481                     lastspat = oldlastspat;
482             }
483             perldb = i;
484             break;
485         case '\024':    /* ^T */
486             basetime = (time_t)str_gnum(str);
487             break;
488         case '\027':    /* ^W */
489             dowarn = (bool)str_gnum(str);
490             break;
491         case '.':
492             if (localizing)
493                 savesptr((STR**)&last_in_stab);
494             break;
495         case '^':
496             Safefree(stab_io(curoutstab)->top_name);
497             stab_io(curoutstab)->top_name = s = savestr(str_get(str));
498             stab_io(curoutstab)->top_stab = stabent(s,TRUE);
499             break;
500         case '~':
501             Safefree(stab_io(curoutstab)->fmt_name);
502             stab_io(curoutstab)->fmt_name = s = savestr(str_get(str));
503             stab_io(curoutstab)->fmt_stab = stabent(s,TRUE);
504             break;
505         case '=':
506             stab_io(curoutstab)->page_len = (long)str_gnum(str);
507             break;
508         case '-':
509             stab_io(curoutstab)->lines_left = (long)str_gnum(str);
510             if (stab_io(curoutstab)->lines_left < 0L)
511                 stab_io(curoutstab)->lines_left = 0L;
512             break;
513         case '%':
514             stab_io(curoutstab)->page = (long)str_gnum(str);
515             break;
516         case '|':
517             if (!stab_io(curoutstab))
518                 stab_io(curoutstab) = stio_new();
519             stab_io(curoutstab)->flags &= ~IOF_FLUSH;
520             if (str_gnum(str) != 0.0) {
521                 stab_io(curoutstab)->flags |= IOF_FLUSH;
522             }
523             break;
524         case '*':
525             i = (int)str_gnum(str);
526             multiline = (i != 0);
527             break;
528         case '/':
529             if (str->str_pok) {
530                 rs = str_get(str);
531                 rslen = str->str_cur;
532                 if (rspara = !rslen) {
533                     rs = "\n\n";
534                     rslen = 2;
535                 }
536                 rschar = rs[rslen - 1];
537             }
538             else {
539                 rschar = 0777;  /* fake a non-existent char */
540                 rslen = 1;
541             }
542             break;
543         case '\\':
544             if (ors)
545                 Safefree(ors);
546             ors = savestr(str_get(str));
547             orslen = str->str_cur;
548             break;
549         case ',':
550             if (ofs)
551                 Safefree(ofs);
552             ofs = savestr(str_get(str));
553             ofslen = str->str_cur;
554             break;
555         case '#':
556             if (ofmt)
557                 Safefree(ofmt);
558             ofmt = savestr(str_get(str));
559             break;
560         case '[':
561             arybase = (int)str_gnum(str);
562             break;
563         case '?':
564             statusvalue = U_S(str_gnum(str));
565             break;
566         case '!':
567             errno = (int)str_gnum(str);         /* will anyone ever use this? */
568             break;
569         case '<':
570             uid = (int)str_gnum(str);
571             if (delaymagic) {
572                 delaymagic |= DM_RUID;
573                 break;                          /* don't do magic till later */
574             }
575 #ifdef HAS_SETRUID
576             (void)setruid((UIDTYPE)uid);
577 #else
578 #ifdef HAS_SETREUID
579             (void)setreuid((UIDTYPE)uid, (UIDTYPE)-1);
580 #else
581             if (uid == euid)            /* special case $< = $> */
582                 (void)setuid(uid);
583             else
584                 fatal("setruid() not implemented");
585 #endif
586 #endif
587             uid = (int)getuid();
588             break;
589         case '>':
590             euid = (int)str_gnum(str);
591             if (delaymagic) {
592                 delaymagic |= DM_EUID;
593                 break;                          /* don't do magic till later */
594             }
595 #ifdef HAS_SETEUID
596             (void)seteuid((UIDTYPE)euid);
597 #else
598 #ifdef HAS_SETREUID
599             (void)setreuid((UIDTYPE)-1, (UIDTYPE)euid);
600 #else
601             if (euid == uid)            /* special case $> = $< */
602                 setuid(euid);
603             else
604                 fatal("seteuid() not implemented");
605 #endif
606 #endif
607             euid = (int)geteuid();
608             break;
609         case '(':
610             gid = (int)str_gnum(str);
611             if (delaymagic) {
612                 delaymagic |= DM_RGID;
613                 break;                          /* don't do magic till later */
614             }
615 #ifdef HAS_SETRGID
616             (void)setrgid((GIDTYPE)gid);
617 #else
618 #ifdef HAS_SETREGID
619             (void)setregid((GIDTYPE)gid, (GIDTYPE)-1);
620 #else
621             if (gid == egid)                    /* special case $( = $) */
622                 (void)setgid(gid);
623             else
624                 fatal("setrgid() not implemented");
625 #endif
626 #endif
627             gid = (int)getgid();
628             break;
629         case ')':
630             egid = (int)str_gnum(str);
631             if (delaymagic) {
632                 delaymagic |= DM_EGID;
633                 break;                          /* don't do magic till later */
634             }
635 #ifdef HAS_SETEGID
636             (void)setegid((GIDTYPE)egid);
637 #else
638 #ifdef HAS_SETREGID
639             (void)setregid((GIDTYPE)-1, (GIDTYPE)egid);
640 #else
641             if (egid == gid)                    /* special case $) = $( */
642                 (void)setgid(egid);
643             else
644                 fatal("setegid() not implemented");
645 #endif
646 #endif
647             egid = (int)getegid();
648             break;
649         case ':':
650             chopset = str_get(str);
651             break;
652         case '0':
653             if (!origalen) {
654                 s = origargv[0];
655                 s += strlen(s);
656                 /* See if all the arguments are contiguous in memory */
657                 for (i = 1; i < origargc; i++) {
658                     if (origargv[i] == s + 1)
659                         s += strlen(++s);       /* this one is ok too */
660                 }
661                 if (origenviron[0] == s + 1) {  /* can grab env area too? */
662                     my_setenv("NoNeSuCh", Nullch);
663                                                 /* force copy of environment */
664                     for (i = 0; origenviron[i]; i++)
665                         if (origenviron[i] == s + 1)
666                             s += strlen(++s);
667                 }
668                 origalen = s - origargv[0];
669             }
670             s = str_get(str);
671             i = str->str_cur;
672             if (i >= origalen) {
673                 i = origalen;
674                 str->str_cur = i;
675                 str->str_ptr[i] = '\0';
676                 Copy(s, origargv[0], i, char);
677             }
678             else {
679                 Copy(s, origargv[0], i, char);
680                 s = origargv[0]+i;
681                 *s++ = '\0';
682                 while (++i < origalen)
683                     *s++ = ' ';
684             }
685             break;
686         default:
687             {
688                 struct ufuncs *uf = (struct ufuncs *)str->str_magic->str_ptr;
689
690                 if (uf && uf->uf_set)
691                     (*uf->uf_set)(uf->uf_index, str);
692             }
693             break;
694         }
695         break;
696     }
697 }
698
699 int
700 whichsig(sig)
701 char *sig;
702 {
703     register char **sigv;
704
705     for (sigv = sig_name+1; *sigv; sigv++)
706         if (strEQ(sig,*sigv))
707             return sigv - sig_name;
708 #ifdef SIGCLD
709     if (strEQ(sig,"CHLD"))
710         return SIGCLD;
711 #endif
712 #ifdef SIGCHLD
713     if (strEQ(sig,"CLD"))
714         return SIGCHLD;
715 #endif
716     return 0;
717 }
718
719 static handlertype
720 sighandler(sig)
721 int sig;
722 {
723     STAB *stab;
724     STR *str;
725     int oldsave = savestack->ary_fill;
726     int oldtmps_base = tmps_base;
727     register CSV *csv;
728     SUBR *sub;
729
730 #ifdef OS2              /* or anybody else who requires SIG_ACK */
731     signal(sig, SIG_ACK);
732 #endif
733     stab = stabent(
734         str_get(hfetch(stab_hash(sigstab),sig_name[sig],strlen(sig_name[sig]),
735           TRUE)), TRUE);
736     sub = stab_sub(stab);
737     if (!sub && *sig_name[sig] == 'C' && instr(sig_name[sig],"LD")) {
738         if (sig_name[sig][1] == 'H')
739             stab = stabent(str_get(hfetch(stab_hash(sigstab),"CLD",3,TRUE)),
740               TRUE);
741         else
742             stab = stabent(str_get(hfetch(stab_hash(sigstab),"CHLD",4,TRUE)),
743               TRUE);
744         sub = stab_sub(stab);   /* gag */
745     }
746     if (!sub) {
747         if (dowarn)
748             warn("SIG%s handler \"%s\" not defined.\n",
749                 sig_name[sig], stab_ename(stab) );
750         return;
751     }
752     /*SUPPRESS 701*/
753     saveaptr(&stack);
754     str = Str_new(15, sizeof(CSV));
755     str->str_state = SS_SCSV;
756     (void)apush(savestack,str);
757     csv = (CSV*)str->str_ptr;
758     csv->sub = sub;
759     csv->stab = stab;
760     csv->curcsv = curcsv;
761     csv->curcmd = curcmd;
762     csv->depth = sub->depth;
763     csv->wantarray = G_SCALAR;
764     csv->hasargs = TRUE;
765     csv->savearray = stab_xarray(defstab);
766     csv->argarray = stab_xarray(defstab) = stack = anew(defstab);
767     stack->ary_flags = 0;
768     curcsv = csv;
769     str = str_mortal(&str_undef);
770     str_set(str,sig_name[sig]);
771     (void)apush(stab_xarray(defstab),str);
772     sub->depth++;
773     if (sub->depth >= 2) {      /* save temporaries on recursion? */
774         if (sub->depth == 100 && dowarn)
775             warn("Deep recursion on subroutine \"%s\"",stab_ename(stab));
776         savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
777     }
778
779     tmps_base = tmps_max;               /* protect our mortal string */
780     (void)cmd_exec(sub->cmd,G_SCALAR,0);                /* so do it already */
781     tmps_base = oldtmps_base;
782
783     restorelist(oldsave);               /* put everything back */
784 }
785
786 STAB *
787 aadd(stab)
788 register STAB *stab;
789 {
790     if (!stab_xarray(stab))
791         stab_xarray(stab) = anew(stab);
792     return stab;
793 }
794
795 STAB *
796 hadd(stab)
797 register STAB *stab;
798 {
799     if (!stab_xhash(stab))
800         stab_xhash(stab) = hnew(COEFFSIZE);
801     return stab;
802 }
803
804 STAB *
805 fstab(name)
806 char *name;
807 {
808     char tmpbuf[1200];
809     STAB *stab;
810
811     sprintf(tmpbuf,"'_<%s", name);
812     stab = stabent(tmpbuf, TRUE);
813     str_set(stab_val(stab), name);
814     if (perldb)
815         (void)hadd(aadd(stab));
816     return stab;
817 }
818
819 STAB *
820 stabent(name,add)
821 register char *name;
822 int add;
823 {
824     register STAB *stab;
825     register STBP *stbp;
826     int len;
827     register char *namend;
828     HASH *stash;
829     char *sawquote = Nullch;
830     char *prevquote = Nullch;
831     bool global = FALSE;
832
833     if (isUPPER(*name)) {
834         if (*name > 'I') {
835             if (*name == 'S' && (
836               strEQ(name, "SIG") ||
837               strEQ(name, "STDIN") ||
838               strEQ(name, "STDOUT") ||
839               strEQ(name, "STDERR") ))
840                 global = TRUE;
841         }
842         else if (*name > 'E') {
843             if (*name == 'I' && strEQ(name, "INC"))
844                 global = TRUE;
845         }
846         else if (*name > 'A') {
847             if (*name == 'E' && strEQ(name, "ENV"))
848                 global = TRUE;
849         }
850         else if (*name == 'A' && (
851           strEQ(name, "ARGV") ||
852           strEQ(name, "ARGVOUT") ))
853             global = TRUE;
854     }
855     for (namend = name; *namend; namend++) {
856         if (*namend == '\'' && namend[1])
857             prevquote = sawquote, sawquote = namend;
858     }
859     if (sawquote == name && name[1]) {
860         stash = defstash;
861         sawquote = Nullch;
862         name++;
863     }
864     else if (!isALPHA(*name) || global)
865         stash = defstash;
866     else if ((CMD*)curcmd == &compiling)
867         stash = curstash;
868     else
869         stash = curcmd->c_stash;
870     if (sawquote) {
871         char tmpbuf[256];
872         char *s, *d;
873
874         *sawquote = '\0';
875         /*SUPPRESS 560*/
876         if (s = prevquote) {
877             strncpy(tmpbuf,name,s-name+1);
878             d = tmpbuf+(s-name+1);
879             *d++ = '_';
880             strcpy(d,s+1);
881         }
882         else {
883             *tmpbuf = '_';
884             strcpy(tmpbuf+1,name);
885         }
886         stab = stabent(tmpbuf,TRUE);
887         if (!(stash = stab_xhash(stab)))
888             stash = stab_xhash(stab) = hnew(0);
889         if (!stash->tbl_name)
890             stash->tbl_name = savestr(name);
891         name = sawquote+1;
892         *sawquote = '\'';
893     }
894     len = namend - name;
895     stab = (STAB*)hfetch(stash,name,len,add);
896     if (stab == (STAB*)&str_undef)
897         return Nullstab;
898     if (stab->str_pok) {
899         stab->str_pok |= SP_MULTI;
900         return stab;
901     }
902     else {
903         if (stab->str_len)
904             Safefree(stab->str_ptr);
905         Newz(602,stbp, 1, STBP);
906         stab->str_ptr = stbp;
907         stab->str_len = stab->str_cur = sizeof(STBP);
908         stab->str_pok = 1;
909         strcpy(stab_magic(stab),"StB");
910         stab_val(stab) = Str_new(72,0);
911         stab_line(stab) = curcmd->c_line;
912         stab_estab(stab) = stab;
913         str_magic((STR*)stab, stab, '*', name, len);
914         stab_stash(stab) = stash;
915         if (isDIGIT(*name) && *name != '0') {
916             stab_flags(stab) = SF_VMAGIC;
917             str_magic(stab_val(stab), stab, 0, Nullch, 0);
918         }
919         if (add & 2)
920             stab->str_pok |= SP_MULTI;
921         return stab;
922     }
923 }
924
925 void
926 stab_fullname(str,stab)
927 STR *str;
928 STAB *stab;
929 {
930     HASH *tb = stab_stash(stab);
931
932     if (!tb)
933         return;
934     str_set(str,tb->tbl_name);
935     str_ncat(str,"'", 1);
936     str_scat(str,stab->str_magic);
937 }
938
939 void
940 stab_efullname(str,stab)
941 STR *str;
942 STAB *stab;
943 {
944     HASH *tb = stab_estash(stab);
945
946     if (!tb)
947         return;
948     str_set(str,tb->tbl_name);
949     str_ncat(str,"'", 1);
950     str_scat(str,stab_estab(stab)->str_magic);
951 }
952
953 STIO *
954 stio_new()
955 {
956     STIO *stio;
957
958     Newz(603,stio,1,STIO);
959     stio->page_len = 60;
960     return stio;
961 }
962
963 void
964 stab_check(min,max)
965 int min;
966 register int max;
967 {
968     register HENT *entry;
969     register int i;
970     register STAB *stab;
971
972     for (i = min; i <= max; i++) {
973         for (entry = defstash->tbl_array[i]; entry; entry = entry->hent_next) {
974             stab = (STAB*)entry->hent_val;
975             if (stab->str_pok & SP_MULTI)
976                 continue;
977             curcmd->c_line = stab_line(stab);
978             warn("Possible typo: \"%s\"", stab_name(stab));
979         }
980     }
981 }
982
983 static int gensym = 0;
984
985 STAB *
986 genstab()
987 {
988     (void)sprintf(tokenbuf,"_GEN_%d",gensym++);
989     return stabent(tokenbuf,TRUE);
990 }
991
992 /* hopefully this is only called on local symbol table entries */
993
994 void
995 stab_clear(stab)
996 register STAB *stab;
997 {
998     STIO *stio;
999     SUBR *sub;
1000
1001     if (!stab || !stab->str_ptr)
1002         return;
1003     afree(stab_xarray(stab));
1004     stab_xarray(stab) = Null(ARRAY*);
1005     (void)hfree(stab_xhash(stab), FALSE);
1006     stab_xhash(stab) = Null(HASH*);
1007     str_free(stab_val(stab));
1008     stab_val(stab) = Nullstr;
1009     /*SUPPRESS 560*/
1010     if (stio = stab_io(stab)) {
1011         do_close(stab,FALSE);
1012         Safefree(stio->top_name);
1013         Safefree(stio->fmt_name);
1014         Safefree(stio);
1015     }
1016     /*SUPPRESS 560*/
1017     if (sub = stab_sub(stab)) {
1018         afree(sub->tosave);
1019         cmd_free(sub->cmd);
1020     }
1021     Safefree(stab->str_ptr);
1022     stab->str_ptr = Null(STBP*);
1023     stab->str_len = 0;
1024     stab->str_cur = 0;
1025 }
1026
1027 #if defined(CRIPPLED_CC) && (defined(iAPX286) || defined(M_I286) || defined(I80286))
1028 #define MICROPORT
1029 #endif
1030
1031 #ifdef  MICROPORT       /* Microport 2.4 hack */
1032 ARRAY *stab_array(stab)
1033 register STAB *stab;
1034 {
1035     if (((STBP*)(stab->str_ptr))->stbp_array) 
1036         return ((STBP*)(stab->str_ptr))->stbp_array;
1037     else
1038         return ((STBP*)(aadd(stab)->str_ptr))->stbp_array;
1039 }
1040
1041 HASH *stab_hash(stab)
1042 register STAB *stab;
1043 {
1044     if (((STBP*)(stab->str_ptr))->stbp_hash)
1045         return ((STBP*)(stab->str_ptr))->stbp_hash;
1046     else
1047         return ((STBP*)(hadd(stab)->str_ptr))->stbp_hash;
1048 }
1049 #endif                  /* Microport 2.4 hack */