blob: 2f8e9001aecad8e8e25c68468b36119b90e2cc2e [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/11 17:40:14 lwall
* patch1: fixed undefined environ problem
* patch1: fixed debugger coredump on subroutines
*
* Revision 4.0 91/03/20 01:06:42 lwall
* 4.0 baseline.
*
*/
#include "EXTERN.h"
#include "perl.h"
#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
#include <signal.h>
#endif
extern unsigned char fold[];
#ifdef BUGGY_MSC
#pragma function(memcmp)
#endif /* BUGGY_MSC */
int
do_subst(str,arg,sp)
STR *str;
ARG *arg;
int sp;
{
register SPAT *spat;
SPAT *rspat;
register STR *dstr;
register char *s = str_get(str);
char *strend = s + str->str_cur;
register char *m;
char *c;
register char *d;
int clen;
int iters = 0;
int maxiters = (strend - s) + 10;
register int i;
bool once;
char *orig;
int safebase;
rspat = spat = arg[2].arg_ptr.arg_spat;
if (!spat || !s)
fatal("panic: do_subst");
else if (spat->spat_runtime) {
nointrp = "|)";
(void)eval(spat->spat_runtime,G_SCALAR,sp);
m = str_get(dstr = stack->ary_array[sp+1]);
nointrp = "";
if (spat->spat_regexp) {
regfree(spat->spat_regexp);
spat->spat_regexp = Null(REGEXP*); /* required if regcomp pukes */
}
spat->spat_regexp = regcomp(m,m+dstr->str_cur,
spat->spat_flags & SPAT_FOLD);
if (spat->spat_flags & SPAT_KEEP) {
arg_free(spat->spat_runtime); /* it won't change, so */
spat->spat_runtime = Nullarg; /* no point compiling again */
}
}
#ifdef DEBUGGING
if (debug & 8) {
deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
}
#endif
safebase = ((!spat->spat_regexp || !spat->spat_regexp->nparens) &&
!sawampersand);
if (!*spat->spat_regexp->precomp && lastspat)
spat = lastspat;
orig = m = s;
if (hint) {
if (hint < s || hint > strend)
fatal("panic: hint in do_match");
s = hint;
hint = Nullch;
if (spat->spat_regexp->regback >= 0) {
s -= spat->spat_regexp->regback;
if (s < m)
s = m;
}
else
s = m;
}
else if (spat->spat_short) {
if (spat->spat_flags & SPAT_SCANFIRST) {
if (str->str_pok & SP_STUDIED) {
if (screamfirst[spat->spat_short->str_rare] < 0)
goto nope;
else if (!(s = screaminstr(str,spat->spat_short)))
goto nope;
}
#ifndef lint
else if (!(s = fbminstr((unsigned char*)s, (unsigned char*)strend,
spat->spat_short)))
goto nope;
#endif
if (s && spat->spat_regexp->regback >= 0) {
++spat->spat_short->str_u.str_useful;
s -= spat->spat_regexp->regback;
if (s < m)
s = m;
}
else
s = m;
}
else if (!multiline && (*spat->spat_short->str_ptr != *s ||
bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) ))
goto nope;
if (--spat->spat_short->str_u.str_useful < 0) {
str_free(spat->spat_short);
spat->spat_short = Nullstr; /* opt is being useless */
}
}
once = ((rspat->spat_flags & SPAT_ONCE) != 0);
if (rspat->spat_flags & SPAT_CONST) { /* known replacement string? */
if ((rspat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
dstr = rspat->spat_repl[1].arg_ptr.arg_str;
else { /* constant over loop, anyway */
(void)eval(rspat->spat_repl,G_SCALAR,sp);
dstr = stack->ary_array[sp+1];
}
c = str_get(dstr);
clen = dstr->str_cur;
if (clen <= spat->spat_slen + (int)spat->spat_regexp->regback) {
/* can do inplace substitution */
if (regexec(spat->spat_regexp, s, strend, orig, 0,
str->str_pok & SP_STUDIED ? str : Nullstr, safebase)) {
if (spat->spat_regexp->subbase) /* oops, no we can't */
goto long_way;
d = s;
lastspat = spat;
str->str_pok = SP_VALID; /* disable possible screamer */
if (once) {
m = spat->spat_regexp->startp[0];
d = spat->spat_regexp->endp[0];
s = orig;
if (m - s > strend - d) { /* faster to shorten from end */
if (clen) {
(void)bcopy(c, m, clen);
m += clen;
}
i = strend - d;
if (i > 0) {
(void)bcopy(d, m, i);
m += i;
}
*m = '\0';
str->str_cur = m - s;
STABSET(str);
str_numset(arg->arg_ptr.arg_str, 1.0);
stack->ary_array[++sp] = arg->arg_ptr.arg_str;
return sp;
}
else if (i = m - s) { /* faster from front */
d -= clen;
m = d;
str_chop(str,d-i);
s += i;
while (i--)
*--d = *--s;
if (clen)
(void)bcopy(c, m, clen);
STABSET(str);
str_numset(arg->arg_ptr.arg_str, 1.0);
stack->ary_array[++sp] = arg->arg_ptr.arg_str;
return sp;
}
else if (clen) {
d -= clen;
str_chop(str,d);
(void)bcopy(c,d,clen);
STABSET(str);
str_numset(arg->arg_ptr.arg_str, 1.0);
stack->ary_array[++sp] = arg->arg_ptr.arg_str;
return sp;
}
else {
str_chop(str,d);
STABSET(str);
str_numset(arg->arg_ptr.arg_str, 1.0);
stack->ary_array[++sp] = arg->arg_ptr.arg_str;
return sp;
}
/* NOTREACHED */
}
do {
if (iters++ > maxiters)
fatal("Substitution loop");
m = spat->spat_regexp->startp[0];
if (i = m - s) {
if (s != d)
(void)bcopy(s,d,i);
d += i;
}
if (clen) {
(void)bcopy(c,d,clen);
d += clen;
}
s = spat->spat_regexp->endp[0];
} while (regexec(spat->spat_regexp, s, strend, orig, s == m,
Nullstr, TRUE)); /* (don't match same null twice) */
if (s != d) {
i = strend - s;
str->str_cur = d - str->str_ptr + i;
(void)bcopy(s,d,i+1); /* include the Null */
}
STABSET(str);
str_numset(arg->arg_ptr.arg_str, (double)iters);
stack->ary_array[++sp] = arg->arg_ptr.arg_str;
return sp;
}
str_numset(arg->arg_ptr.arg_str, 0.0);
stack->ary_array[++sp] = arg->arg_ptr.arg_str;
return sp;
}
}
else
c = Nullch;
if (regexec(spat->spat_regexp, s, strend, orig, 0,
str->str_pok & SP_STUDIED ? str : Nullstr, safebase)) {
long_way:
dstr = Str_new(25,str_len(str));
str_nset(dstr,m,s-m);
if (spat->spat_regexp->subbase)
curspat = spat;
lastspat = spat;
do {
if (iters++ > maxiters)
fatal("Substitution loop");
if (spat->spat_regexp->subbase
&& spat->spat_regexp->subbase != orig) {
m = s;
s = orig;
orig = spat->spat_regexp->subbase;
s = orig + (m - s);
strend = s + (strend - m);
}
m = spat->spat_regexp->startp[0];
str_ncat(dstr,s,m-s);
s = spat->spat_regexp->endp[0];
if (c) {
if (clen)
str_ncat(dstr,c,clen);
}
else {
char *mysubbase = spat->spat_regexp->subbase;
spat->spat_regexp->subbase = Nullch; /* so recursion works */
(void)eval(rspat->spat_repl,G_SCALAR,sp);
str_scat(dstr,stack->ary_array[sp+1]);
if (spat->spat_regexp->subbase)
Safefree(spat->spat_regexp->subbase);
spat->spat_regexp->subbase = mysubbase;
}
if (once)
break;
} while (regexec(spat->spat_regexp, s, strend, orig, s == m, Nullstr,
safebase));
str_ncat(dstr,s,strend - s);
str_replace(str,dstr);
STABSET(str);
str_numset(arg->arg_ptr.arg_str, (double)iters);
stack->ary_array[++sp] = arg->arg_ptr.arg_str;
return sp;
}
str_numset(arg->arg_ptr.arg_str, 0.0);
stack->ary_array[++sp] = arg->arg_ptr.arg_str;
return sp;
nope:
++spat->spat_short->str_u.str_useful;
str_numset(arg->arg_ptr.arg_str, 0.0);
stack->ary_array[++sp] = arg->arg_ptr.arg_str;
return sp;
}
#ifdef BUGGY_MSC
#pragma intrinsic(memcmp)
#endif /* BUGGY_MSC */
int
do_trans(str,arg)
STR *str;
ARG *arg;
{
register short *tbl;
register char *s;
register int matches = 0;
register int ch;
register char *send;
register char *d;
register int squash = arg[2].arg_len & 1;
tbl = (short*) arg[2].arg_ptr.arg_cval;
s = str_get(str);
send = s + str->str_cur;
if (!tbl || !s)
fatal("panic: do_trans");
#ifdef DEBUGGING
if (debug & 8) {
deb("2.TBL\n");
}
#endif
if (!arg[2].arg_len) {
while (s < send) {
if ((ch = tbl[*s & 0377]) >= 0) {
matches++;
*s = ch;
}
s++;
}
}
else {
d = s;
while (s < send) {
if ((ch = tbl[*s & 0377]) >= 0) {
*d = ch;
if (matches++ && squash) {
if (d[-1] == *d)
matches--;
else
d++;
}
else
d++;
}
else if (ch == -1) /* -1 is unmapped character */
*d++ = *s; /* -2 is delete character */
s++;
}
matches += send - d; /* account for disappeared chars */
*d = '\0';
str->str_cur = d - str->str_ptr;
}
STABSET(str);
return matches;
}
void
do_join(str,arglast)
register STR *str;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register int items = arglast[2] - sp;
register char *delim = str_get(st[sp]);
int delimlen = st[sp]->str_cur;
st += ++sp;
if (items-- > 0)
str_sset(str, *st++);
else
str_set(str,"");
if (delimlen) {
for (; items > 0; items--,st++) {
str_ncat(str,delim,delimlen);
str_scat(str,*st);
}
}
else {
for (; items > 0; items--,st++)
str_scat(str,*st);
}
STABSET(str);
}
void
do_pack(str,arglast)
register STR *str;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register int items;
register char *pat = str_get(st[sp]);
register char *patend = pat + st[sp]->str_cur;
register int len;
int datumtype;
STR *fromstr;
static char *null10 = "\0\0\0\0\0\0\0\0\0\0";
static char *space10 = " ";
/* These must not be in registers: */
char achar;
short ashort;
int aint;
unsigned int auint;
long along;
unsigned long aulong;
char *aptr;
float afloat;
double adouble;
items = arglast[2] - sp;
st += ++sp;
str_nset(str,"",0);
while (pat < patend) {
#define NEXTFROM (items-- > 0 ? *st++ : &str_no)
datumtype = *pat++;
if (*pat == '*') {
len = index("@Xxu",datumtype) ? 0 : items;
pat++;
}
else if (isdigit(*pat)) {
len = *pat++ - '0';
while (isdigit(*pat))
len = (len * 10) + (*pat++ - '0');
}
else
len = 1;
switch(datumtype) {
default:
break;
case '%':
fatal("% may only be used in unpack");
case '@':
len -= str->str_cur;
if (len > 0)
goto grow;
len = -len;
if (len > 0)
goto shrink;
break;
case 'X':
shrink:
if (str->str_cur < len)
fatal("X outside of string");
str->str_cur -= len;
str->str_ptr[str->str_cur] = '\0';
break;
case 'x':
grow:
while (len >= 10) {
str_ncat(str,null10,10);
len -= 10;
}
str_ncat(str,null10,len);
break;
case 'A':
case 'a':
fromstr = NEXTFROM;
aptr = str_get(fromstr);
if (pat[-1] == '*')
len = fromstr->str_cur;
if (fromstr->str_cur > len)
str_ncat(str,aptr,len);
else {
str_ncat(str,aptr,fromstr->str_cur);
len -= fromstr->str_cur;
if (datumtype == 'A') {
while (len >= 10) {
str_ncat(str,space10,10);
len -= 10;
}
str_ncat(str,space10,len);
}
else {
while (len >= 10) {
str_ncat(str,null10,10);
len -= 10;
}
str_ncat(str,null10,len);
}
}
break;
case 'B':
case 'b':
{
char *savepat = pat;
int saveitems = items;
fromstr = NEXTFROM;
aptr = str_get(fromstr);
if (pat[-1] == '*')
len = fromstr->str_cur;
pat = aptr;
aint = str->str_cur;
str->str_cur += (len+7)/8;
STR_GROW(str, str->str_cur + 1);
aptr = str->str_ptr + aint;
if (len > fromstr->str_cur)
len = fromstr->str_cur;
aint = len;
items = 0;
if (datumtype == 'B') {
for (len = 0; len++ < aint;) {
items |= *pat++ & 1;
if (len & 7)
items <<= 1;
else {
*aptr++ = items & 0xff;
items = 0;
}
}
}
else {
for (len = 0; len++ < aint;) {
if (*pat++ & 1)
items |= 128;
if (len & 7)
items >>= 1;
else {
*aptr++ = items & 0xff;
items = 0;
}
}
}
if (aint & 7) {
if (datumtype == 'B')
items <<= 7 - (aint & 7);
else
items >>= 7 - (aint & 7);
*aptr++ = items & 0xff;
}
pat = str->str_ptr + str->str_cur;
while (aptr <= pat)
*aptr++ = '\0';
pat = savepat;
items = saveitems;
}
break;
case 'H':
case 'h':
{
char *savepat = pat;
int saveitems = items;
fromstr = NEXTFROM;
aptr = str_get(fromstr);
if (pat[-1] == '*')
len = fromstr->str_cur;
pat = aptr;
aint = str->str_cur;
str->str_cur += (len+1)/2;
STR_GROW(str, str->str_cur + 1);
aptr = str->str_ptr + aint;
if (len > fromstr->str_cur)
len = fromstr->str_cur;
aint = len;
items = 0;
if (datumtype == 'H') {
for (len = 0; len++ < aint;) {
if (isalpha(*pat))
items |= ((*pat++ & 15) + 9) & 15;
else
items |= *pat++ & 15;
if (len & 1)
items <<= 4;
else {
*aptr++ = items & 0xff;
items = 0;
}
}
}
else {
for (len = 0; len++ < aint;) {
if (isalpha(*pat))
items |= (((*pat++ & 15) + 9) & 15) << 4;
else
items |= (*pat++ & 15) << 4;
if (len & 1)
items >>= 4;
else {
*aptr++ = items & 0xff;
items = 0;
}
}
}
if (aint & 1)
*aptr++ = items & 0xff;
pat = str->str_ptr + str->str_cur;
while (aptr <= pat)
*aptr++ = '\0';
pat = savepat;
items = saveitems;
}
break;
case 'C':
case 'c':
while (len-- > 0) {
fromstr = NEXTFROM;
aint = (int)str_gnum(fromstr);
achar = aint;
str_ncat(str,&achar,sizeof(char));
}
break;
/* Float and double added by gnb@melba.bby.oz.au 22/11/89 */
case 'f':
case 'F':
while (len-- > 0) {
fromstr = NEXTFROM;
afloat = (float)str_gnum(fromstr);
str_ncat(str, (char *)&afloat, sizeof (float));
}
break;
case 'd':
case 'D':
while (len-- > 0) {
fromstr = NEXTFROM;
adouble = (double)str_gnum(fromstr);
str_ncat(str, (char *)&adouble, sizeof (double));
}
break;
case 'n':
while (len-- > 0) {
fromstr = NEXTFROM;
ashort = (short)str_gnum(fromstr);
#ifdef HAS_HTONS
ashort = htons(ashort);
#endif
str_ncat(str,(char*)&ashort,sizeof(short));
}
break;
case 'S':
case 's':
while (len-- > 0) {
fromstr = NEXTFROM;
ashort = (short)str_gnum(fromstr);
str_ncat(str,(char*)&ashort,sizeof(short));
}
break;
case 'I':
while (len-- > 0) {
fromstr = NEXTFROM;
auint = U_I(str_gnum(fromstr));
str_ncat(str,(char*)&auint,sizeof(unsigned int));
}
break;
case 'i':
while (len-- > 0) {
fromstr = NEXTFROM;
aint = (int)str_gnum(fromstr);
str_ncat(str,(char*)&aint,sizeof(int));
}
break;
case 'N':
while (len-- > 0) {
fromstr = NEXTFROM;
aulong = U_L(str_gnum(fromstr));
#ifdef HAS_HTONL
aulong = htonl(aulong);
#endif
str_ncat(str,(char*)&aulong,sizeof(unsigned long));
}
break;
case 'L':
while (len-- > 0) {
fromstr = NEXTFROM;
aulong = U_L(str_gnum(fromstr));
str_ncat(str,(char*)&aulong,sizeof(unsigned long));
}
break;
case 'l':
while (len-- > 0) {
fromstr = NEXTFROM;
along = (long)str_gnum(fromstr);
str_ncat(str,(char*)&along,sizeof(long));
}
break;
case 'p':
while (len-- > 0) {
fromstr = NEXTFROM;
aptr = str_get(fromstr);
str_ncat(str,(char*)&aptr,sizeof(char*));
}
break;
case 'u':
fromstr = NEXTFROM;
aptr = str_get(fromstr);
aint = fromstr->str_cur;
STR_GROW(str,aint * 4 / 3);
if (len <= 1)
len = 45;
else
len = len / 3 * 3;
while (aint > 0) {
int todo;
if (aint > len)
todo = len;
else
todo = aint;
doencodes(str, aptr, todo);
aint -= todo;
aptr += todo;
}
break;
}
}
STABSET(str);
}
#undef NEXTFROM
doencodes(str, s, len)
register STR *str;
register char *s;
register int len;
{
char hunk[5];
*hunk = len + ' ';
str_ncat(str, hunk, 1);
hunk[4] = '\0';
while (len > 0) {
hunk[0] = ' ' + (077 & (*s >> 2));
hunk[1] = ' ' + (077 & ((*s << 4) & 060 | (s[1] >> 4) & 017));
hunk[2] = ' ' + (077 & ((s[1] << 2) & 074 | (s[2] >> 6) & 03));
hunk[3] = ' ' + (077 & (s[2] & 077));
str_ncat(str, hunk, 4);
s += 3;
len -= 3;
}
for (s = str->str_ptr; *s; s++) {
if (*s == ' ')
*s = '`';
}
str_ncat(str, "\n", 1);
}
void
do_sprintf(str,len,sarg)
register STR *str;
register int len;
register STR **sarg;
{
register char *s;
register char *t;
register char *f;
bool dolong;
char ch;
static STR *sargnull = &str_no;
register char *send;
char *xs;
int xlen;
double value;
char *origs;
str_set(str,"");
len--; /* don't count pattern string */
origs = t = s = str_get(*sarg);
send = s + (*sarg)->str_cur;
sarg++;
for ( ; ; len--) {
if (len <= 0 || !*sarg) {
sarg = &sargnull;
len = 0;
}
for ( ; t < send && *t != '%'; t++) ;
if (t >= send)
break; /* end of format string, ignore extra args */
f = t;
*buf = '\0';
xs = buf;
dolong = FALSE;
for (t++; t < send; t++) {
switch (*t) {
default:
ch = *(++t);
*t = '\0';
(void)sprintf(xs,f);
len++;
xlen = strlen(xs);
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.': case '#': case '-': case '+': case ' ':
continue;
case 'l':
dolong = TRUE;
continue;
case 'c':
ch = *(++t);
*t = '\0';
xlen = (int)str_gnum(*(sarg++));
if (strEQ(f,"%c")) { /* some printfs fail on null chars */
*xs = xlen;
xs[1] = '\0';
xlen = 1;
}
else {
(void)sprintf(xs,f,xlen);
xlen = strlen(xs);
}
break;
case 'D':
dolong = TRUE;
/* FALL THROUGH */
case 'd':
ch = *(++t);
*t = '\0';
if (dolong)
(void)sprintf(xs,f,(long)str_gnum(*(sarg++)));
else
(void)sprintf(xs,f,(int)str_gnum(*(sarg++)));
xlen = strlen(xs);
break;
case 'X': case 'O':
dolong = TRUE;
/* FALL THROUGH */
case 'x': case 'o': case 'u':
ch = *(++t);
*t = '\0';
value = str_gnum(*(sarg++));
if (dolong)
(void)sprintf(xs,f,U_L(value));
else
(void)sprintf(xs,f,U_I(value));
xlen = strlen(xs);
break;
case 'E': case 'e': case 'f': case 'G': case 'g':
ch = *(++t);
*t = '\0';
(void)sprintf(xs,f,str_gnum(*(sarg++)));
xlen = strlen(xs);
break;
case 's':
ch = *(++t);
*t = '\0';
xs = str_get(*sarg);
xlen = (*sarg)->str_cur;
if (*xs == 'S' && xs[1] == 't' && xs[2] == 'B' && xs[3] == '\0'
&& xlen == sizeof(STBP)) {
STR *tmpstr = Str_new(24,0);
stab_fullname(tmpstr, ((STAB*)(*sarg))); /* a stab value! */
sprintf(tokenbuf,"*%s",tmpstr->str_ptr);
/* reformat to non-binary */
xs = tokenbuf;
xlen = strlen(tokenbuf);
str_free(tmpstr);
}
sarg++;
if (strEQ(f,"%s")) { /* some printfs fail on >128 chars */
break; /* so handle simple case */
}
strcpy(tokenbuf+64,f); /* sprintf($s,...$s...) */
*t = ch;
(void)sprintf(buf,tokenbuf+64,xs);
xs = buf;
xlen = strlen(xs);
break;
}
/* end of switch, copy results */
*t = ch;
STR_GROW(str, str->str_cur + (f - s) + len + 1);
str_ncat(str, s, f - s);
str_ncat(str, xs, xlen);
s = t;
break; /* break from for loop */
}
}
str_ncat(str, s, t - s);
STABSET(str);
}
STR *
do_push(ary,arglast)
register ARRAY *ary;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register int items = arglast[2] - sp;
register STR *str = &str_undef;
for (st += ++sp; items > 0; items--,st++) {
str = Str_new(26,0);
if (*st)
str_sset(str,*st);
(void)apush(ary,str);
}
return str;
}
void
do_unshift(ary,arglast)
register ARRAY *ary;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register int items = arglast[2] - sp;
register STR *str;
register int i;
aunshift(ary,items);
i = 0;
for (st += ++sp; i < items; i++,st++) {
str = Str_new(27,0);
str_sset(str,*st);
(void)astore(ary,i,str);
}
}
int
do_subr(arg,gimme,arglast)
register ARG *arg;
int gimme;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register int items = arglast[2] - sp;
register SUBR *sub;
STR *str;
STAB *stab;
int oldsave = savestack->ary_fill;
int oldtmps_base = tmps_base;
int hasargs = ((arg[2].arg_type & A_MASK) != A_NULL);
register CSV *csv;
if ((arg[1].arg_type & A_MASK) == A_WORD)
stab = arg[1].arg_ptr.arg_stab;
else {
STR *tmpstr = stab_val(arg[1].arg_ptr.arg_stab);
if (tmpstr)
stab = stabent(str_get(tmpstr),TRUE);
else
stab = Nullstab;
}
if (!stab)
fatal("Undefined subroutine called");
if (!(sub = stab_sub(stab))) {
STR *tmpstr = arg[0].arg_ptr.arg_str;
stab_fullname(tmpstr, stab);
fatal("Undefined subroutine \"%s\" called",tmpstr->str_ptr);
}
if (arg->arg_type == O_DBSUBR && !sub->usersub) {
str = stab_val(DBsub);
saveitem(str);
stab_fullname(str,stab);
sub = stab_sub(DBsub);
if (!sub)
fatal("No DBsub routine");
}
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 = gimme;
csv->hasargs = hasargs;
curcsv = csv;
if (sub->usersub) {
csv->hasargs = 0;
csv->savearray = Null(ARRAY*);;
csv->argarray = Null(ARRAY*);
st[sp] = arg->arg_ptr.arg_str;
if (!hasargs)
items = 0;
return (*sub->usersub)(sub->userindex,sp,items);
}
if (hasargs) {
csv->savearray = stab_xarray(defstab);
csv->argarray = afake(defstab, items, &st[sp+1]);
stab_xarray(defstab) = csv->argarray;
}
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;
sp = cmd_exec(sub->cmd,gimme, --sp); /* so do it already */
st = stack->ary_array;
tmps_base = oldtmps_base;
for (items = arglast[0] + 1; items <= sp; items++)
st[items] = str_mortal(st[items]);
/* in case restore wipes old str */
restorelist(oldsave);
return sp;
}
int
do_assign(arg,gimme,arglast)
register ARG *arg;
int gimme;
int *arglast;
{
register STR **st = stack->ary_array;
STR **firstrelem = st + arglast[1] + 1;
STR **firstlelem = st + arglast[0] + 1;
STR **lastrelem = st + arglast[2];
STR **lastlelem = st + arglast[1];
register STR **relem;
register STR **lelem;
register STR *str;
register ARRAY *ary;
register int makelocal;
HASH *hash;
int i;
makelocal = (arg->arg_flags & AF_LOCAL);
localizing = makelocal;
delaymagic = DM_DELAY; /* catch simultaneous items */
/* If there's a common identifier on both sides we have to take
* special care that assigning the identifier on the left doesn't
* clobber a value on the right that's used later in the list.
*/
if (arg->arg_flags & AF_COMMON) {
for (relem = firstrelem; relem <= lastrelem; relem++) {
if (str = *relem)
*relem = str_mortal(str);
}
}
relem = firstrelem;
lelem = firstlelem;
ary = Null(ARRAY*);
hash = Null(HASH*);
while (lelem <= lastlelem) {
str = *lelem++;
if (str->str_state >= SS_HASH) {
if (str->str_state == SS_ARY) {
if (makelocal)
ary = saveary(str->str_u.str_stab);
else {
ary = stab_array(str->str_u.str_stab);
ary->ary_fill = -1;
}
i = 0;
while (relem <= lastrelem) { /* gobble up all the rest */
str = Str_new(28,0);
if (*relem)
str_sset(str,*relem);
*(relem++) = str;
(void)astore(ary,i++,str);
}
}
else if (str->str_state == SS_HASH) {
char *tmps;
STR *tmpstr;
int magic = 0;
STAB *tmpstab = str->str_u.str_stab;
if (makelocal)
hash = savehash(str->str_u.str_stab);
else {
hash = stab_hash(str->str_u.str_stab);
if (tmpstab == envstab) {
magic = 'E';
environ[0] = Nullch;
}
else if (tmpstab == sigstab) {
magic = 'S';
#ifndef NSIG
#define NSIG 32
#endif
for (i = 1; i < NSIG; i++)
signal(i, SIG_DFL); /* crunch, crunch, crunch */
}
#ifdef SOME_DBM
else if (hash->tbl_dbm)
magic = 'D';
#endif
hclear(hash, magic == 'D'); /* wipe any dbm file too */
}
while (relem < lastrelem) { /* gobble up all the rest */
if (*relem)
str = *(relem++);
else
str = &str_no, relem++;
tmps = str_get(str);
tmpstr = Str_new(29,0);
if (*relem)
str_sset(tmpstr,*relem); /* value */
*(relem++) = tmpstr;
(void)hstore(hash,tmps,str->str_cur,tmpstr,0);
if (magic) {
str_magic(tmpstr, tmpstab, magic, tmps, str->str_cur);
stabset(tmpstr->str_magic, tmpstr);
}
}
}
else
fatal("panic: do_assign");
}
else {
if (makelocal)
saveitem(str);
if (relem <= lastrelem) {
str_sset(str, *relem);
*(relem++) = str;
}
else {
str_sset(str, &str_undef);
if (gimme == G_ARRAY) {
i = ++lastrelem - firstrelem;
relem++; /* tacky, I suppose */
astore(stack,i,str);
if (st != stack->ary_array) {
st = stack->ary_array;
firstrelem = st + arglast[1] + 1;
firstlelem = st + arglast[0] + 1;
lastlelem = st + arglast[1];
lastrelem = st + i;
relem = lastrelem + 1;
}
}
}
STABSET(str);
}
}
if (delaymagic > 1) {
if (delaymagic & DM_REUID) {
#ifdef HAS_SETREUID
setreuid(uid,euid);
#else
if (uid != euid || setuid(uid) < 0)
fatal("No setreuid available");
#endif
}
if (delaymagic & DM_REGID) {
#ifdef HAS_SETREGID
setregid(gid,egid);
#else
if (gid != egid || setgid(gid) < 0)
fatal("No setregid available");
#endif
}
}
delaymagic = 0;
localizing = FALSE;
if (gimme == G_ARRAY) {
i = lastrelem - firstrelem + 1;
if (ary || hash)
Copy(firstrelem, firstlelem, i, STR*);
return arglast[0] + i;
}
else {
str_numset(arg->arg_ptr.arg_str,(double)(arglast[2] - arglast[1]));
*firstlelem = arg->arg_ptr.arg_str;
return arglast[0] + 1;
}
}
int
do_study(str,arg,gimme,arglast)
STR *str;
ARG *arg;
int gimme;
int *arglast;
{
register unsigned char *s;
register int pos = str->str_cur;
register int ch;
register int *sfirst;
register int *snext;
static int maxscream = -1;
static STR *lastscream = Nullstr;
int retval;
int retarg = arglast[0] + 1;
#ifndef lint
s = (unsigned char*)(str_get(str));
#else
s = Null(unsigned char*);
#endif
if (lastscream)
lastscream->str_pok &= ~SP_STUDIED;
lastscream = str;
if (pos <= 0) {
retval = 0;
goto ret;
}
if (pos > maxscream) {
if (maxscream < 0) {
maxscream = pos + 80;
New(301,screamfirst, 256, int);
New(302,screamnext, maxscream, int);
}
else {
maxscream = pos + pos / 4;
Renew(screamnext, maxscream, int);
}
}
sfirst = screamfirst;
snext = screamnext;
if (!sfirst || !snext)
fatal("do_study: out of memory");
for (ch = 256; ch; --ch)
*sfirst++ = -1;
sfirst -= 256;
while (--pos >= 0) {
ch = s[pos];
if (sfirst[ch] >= 0)
snext[pos] = sfirst[ch] - pos;
else
snext[pos] = -pos;
sfirst[ch] = pos;
/* If there were any case insensitive searches, we must assume they
* all are. This speeds up insensitive searches much more than
* it slows down sensitive ones.
*/
if (sawi)
sfirst[fold[ch]] = pos;
}
str->str_pok |= SP_STUDIED;
retval = 1;
ret:
str_numset(arg->arg_ptr.arg_str,(double)retval);
stack->ary_array[retarg] = arg->arg_ptr.arg_str;
return retarg;
}
int
do_defined(str,arg,gimme,arglast)
STR *str;
register ARG *arg;
int gimme;
int *arglast;
{
register int type;
register int retarg = arglast[0] + 1;
int retval;
ARRAY *ary;
HASH *hash;
if ((arg[1].arg_type & A_MASK) != A_LEXPR)
fatal("Illegal argument to defined()");
arg = arg[1].arg_ptr.arg_arg;
type = arg->arg_type;
if (type == O_SUBR || type == O_DBSUBR)
retval = stab_sub(arg[1].arg_ptr.arg_stab) != 0;
else if (type == O_ARRAY || type == O_LARRAY ||
type == O_ASLICE || type == O_LASLICE )
retval = ((ary = stab_xarray(arg[1].arg_ptr.arg_stab)) != 0
&& ary->ary_max >= 0 );
else if (type == O_HASH || type == O_LHASH ||
type == O_HSLICE || type == O_LHSLICE )
retval = ((hash = stab_xhash(arg[1].arg_ptr.arg_stab)) != 0
&& hash->tbl_array);
else
retval = FALSE;
str_numset(str,(double)retval);
stack->ary_array[retarg] = str;
return retarg;
}
int
do_undef(str,arg,gimme,arglast)
STR *str;
register ARG *arg;
int gimme;
int *arglast;
{
register int type;
register STAB *stab;
int retarg = arglast[0] + 1;
if ((arg[1].arg_type & A_MASK) != A_LEXPR)
fatal("Illegal argument to undef()");
arg = arg[1].arg_ptr.arg_arg;
type = arg->arg_type;
if (type == O_ARRAY || type == O_LARRAY) {
stab = arg[1].arg_ptr.arg_stab;
afree(stab_xarray(stab));
stab_xarray(stab) = Null(ARRAY*);
}
else if (type == O_HASH || type == O_LHASH) {
stab = arg[1].arg_ptr.arg_stab;
if (stab == envstab)
environ[0] = Nullch;
else if (stab == sigstab) {
int i;
for (i = 1; i < NSIG; i++)
signal(i, SIG_DFL); /* munch, munch, munch */
}
(void)hfree(stab_xhash(stab), TRUE);
stab_xhash(stab) = Null(HASH*);
}
else if (type == O_SUBR || type == O_DBSUBR) {
stab = arg[1].arg_ptr.arg_stab;
if (stab_sub(stab)) {
cmd_free(stab_sub(stab)->cmd);
stab_sub(stab)->cmd = Nullcmd;
afree(stab_sub(stab)->tosave);
Safefree(stab_sub(stab));
stab_sub(stab) = Null(SUBR*);
}
}
else
fatal("Can't undefine that kind of object");
str_numset(str,0.0);
stack->ary_array[retarg] = str;
return retarg;
}
int
do_vec(lvalue,astr,arglast)
int lvalue;
STR *astr;
int *arglast;
{
STR **st = stack->ary_array;
int sp = arglast[0];
register STR *str = st[++sp];
register int offset = (int)str_gnum(st[++sp]);
register int size = (int)str_gnum(st[++sp]);
unsigned char *s = (unsigned char*)str_get(str);
unsigned long retnum;
int len;
sp = arglast[1];
offset *= size; /* turn into bit offset */
len = (offset + size + 7) / 8;
if (offset < 0 || size < 1)
retnum = 0;
else if (!lvalue && len > str->str_cur)
retnum = 0;
else {
if (len > str->str_cur) {
STR_GROW(str,len);
(void)bzero(str->str_ptr + str->str_cur, len - str->str_cur);
str->str_cur = len;
}
s = (unsigned char*)str_get(str);
if (size < 8)
retnum = (s[offset >> 3] >> (offset & 7)) & ((1 << size) - 1);
else {
offset >>= 3;
if (size == 8)
retnum = s[offset];
else if (size == 16)
retnum = (s[offset] << 8) + s[offset+1];
else if (size == 32)
retnum = (s[offset] << 24) + (s[offset + 1] << 16) +
(s[offset + 2] << 8) + s[offset+3];
}
if (lvalue) { /* it's an lvalue! */
struct lstring *lstr = (struct lstring*)astr;
astr->str_magic = str;
st[sp]->str_rare = 'v';
lstr->lstr_offset = offset;
lstr->lstr_len = size;
}
}
str_numset(astr,(double)retnum);
st[sp] = astr;
return sp;
}
void
do_vecset(mstr,str)
STR *mstr;
STR *str;
{
struct lstring *lstr = (struct lstring*)str;
register int offset;
register int size;
register unsigned char *s = (unsigned char*)mstr->str_ptr;
register unsigned long lval = U_L(str_gnum(str));
int mask;
mstr->str_rare = 0;
str->str_magic = Nullstr;
offset = lstr->lstr_offset;
size = lstr->lstr_len;
if (size < 8) {
mask = (1 << size) - 1;
size = offset & 7;
lval &= mask;
offset >>= 3;
s[offset] &= ~(mask << size);
s[offset] |= lval << size;
}
else {
if (size == 8)
s[offset] = lval & 255;
else if (size == 16) {
s[offset] = (lval >> 8) & 255;
s[offset+1] = lval & 255;
}
else if (size == 32) {
s[offset] = (lval >> 24) & 255;
s[offset+1] = (lval >> 16) & 255;
s[offset+2] = (lval >> 8) & 255;
s[offset+3] = lval & 255;
}
}
}
do_chop(astr,str)
register STR *astr;
register STR *str;
{
register char *tmps;
register int i;
ARRAY *ary;
HASH *hash;
HENT *entry;
if (!str)
return;
if (str->str_state == SS_ARY) {
ary = stab_array(str->str_u.str_stab);
for (i = 0; i <= ary->ary_fill; i++)
do_chop(astr,ary->ary_array[i]);
return;
}
if (str->str_state == SS_HASH) {
hash = stab_hash(str->str_u.str_stab);
(void)hiterinit(hash);
while (entry = hiternext(hash))
do_chop(astr,hiterval(hash,entry));
return;
}
tmps = str_get(str);
if (!tmps)
return;
tmps += str->str_cur - (str->str_cur != 0);
str_nset(astr,tmps,1); /* remember last char */
*tmps = '\0'; /* wipe it out */
str->str_cur = tmps - str->str_ptr;
str->str_nok = 0;
STABSET(str);
}
do_vop(optype,str,left,right)
STR *str;
STR *left;
STR *right;
{
register char *s;
register char *l = str_get(left);
register char *r = str_get(right);
register int len;
len = left->str_cur;
if (len > right->str_cur)
len = right->str_cur;
if (str->str_cur > len)
str->str_cur = len;
else if (str->str_cur < len) {
STR_GROW(str,len);
(void)bzero(str->str_ptr + str->str_cur, len - str->str_cur);
str->str_cur = len;
}
s = str->str_ptr;
if (!s) {
str_nset(str,"",0);
s = str->str_ptr;
}
switch (optype) {
case O_BIT_AND:
while (len--)
*s++ = *l++ & *r++;
break;
case O_XOR:
while (len--)
*s++ = *l++ ^ *r++;
goto mop_up;
case O_BIT_OR:
while (len--)
*s++ = *l++ | *r++;
mop_up:
len = str->str_cur;
if (right->str_cur > len)
str_ncat(str,right->str_ptr+len,right->str_cur - len);
else if (left->str_cur > len)
str_ncat(str,left->str_ptr+len,left->str_cur - len);
break;
}
}
int
do_syscall(arglast)
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register int items = arglast[2] - sp;
long arg[8];
register int i = 0;
int retval = -1;
#ifdef HAS_SYSCALL
#ifdef TAINT
for (st += ++sp; items--; st++)
tainted |= (*st)->str_tainted;
st = stack->ary_array;
sp = arglast[1];
items = arglast[2] - sp;
#endif
#ifdef TAINT
taintproper("Insecure dependency in syscall");
#endif
/* This probably won't work on machines where sizeof(long) != sizeof(int)
* or where sizeof(long) != sizeof(char*). But such machines will
* not likely have syscall implemented either, so who cares?
*/
while (items--) {
if (st[++sp]->str_nok || !i)
arg[i++] = (long)str_gnum(st[sp]);
#ifndef lint
else
arg[i++] = (long)st[sp]->str_ptr;
#endif /* lint */
}
sp = arglast[1];
items = arglast[2] - sp;
switch (items) {
case 0:
fatal("Too few args to syscall");
case 1:
retval = syscall(arg[0]);
break;
case 2:
retval = syscall(arg[0],arg[1]);
break;
case 3:
retval = syscall(arg[0],arg[1],arg[2]);
break;
case 4:
retval = syscall(arg[0],arg[1],arg[2],arg[3]);
break;
case 5:
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4]);
break;
case 6:
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
break;
case 7:
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
break;
case 8:
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
arg[7]);
break;
}
return retval;
#else
fatal("syscall() unimplemented");
#endif
}