blob: f65f6469c596dcedbde60853a7e6da54ce1bf8e7 [file] [log] [blame]
/* $RCSfile$$Revision$$Date$
*
* 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$
* Revision 1.1 2004/02/17 22:21:16 criswell
* Initial commit of the perl Malloc Benchmark. I've cheated a little by
* generating the yacc output files and committing them directly, but it was
* easier than disabling the Bison Voodoo that gets executed by default.
*
* 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>
#endif
static char *sig_name[] = {
SIG_NAME,0
};
#ifdef VOIDSIG
#define handlertype void
#else
#define handlertype int
#endif
static handlertype sighandler();
static int origalen = 0;
STR *
stab_str(str)
STR *str;
{
STAB *stab = str->str_u.str_stab;
register int paren;
register char *s;
register int i;
if (str->str_rare)
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 '\t': /* ^I */
if (inplace)
str_set(stab_val(stab), inplace);
else
str_sset(stab_val(stab),&str_undef);
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));
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_val(stab),s,i);
else
str_sset(stab_val(stab),&str_undef);
}
else
str_sset(stab_val(stab),&str_undef);
}
break;
case '+':
if (curspat) {
paren = curspat->spat_regexp->lastparen;
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_nset(stab_val(stab),s, curspat->spat_regexp->subend - s);
}
else
str_nset(stab_val(stab),"",0);
}
break;
case '.':
#ifndef lint
if (last_in_stab) {
str_numset(stab_val(stab),(double)stab_io(last_in_stab)->lines);
}
#endif
break;
case '?':
str_numset(stab_val(stab),(double)statusvalue);
break;
case '^':
s = stab_io(curoutstab)->top_name;
str_set(stab_val(stab),s);
break;
case '~':
s = stab_io(curoutstab)->fmt_name;
str_set(stab_val(stab),s);
break;
#ifndef lint
case '=':
str_numset(stab_val(stab),(double)stab_io(curoutstab)->page_len);
break;
case '-':
str_numset(stab_val(stab),(double)stab_io(curoutstab)->lines_left);
break;
case '%':
str_numset(stab_val(stab),(double)stab_io(curoutstab)->page);
break;
#endif
case '/':
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;
case ',':
str_nset(stab_val(stab),ofs,ofslen);
break;
case '\\':
str_nset(stab_val(stab),ors,orslen);
break;
case '#':
str_set(stab_val(stab),ofmt);
break;
case '!':
str_numset(stab_val(stab), (double)errno);
str_set(stab_val(stab), errno ? strerror(errno) : "");
stab_val(stab)->str_nok = 1; /* what a wonderful hack! */
break;
case '<':
str_numset(stab_val(stab),(double)uid);
break;
case '>':
str_numset(stab_val(stab),(double)euid);
break;
case '(':
s = buf;
(void)sprintf(s,"%d",(int)gid);
goto add_groups;
case ')':
s = buf;
(void)sprintf(s,"%d",(int)egid);
add_groups:
while (*s) s++;
#ifdef HAS_GETGROUPS
#ifndef NGROUPS
#define NGROUPS 32
#endif
{
GROUPSTYPE gary[NGROUPS];
i = getgroups(NGROUPS,gary);
while (--i >= 0) {
(void)sprintf(s," %ld", (long)gary[i]);
while (*s) s++;
}
}
#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);
}
stabset(mstr,str)
register STR *mstr;
STR *str;
{
STAB *stab = mstr->str_u.str_stab;
register char *s;
int i;
switch (mstr->str_rare) {
case 'E':
my_setenv(mstr->str_ptr,str_get(str));
/* And you'll never guess what the dog had */
/* 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 (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);
if (!index(s,'\'')) {
sprintf(tokenbuf, "main'%s",s);
str_set(str,tokenbuf);
}
}
break;
#ifdef SOME_DBM
case 'D':
hdbmstore(stab_hash(stab),mstr->str_ptr,mstr->str_cur,str);
break;
#endif
case 'L':
{
CMD *cmd;
i = str_true(str);
str = afetch(stab_xarray(stab),atoi(mstr->str_ptr), FALSE);
cmd = str->str_magic->str_u.str_cmd;
cmd->c_flags &= ~CF_OPTIMIZE;
cmd->c_flags |= i? CFT_D1 : CFT_D0;
}
break;
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) = curcmd->c_line;
stab_stash(stab) = curcmd->c_stash;
}
else {
stab = stabent(s,TRUE);
if (!stab_xarray(stab))
aadd(stab);
if (!stab_xhash(stab))
hadd(stab);
if (!stab_io(stab))
stab_io(stab) = stio_new();
}
str_sset(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,
tmps,str->str_cur);
}
break;
case 'v':
do_vecset(mstr,str);
break;
case 0:
switch (*stab->str_magic->str_ptr) {
case '\004': /* ^D */
#ifdef DEBUGGING
debug = (int)(str_gnum(str)) | 32768;
#endif
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 '\024': /* ^T */
basetime = (long)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));
stab_io(curoutstab)->top_stab = stabent(s,TRUE);
break;
case '~':
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 '=':
stab_io(curoutstab)->page_len = (long)str_gnum(str);
break;
case '-':
stab_io(curoutstab)->lines_left = (long)str_gnum(str);
if (stab_io(curoutstab)->lines_left < 0L)
stab_io(curoutstab)->lines_left = 0L;
break;
case '%':
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;
}
break;
case '*':
i = (int)str_gnum(str);
multiline = (i != 0);
break;
case '/':
if (str->str_pok) {
rs = str_get(str);
rslen = str->str_cur;
if (!rslen) {
rs = "\n\n";
rslen = 2;
}
rschar = rs[rslen - 1];
}
else {
rschar = 0777; /* fake a non-existent char */
rslen = 1;
}
break;
case '\\':
if (ors)
Safefree(ors);
ors = savestr(str_get(str));
orslen = str->str_cur;
break;
case ',':
if (ofs)
Safefree(ofs);
ofs = savestr(str_get(str));
ofslen = str->str_cur;
break;
case '#':
if (ofmt)
Safefree(ofmt);
ofmt = savestr(str_get(str));
break;
case '[':
arybase = (int)str_gnum(str);
break;
case '?':
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 HAS_SETREUID
if (delaymagic) {
delaymagic |= DM_REUID;
break; /* don't do magic till later */
}
#endif /* HAS_SETREUID */
#ifdef HAS_SETRUID
if (setruid((UIDTYPE)uid) < 0)
uid = (int)getuid();
#else
#ifdef HAS_SETREUID
if (setreuid((UIDTYPE)uid, (UIDTYPE)-1) < 0)
uid = (int)getuid();
#else
if (uid == euid) /* special case $< = $> */
setuid(uid);
else
fatal("setruid() not implemented");
#endif
#endif
break;
case '>':
euid = (int)str_gnum(str);
#ifdef HAS_SETREUID
if (delaymagic) {
delaymagic |= DM_REUID;
break; /* don't do magic till later */
}
#endif /* HAS_SETREUID */
#ifdef HAS_SETEUID
if (seteuid((UIDTYPE)euid) < 0)
euid = (int)geteuid();
#else
#ifdef HAS_SETREUID
if (setreuid((UIDTYPE)-1, (UIDTYPE)euid) < 0)
euid = (int)geteuid();
#else
if (euid == uid) /* special case $> = $< */
setuid(euid);
else
fatal("seteuid() not implemented");
#endif
#endif
break;
case '(':
gid = (int)str_gnum(str);
#ifdef HAS_SETREGID
if (delaymagic) {
delaymagic |= DM_REGID;
break; /* don't do magic till later */
}
#endif /* HAS_SETREGID */
#ifdef HAS_SETRGID
(void)setrgid((GIDTYPE)gid);
#else
#ifdef HAS_SETREGID
(void)setregid((GIDTYPE)gid, (GIDTYPE)-1);
#else
fatal("setrgid() not implemented");
#endif
#endif
break;
case ')':
egid = (int)str_gnum(str);
#ifdef HAS_SETREGID
if (delaymagic) {
delaymagic |= DM_REGID;
break; /* don't do magic till later */
}
#endif /* HAS_SETREGID */
#ifdef HAS_SETEGID
(void)setegid((GIDTYPE)egid);
#else
#ifdef HAS_SETREGID
(void)setregid((GIDTYPE)-1, (GIDTYPE)egid);
#else
fatal("setegid() not implemented");
#endif
#endif
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';
bcopy(s, origargv[0], i);
}
else {
bcopy(s, origargv[0], i);
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;
}
}
whichsig(sig)
char *sig;
{
register char **sigv;
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;
{
STAB *stab;
STR *str;
int oldsave = savestack->ary_fill;
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);
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_name(stab) );
return;
}
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;
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));
savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
}
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 *
aadd(stab)
register STAB *stab;
{
if (!stab_xarray(stab))
stab_xarray(stab) = anew(stab);
return stab;
}
STAB *
hadd(stab)
register STAB *stab;
{
if (!stab_xhash(stab))
stab_xhash(stab) = hnew(COEFFSIZE);
return 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;
{
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 if (curcmd == &compiling)
stash = curstash;
else
stash = curcmd->c_stash;
if (sawquote) {
char tmpbuf[256];
char *s, *d;
*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);
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 == (STAB*)&str_undef)
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) = curcmd->c_line;
str_magic(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);
}
return stab;
}
}
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);
}
STIO *
stio_new()
{
STIO *stio;
Newz(603,stio,1,STIO);
stio->page_len = 60;
return stio;
}
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 (entry = defstash->tbl_array[i]; entry; entry = entry->hent_next) {
stab = (STAB*)entry->hent_val;
if (stab->str_pok & SP_MULTI)
continue;
curcmd->c_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));
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;
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 */