| /* $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 |
| } |
| |
| |