diff options
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 2296 |
1 files changed, 1469 insertions, 827 deletions
@@ -1,8 +1,13 @@ -/* $Header: eval.c,v 2.0 88/06/05 00:08:48 root Exp $ +/* $Header: eval.c,v 3.0 89/10/18 15:17:04 lwall Locked $ + * + * Copyright (c) 1989, Larry Wall + * + * You may distribute under the terms of the GNU General Public License + * as specified in the README file that comes with the perl 3.0 kit. * * $Log: eval.c,v $ - * Revision 2.0 88/06/05 00:08:48 root - * Baseline version 2.0. + * Revision 3.0 89/10/18 15:17:04 lwall + * 3.0 baseline * */ @@ -12,6 +17,10 @@ #include <signal.h> #include <errno.h> +#ifdef I_VFORK +# include <vfork.h> +#endif + extern int errno; #ifdef VOIDSIG @@ -24,27 +33,36 @@ static int (*qhand)(); ARG *debarg; STR str_args; +static STAB *stab2; +static STIO *stio; +static struct lstring *lstr; +static char old_record_separator; + +double sin(), cos(), atan2(), pow(); -STR * -eval(arg,retary,sargoff) +char *getlogin(); + +extern int sys_nerr; +extern char *sys_errlist[]; + +int +eval(arg,gimme,sp) register ARG *arg; -STR ***retary; /* where to return an array to, null if nowhere */ -int sargoff; /* how many elements in sarg are already assigned */ +int gimme; +register int sp; { register STR *str; register int anum; register int optype; + register STR **st; int maxarg; - int maxsarg; double value; - STR *quicksarg[5]; - register STR **sarg = quicksarg; register char *tmps; char *tmps2; int argflags; int argtype; union argptr argptr; - int cushion; + int arglast[8]; /* highest sp for arg--valid only for non-O_LIST args */ unsigned long tmplong; long when; FILE *fp; @@ -55,319 +73,67 @@ int sargoff; /* how many elements in sarg are already assigned */ bool assigning = FALSE; double exp(), log(), sqrt(), modf(); char *crypt(), *getenv(); + extern void grow_dlevel(); if (!arg) - return &str_no; - str = arg->arg_ptr.arg_str; + goto say_undef; optype = arg->arg_type; - maxsarg = maxarg = arg->arg_len; - if (maxsarg > 3 || retary) { - if (sargoff >= 0) { /* array already exists, just append to it */ - cushion = 10; - sarg = (STR **)saferealloc((char*)*retary, - (maxsarg+sargoff+2+cushion) * sizeof(STR*)) + sargoff; - /* Note that sarg points into the middle of the array */ - } - else { - sargoff = cushion = 0; - sarg = (STR **)safemalloc((maxsarg+2) * sizeof(STR*)); - } - } - else - sargoff = 0; + maxarg = arg->arg_len; + arglast[0] = sp; + str = arg->arg_ptr.arg_str; + if (sp + maxarg > stack->ary_max) + astore(stack, sp + maxarg, Nullstr); + st = stack->ary_array; + #ifdef DEBUGGING if (debug) { if (debug & 8) { deb("%s (%lx) %d args:\n",opname[optype],arg,maxarg); } debname[dlevel] = opname[optype][0]; - debdelim[dlevel++] = ':'; + debdelim[dlevel] = ':'; + if (++dlevel >= dlmax) + grow_dlevel(); } #endif - for (anum = 1; anum <= maxarg; anum++) { - argflags = arg[anum].arg_flags; - if (argflags & AF_SPECIAL) - continue; - argtype = arg[anum].arg_type; - argptr = arg[anum].arg_ptr; - re_eval: - switch (argtype) { - default: - sarg[anum] = &str_no; -#ifdef DEBUGGING - tmps = "NULL"; -#endif - break; - case A_EXPR: -#ifdef DEBUGGING - if (debug & 8) { - tmps = "EXPR"; - deb("%d.EXPR =>\n",anum); - } -#endif - if (retary && - (optype == O_LIST || optype == O_ITEM2 || optype == O_ITEM3)) { - *retary = sarg - sargoff; - eval(argptr.arg_arg, retary, anum - 1 + sargoff); - sarg = *retary; /* they do realloc it... */ - argtype = maxarg - anum; /* how many left? */ - maxsarg = (int)(str_gnum(sarg[0])) + argtype; - sargoff = maxsarg - maxarg; - if (argtype > 9 - cushion) { /* we don't have room left */ - sarg = (STR **)saferealloc((char*)sarg, - (maxsarg+2+cushion) * sizeof(STR*)); - } - sarg += sargoff; - } - else - sarg[anum] = eval(argptr.arg_arg, Null(STR***),-1); - break; - case A_CMD: -#ifdef DEBUGGING - if (debug & 8) { - tmps = "CMD"; - deb("%d.CMD (%lx) =>\n",anum,argptr.arg_cmd); - } -#endif - sarg[anum] = cmd_exec(argptr.arg_cmd); - break; - case A_STAB: - sarg[anum] = STAB_STR(argptr.arg_stab); -#ifdef DEBUGGING - if (debug & 8) { - sprintf(buf,"STAB $%s",argptr.arg_stab->stab_name); - tmps = buf; - } -#endif - break; - case A_LEXPR: -#ifdef DEBUGGING - if (debug & 8) { - tmps = "LEXPR"; - deb("%d.LEXPR =>\n",anum); - } -#endif - str = eval(argptr.arg_arg,Null(STR***),-1); - if (!str) - fatal("panic: A_LEXPR"); - goto do_crement; - case A_LVAL: -#ifdef DEBUGGING - if (debug & 8) { - sprintf(buf,"LVAL $%s",argptr.arg_stab->stab_name); - tmps = buf; - } -#endif - str = STAB_STR(argptr.arg_stab); - if (!str) - fatal("panic: A_LVAL"); - do_crement: - assigning = TRUE; - if (argflags & AF_PRE) { - if (argflags & AF_UP) - str_inc(str); - else - str_dec(str); - STABSET(str); - sarg[anum] = str; - str = arg->arg_ptr.arg_str; - } - else if (argflags & AF_POST) { - sarg[anum] = str_static(str); - if (argflags & AF_UP) - str_inc(str); - else - str_dec(str); - STABSET(str); - str = arg->arg_ptr.arg_str; - } - else { - sarg[anum] = str; - } - break; - case A_LARYLEN: - str = sarg[anum] = - argptr.arg_stab->stab_array->ary_magic; -#ifdef DEBUGGING - tmps = "LARYLEN"; -#endif - if (!str) - fatal("panic: A_LEXPR"); - goto do_crement; - case A_ARYLEN: - stab = argptr.arg_stab; - sarg[anum] = stab->stab_array->ary_magic; - str_numset(sarg[anum],(double)(stab->stab_array->ary_fill+arybase)); -#ifdef DEBUGGING - tmps = "ARYLEN"; -#endif - break; - case A_SINGLE: - sarg[anum] = argptr.arg_str; -#ifdef DEBUGGING - tmps = "SINGLE"; -#endif - break; - case A_DOUBLE: - (void) interp(str,str_get(argptr.arg_str)); - sarg[anum] = str; -#ifdef DEBUGGING - tmps = "DOUBLE"; -#endif - break; - case A_BACKTICK: - tmps = str_get(argptr.arg_str); - fp = popen(str_get(interp(str,tmps)),"r"); - tmpstr = str_new(80); - str_set(str,""); - if (fp) { - while (str_gets(tmpstr,fp) != Nullch) { - str_scat(str,tmpstr); - } - statusvalue = pclose(fp); - } - else - statusvalue = -1; - str_free(tmpstr); - sarg[anum] = str; -#ifdef DEBUGGING - tmps = "BACK"; -#endif - break; - case A_INDREAD: - last_in_stab = stabent(str_get(STAB_STR(argptr.arg_stab)),TRUE); - goto do_read; - case A_GLOB: - argflags |= AF_POST; /* enable newline chopping */ - case A_READ: - last_in_stab = argptr.arg_stab; - do_read: - fp = Nullfp; - if (last_in_stab->stab_io) { - fp = last_in_stab->stab_io->fp; - if (!fp) { - if (last_in_stab->stab_io->flags & IOF_ARGV) { - if (last_in_stab->stab_io->flags & IOF_START) { - last_in_stab->stab_io->flags &= ~IOF_START; - last_in_stab->stab_io->lines = 0; - if (alen(last_in_stab->stab_array) < 0) { - tmpstr = str_make("-"); /* assume stdin */ - apush(last_in_stab->stab_array, tmpstr); - } - } - fp = nextargv(last_in_stab); - if (!fp) /* Note: fp != last_in_stab->stab_io->fp */ - do_close(last_in_stab,FALSE); /* now it does */ - } - else if (argtype == A_GLOB) { - (void) interp(str,str_get(last_in_stab->stab_val)); - tmps = str->str_ptr; - if (*tmps == '!') - sprintf(tokenbuf,"%s|",tmps+1); - else { - if (*tmps == ';') - sprintf(tokenbuf, "%s", tmps+1); - else - sprintf(tokenbuf, "echo %s", tmps); - strcat(tokenbuf, - "|tr -s ' \t\f\r' '\\012\\012\\012\\012'|"); - } - do_open(last_in_stab,tokenbuf); - fp = last_in_stab->stab_io->fp; - } - } - } - if (!fp && dowarn) - warn("Read on closed filehandle <%s>",last_in_stab->stab_name); - keepgoing: - if (!fp) - sarg[anum] = &str_no; - else if (!str_gets(str,fp)) { - if (last_in_stab->stab_io->flags & IOF_ARGV) { - fp = nextargv(last_in_stab); - if (fp) - goto keepgoing; - do_close(last_in_stab,FALSE); - last_in_stab->stab_io->flags |= IOF_START; - } - else if (argflags & AF_POST) { - do_close(last_in_stab,FALSE); - } - if (fp == stdin) { - clearerr(fp); - } - sarg[anum] = &str_no; - if (retary) { - maxarg = anum - 1; - maxsarg = maxarg + sargoff; - } - break; - } - else { - last_in_stab->stab_io->lines++; - sarg[anum] = str; - if (argflags & AF_POST) { - if (str->str_cur > 0) - str->str_cur--; - str->str_ptr[str->str_cur] = '\0'; - } - if (retary) { - sarg[anum] = str_static(sarg[anum]); - anum++; - if (anum > maxarg) { - maxarg = anum + anum; - maxsarg = maxarg + sargoff; - sarg = (STR **)saferealloc((char*)(sarg-sargoff), - (maxsarg+2+cushion) * sizeof(STR*)) + sargoff; - } - goto keepgoing; - } - } - if (retary) { - maxarg = anum - 1; - maxsarg = maxarg + sargoff; - } -#ifdef DEBUGGING - tmps = "READ"; -#endif - break; - } -#ifdef DEBUGGING - if (debug & 8) - deb("%d.%s = '%s'\n",anum,tmps,str_peek(sarg[anum])); -#endif - } +#include "evalargs.xc" + + st += arglast[0]; switch (optype) { + case O_RCAT: + STABSET(str); + break; case O_ITEM: - if (maxarg > arg->arg_len) + if (gimme == G_ARRAY) goto array_return; - if (str != sarg[1]) - str_sset(str,sarg[1]); + STR_SSET(str,st[1]); STABSET(str); break; case O_ITEM2: - if (str != sarg[--anum]) - str_sset(str,sarg[anum]); + if (gimme == G_ARRAY) + goto array_return; + --anum; + STR_SSET(str,st[arglast[anum]-arglast[0]]); STABSET(str); break; case O_ITEM3: - if (str != sarg[--anum]) - str_sset(str,sarg[anum]); + if (gimme == G_ARRAY) + goto array_return; + --anum; + STR_SSET(str,st[arglast[anum]-arglast[0]]); STABSET(str); break; case O_CONCAT: - if (str != sarg[1]) - str_sset(str,sarg[1]); - str_scat(str,sarg[2]); + STR_SSET(str,st[1]); + str_scat(str,st[2]); STABSET(str); break; case O_REPEAT: - if (str != sarg[1]) - str_sset(str,sarg[1]); - anum = (int)str_gnum(sarg[2]); + STR_SSET(str,st[1]); + anum = (int)str_gnum(st[2]); if (anum >= 1) { - tmpstr = str_new(0); + tmpstr = Str_new(50,0); str_sset(tmpstr,str); while (--anum > 0) str_scat(str,tmpstr); @@ -377,239 +143,365 @@ int sargoff; /* how many elements in sarg are already assigned */ STABSET(str); break; case O_MATCH: - str_sset(str, do_match(arg, - retary,sarg,&maxsarg,sargoff,cushion)); - if (retary) { - sarg = *retary; /* they realloc it */ + sp = do_match(str,arg, + gimme,arglast); + if (gimme == G_ARRAY) goto array_return; - } STABSET(str); break; case O_NMATCH: - str_sset(str, do_match(arg, - retary,sarg,&maxsarg,sargoff,cushion)); - if (retary) { - sarg = *retary; /* they realloc it */ - goto array_return; /* ignore negation */ - } - str_set(str, str_true(str) ? No : Yes); + sp = do_match(str,arg, + gimme,arglast); + if (gimme == G_ARRAY) + goto array_return; + str_sset(str, str_true(str) ? &str_no : &str_yes); STABSET(str); break; case O_SUBST: - value = (double) do_subst(str, arg); - str = arg->arg_ptr.arg_str; - goto donumset; + sp = do_subst(str,arg,arglast[0]); + goto array_return; case O_NSUBST: - str_set(arg->arg_ptr.arg_str, do_subst(str, arg) ? No : Yes); + sp = do_subst(str,arg,arglast[0]); str = arg->arg_ptr.arg_str; - break; + str_set(str, str_true(str) ? No : Yes); + goto array_return; case O_ASSIGN: - if (arg[1].arg_flags & AF_SPECIAL) - do_assign(str,arg,sarg); + if (arg[1].arg_flags & AF_ARYOK) { + if (arg->arg_len == 1) { + arg->arg_type = O_LOCAL; + arg->arg_flags |= AF_LOCAL; + goto local; + } + else { + arg->arg_type = O_AASSIGN; + goto aassign; + } + } else { - if (str != sarg[2]) - str_sset(str, sarg[2]); - STABSET(str); + arg->arg_type = O_SASSIGN; + goto sassign; } + case O_LOCAL: + local: + arglast[2] = arglast[1]; /* push a null array */ + /* FALL THROUGH */ + case O_AASSIGN: + aassign: + sp = do_assign(arg, + gimme,arglast); + goto array_return; + case O_SASSIGN: + sassign: + STR_SSET(str, st[2]); + STABSET(str); break; case O_CHOP: - tmps = str_get(str); - tmps += str->str_cur - (str->str_cur != 0); - str_set(arg->arg_ptr.arg_str,tmps); /* remember last char */ - *tmps = '\0'; /* wipe it out */ - str->str_cur = tmps - str->str_ptr; - str->str_nok = 0; + st -= arglast[0]; str = arg->arg_ptr.arg_str; + for (sp = arglast[0] + 1; sp <= arglast[1]; sp++) + do_chop(str,st[sp]); + st += arglast[0]; break; + case O_DEFINED: + if (arg[1].arg_type & A_DONT) { + sp = do_defined(str,arg, + gimme,arglast); + goto array_return; + } + else if (str->str_pok || str->str_nok) + goto say_yes; + goto say_no; + case O_UNDEF: + if (arg[1].arg_type & A_DONT) { + sp = do_undef(str,arg, + gimme,arglast); + goto array_return; + } + else if (str != stab_val(defstab)) { + str->str_pok = str->str_nok = 0; + STABSET(str); + } + goto say_undef; case O_STUDY: - value = (double)do_study(str); - str = arg->arg_ptr.arg_str; + sp = do_study(str,arg, + gimme,arglast); + goto array_return; + case O_POW: + value = str_gnum(st[1]); + value = pow(value,str_gnum(st[2])); goto donumset; case O_MULTIPLY: - value = str_gnum(sarg[1]); - value *= str_gnum(sarg[2]); + value = str_gnum(st[1]); + value *= str_gnum(st[2]); goto donumset; case O_DIVIDE: - if ((value = str_gnum(sarg[2])) == 0.0) + if ((value = str_gnum(st[2])) == 0.0) fatal("Illegal division by zero"); - value = str_gnum(sarg[1]) / value; + value = str_gnum(st[1]) / value; goto donumset; case O_MODULO: - if ((tmplong = (unsigned long) str_gnum(sarg[2])) == 0L) + tmplong = (long) str_gnum(st[2]); + if (tmplong == 0L) fatal("Illegal modulus zero"); - value = str_gnum(sarg[1]); - value = (double)(((unsigned long)value) % tmplong); + when = (long)str_gnum(st[1]); +#ifndef lint + if (when >= 0) + value = (double)(when % tmplong); + else + value = (double)(tmplong - (-when % tmplong)); +#endif goto donumset; case O_ADD: - value = str_gnum(sarg[1]); - value += str_gnum(sarg[2]); + value = str_gnum(st[1]); + value += str_gnum(st[2]); goto donumset; case O_SUBTRACT: - value = str_gnum(sarg[1]); - value -= str_gnum(sarg[2]); + value = str_gnum(st[1]); + value -= str_gnum(st[2]); goto donumset; case O_LEFT_SHIFT: - value = str_gnum(sarg[1]); - anum = (int)str_gnum(sarg[2]); - value = (double)(((unsigned long)value) << anum); + value = str_gnum(st[1]); + anum = (int)str_gnum(st[2]); +#ifndef lint + value = (double)(((long)value) << anum); +#endif goto donumset; case O_RIGHT_SHIFT: - value = str_gnum(sarg[1]); - anum = (int)str_gnum(sarg[2]); - value = (double)(((unsigned long)value) >> anum); + value = str_gnum(st[1]); + anum = (int)str_gnum(st[2]); +#ifndef lint + value = (double)(((long)value) >> anum); +#endif goto donumset; case O_LT: - value = str_gnum(sarg[1]); - value = (double)(value < str_gnum(sarg[2])); + value = str_gnum(st[1]); + value = (value < str_gnum(st[2])) ? 1.0 : 0.0; goto donumset; case O_GT: - value = str_gnum(sarg[1]); - value = (double)(value > str_gnum(sarg[2])); + value = str_gnum(st[1]); + value = (value > str_gnum(st[2])) ? 1.0 : 0.0; goto donumset; case O_LE: - value = str_gnum(sarg[1]); - value = (double)(value <= str_gnum(sarg[2])); + value = str_gnum(st[1]); + value = (value <= str_gnum(st[2])) ? 1.0 : 0.0; goto donumset; case O_GE: - value = str_gnum(sarg[1]); - value = (double)(value >= str_gnum(sarg[2])); + value = str_gnum(st[1]); + value = (value >= str_gnum(st[2])) ? 1.0 : 0.0; goto donumset; case O_EQ: - value = str_gnum(sarg[1]); - value = (double)(value == str_gnum(sarg[2])); + if (dowarn) { + if ((!st[1]->str_nok && !looks_like_number(st[1])) || + (!st[2]->str_nok && !looks_like_number(st[2])) ) + warn("Possible use of == on string value"); + } + value = str_gnum(st[1]); + value = (value == str_gnum(st[2])) ? 1.0 : 0.0; goto donumset; case O_NE: - value = str_gnum(sarg[1]); - value = (double)(value != str_gnum(sarg[2])); + value = str_gnum(st[1]); + value = (value != str_gnum(st[2])) ? 1.0 : 0.0; goto donumset; case O_BIT_AND: - value = str_gnum(sarg[1]); - value = (double)(((unsigned long)value) & - (unsigned long)str_gnum(sarg[2])); - goto donumset; + if (!sawvec || st[1]->str_nok || st[2]->str_nok) { + value = str_gnum(st[1]); +#ifndef lint + value = (double)(((long)value) & (long)str_gnum(st[2])); +#endif + goto donumset; + } + else + do_vop(optype,str,st[1],st[2]); + break; case O_XOR: - value = str_gnum(sarg[1]); - value = (double)(((unsigned long)value) ^ - (unsigned long)str_gnum(sarg[2])); - goto donumset; + if (!sawvec || st[1]->str_nok || st[2]->str_nok) { + value = str_gnum(st[1]); +#ifndef lint + value = (double)(((long)value) ^ (long)str_gnum(st[2])); +#endif + goto donumset; + } + else + do_vop(optype,str,st[1],st[2]); + break; case O_BIT_OR: - value = str_gnum(sarg[1]); - value = (double)(((unsigned long)value) | - (unsigned long)str_gnum(sarg[2])); - goto donumset; + if (!sawvec || st[1]->str_nok || st[2]->str_nok) { + value = str_gnum(st[1]); +#ifndef lint + value = (double)(((long)value) | (long)str_gnum(st[2])); +#endif + goto donumset; + } + else + do_vop(optype,str,st[1],st[2]); + break; +/* use register in evaluating str_true() */ case O_AND: - if (str_true(sarg[1])) { + if (str_true(st[1])) { anum = 2; optype = O_ITEM2; argflags = arg[anum].arg_flags; - argtype = arg[anum].arg_type; + if (gimme == G_ARRAY) + argflags |= AF_ARYOK; + argtype = arg[anum].arg_type & A_MASK; argptr = arg[anum].arg_ptr; maxarg = anum = 1; + sp = arglast[0]; + st -= sp; goto re_eval; } else { if (assigning) { - str_sset(str, sarg[1]); + str_sset(str, st[1]); STABSET(str); } else - str = sarg[1]; + str = st[1]; break; } case O_OR: - if (str_true(sarg[1])) { + if (str_true(st[1])) { if (assigning) { - str_sset(str, sarg[1]); + str_sset(str, st[1]); STABSET(str); } else - str = sarg[1]; + str = st[1]; break; } else { anum = 2; optype = O_ITEM2; argflags = arg[anum].arg_flags; - argtype = arg[anum].arg_type; + if (gimme == G_ARRAY) + argflags |= AF_ARYOK; + argtype = arg[anum].arg_type & A_MASK; argptr = arg[anum].arg_ptr; maxarg = anum = 1; + sp = arglast[0]; + st -= sp; goto re_eval; } case O_COND_EXPR: - anum = (str_true(sarg[1]) ? 2 : 3); + anum = (str_true(st[1]) ? 2 : 3); optype = (anum == 2 ? O_ITEM2 : O_ITEM3); argflags = arg[anum].arg_flags; - argtype = arg[anum].arg_type; + if (gimme == G_ARRAY) + argflags |= AF_ARYOK; + argtype = arg[anum].arg_type & A_MASK; argptr = arg[anum].arg_ptr; maxarg = anum = 1; + sp = arglast[0]; + st -= sp; goto re_eval; case O_COMMA: - str = sarg[2]; + if (gimme == G_ARRAY) + goto array_return; + str = st[2]; break; case O_NEGATE: - value = -str_gnum(sarg[1]); + value = -str_gnum(st[1]); goto donumset; case O_NOT: - value = (double) !str_true(sarg[1]); + value = (double) !str_true(st[1]); goto donumset; case O_COMPLEMENT: - value = (double) ~(long)str_gnum(sarg[1]); +#ifndef lint + value = (double) ~(long)str_gnum(st[1]); +#endif goto donumset; case O_SELECT: - if (arg[1].arg_type == A_LVAL) - defoutstab = arg[1].arg_ptr.arg_stab; - else - defoutstab = stabent(str_get(sarg[1]),TRUE); - if (!defoutstab->stab_io) - defoutstab->stab_io = stio_new(); - curoutstab = defoutstab; - str_set(str,curoutstab->stab_io->fp ? Yes : No); + tmps = stab_name(defoutstab); + if (maxarg > 0) { + if ((arg[1].arg_type & A_MASK) == A_WORD) + defoutstab = arg[1].arg_ptr.arg_stab; + else + defoutstab = stabent(str_get(st[1]),TRUE); + if (!stab_io(defoutstab)) + stab_io(defoutstab) = stio_new(); + curoutstab = defoutstab; + } + str_set(str, tmps); STABSET(str); break; case O_WRITE: if (maxarg == 0) stab = defoutstab; - else if (arg[1].arg_type == A_LVAL) - stab = arg[1].arg_ptr.arg_stab; + else if ((arg[1].arg_type & A_MASK) == A_WORD) { + if (!(stab = arg[1].arg_ptr.arg_stab)) + stab = defoutstab; + } else - stab = stabent(str_get(sarg[1]),TRUE); - if (!stab->stab_io) { + stab = stabent(str_get(st[1]),TRUE); + if (!stab_io(stab)) { str_set(str, No); STABSET(str); break; } curoutstab = stab; - fp = stab->stab_io->fp; + fp = stab_io(stab)->ofp; debarg = arg; - if (stab->stab_io->fmt_stab) - form = stab->stab_io->fmt_stab->stab_form; + if (stab_io(stab)->fmt_stab) + form = stab_form(stab_io(stab)->fmt_stab); else - form = stab->stab_form; + form = stab_form(stab); if (!form || !fp) { + if (dowarn) { + if (form) + warn("No format for filehandle"); + else { + if (stab_io(stab)->ifp) + warn("Filehandle only opened for input"); + else + warn("Write on closed filehandle"); + } + } str_set(str, No); STABSET(str); break; } - format(&outrec,form); - do_write(&outrec,stab->stab_io); - if (stab->stab_io->flags & IOF_FLUSH) - fflush(fp); + format(&outrec,form,sp); + do_write(&outrec,stab_io(stab),sp); + if (stab_io(stab)->flags & IOF_FLUSH) + (void)fflush(fp); str_set(str, Yes); STABSET(str); break; + case O_DBMOPEN: +#ifdef SOME_DBM + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + anum = (int)str_gnum(st[3]); + value = (double)hdbmopen(stab_hash(stab),str_get(st[2]),anum); + goto donumset; +#else + fatal("No dbm or ndbm on this machine"); +#endif + case O_DBMCLOSE: +#ifdef SOME_DBM + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + hdbmclose(stab_hash(stab)); + goto say_yes; +#else + fatal("No dbm or ndbm on this machine"); +#endif case O_OPEN: - if (arg[1].arg_type == A_WORD) + if ((arg[1].arg_type & A_MASK) == A_WORD) stab = arg[1].arg_ptr.arg_stab; else - stab = stabent(str_get(sarg[1]),TRUE); - if (do_open(stab,str_get(sarg[2]))) { + stab = stabent(str_get(st[1]),TRUE); + if (do_open(stab,str_get(st[2]))) { value = (double)forkprocess; - stab->stab_io->lines = 0; + stab_io(stab)->lines = 0; goto donumset; } else - str_set(str, No); - STABSET(str); + goto say_undef; break; case O_TRANS: value = (double) do_trans(str,arg); @@ -620,298 +512,490 @@ int sargoff; /* how many elements in sarg are already assigned */ str = arg->arg_ptr.arg_str; break; case O_CLOSE: - if (arg[1].arg_type == A_WORD) + if (maxarg == 0) + stab = defoutstab; + else if ((arg[1].arg_type & A_MASK) == A_WORD) stab = arg[1].arg_ptr.arg_stab; else - stab = stabent(str_get(sarg[1]),TRUE); + stab = stabent(str_get(st[1]),TRUE); str_set(str, do_close(stab,TRUE) ? Yes : No ); STABSET(str); break; case O_EACH: - str_sset(str,do_each(arg[1].arg_ptr.arg_stab->stab_hash, - retary,sarg,&maxsarg,sargoff,cushion)); - if (retary) { - sarg = *retary; /* they realloc it */ - goto array_return; - } - STABSET(str); - break; + sp = do_each(str,stab_hash(arg[1].arg_ptr.arg_stab), + gimme,arglast); + goto array_return; case O_VALUES: case O_KEYS: - value = (double) do_kv(arg[1].arg_ptr.arg_stab->stab_hash, optype, - retary,sarg,&maxsarg,sargoff,cushion); - if (retary) { - sarg = *retary; /* they realloc it */ - goto array_return; - } - goto donumset; + sp = do_kv(str,stab_hash(arg[1].arg_ptr.arg_stab), optype, + gimme,arglast); + goto array_return; + case O_LARRAY: + str->str_nok = str->str_pok = 0; + str->str_u.str_stab = arg[1].arg_ptr.arg_stab; + str->str_state = SS_ARY; + break; case O_ARRAY: - if (maxarg == 1) { - ary = arg[1].arg_ptr.arg_stab->stab_array; - maxarg = ary->ary_fill; - maxsarg = maxarg + sargoff; - if (retary) { /* array wanted */ - sarg = (STR **)saferealloc((char*)(sarg-sargoff), - (maxsarg+3+cushion)*sizeof(STR*)) + sargoff; - for (anum = 0; anum <= maxarg; anum++) { - sarg[anum+1] = str = afetch(ary,anum); - } - maxarg++; - maxsarg++; - goto array_return; + ary = stab_array(arg[1].arg_ptr.arg_stab); + maxarg = ary->ary_fill + 1; + if (gimme == G_ARRAY) { /* array wanted */ + sp = arglast[0]; + st -= sp; + if (maxarg > 0 && sp + maxarg > stack->ary_max) { + astore(stack,sp + maxarg, Nullstr); + st = stack->ary_array; } - else - str = afetch(ary,maxarg); + Copy(ary->ary_array, &st[sp+1], maxarg, STR*); + sp += maxarg; + goto array_return; } else - str = afetch(arg[2].arg_ptr.arg_stab->stab_array, - ((int)str_gnum(sarg[1])) - arybase); + str = afetch(ary,maxarg - 1,FALSE); + break; + case O_AELEM: + str = afetch(stab_array(arg[1].arg_ptr.arg_stab), + ((int)str_gnum(st[2])) - arybase,FALSE); if (!str) - str = &str_no; + goto say_undef; break; case O_DELETE: - tmpstab = arg[2].arg_ptr.arg_stab; /* XXX */ - str = hdelete(tmpstab->stab_hash,str_get(sarg[1])); + tmpstab = arg[1].arg_ptr.arg_stab; + tmps = str_get(st[2]); + str = hdelete(stab_hash(tmpstab),tmps,st[2]->str_cur); + if (tmpstab == envstab) + setenv(tmps,Nullch); if (!str) - str = &str_no; + goto say_undef; + break; + case O_LHASH: + str->str_nok = str->str_pok = 0; + str->str_u.str_stab = arg[1].arg_ptr.arg_stab; + str->str_state = SS_HASH; break; case O_HASH: - tmpstab = arg[2].arg_ptr.arg_stab; /* XXX */ - str = hfetch(tmpstab->stab_hash,str_get(sarg[1])); + if (gimme == G_ARRAY) { /* array wanted */ + sp = do_kv(str,stab_hash(arg[1].arg_ptr.arg_stab), optype, + gimme,arglast); + goto array_return; + } + else { + tmpstab = arg[1].arg_ptr.arg_stab; + sprintf(buf,"%d/%d",stab_hash(tmpstab)->tbl_fill, + stab_hash(tmpstab)->tbl_max+1); + str_set(str,buf); + } + break; + case O_HELEM: + tmpstab = arg[1].arg_ptr.arg_stab; + tmps = str_get(st[2]); + str = hfetch(stab_hash(tmpstab),tmps,st[2]->str_cur,FALSE); if (!str) - str = &str_no; + goto say_undef; break; - case O_LARRAY: - anum = ((int)str_gnum(sarg[1])) - arybase; - str = afetch(arg[2].arg_ptr.arg_stab->stab_array,anum); - if (!str || str == &str_no) { - str = str_new(0); - astore(arg[2].arg_ptr.arg_stab->stab_array,anum,str); - } + case O_LAELEM: + anum = ((int)str_gnum(st[2])) - arybase; + str = afetch(stab_array(arg[1].arg_ptr.arg_stab),anum,TRUE); + if (!str) + fatal("Assignment to non-creatable value, subscript %d",anum); break; - case O_LHASH: - tmpstab = arg[2].arg_ptr.arg_stab; - str = hfetch(tmpstab->stab_hash,str_get(sarg[1])); - if (!str) { - str = str_new(0); - hstore(tmpstab->stab_hash,str_get(sarg[1]),str); - } - if (tmpstab == envstab) { /* heavy wizardry going on here */ - str->str_link.str_magic = tmpstab;/* str is now magic */ - envname = savestr(str_get(sarg[1])); + case O_LHELEM: + tmpstab = arg[1].arg_ptr.arg_stab; + tmps = str_get(st[2]); + anum = st[2]->str_cur; + str = hfetch(stab_hash(tmpstab),tmps,anum,TRUE); + if (!str) + fatal("Assignment to non-creatable value, subscript \"%s\"",tmps); + if (tmpstab == envstab) /* heavy wizardry going on here */ + str_magic(str, tmpstab, 'E', tmps, anum); /* str is now magic */ /* he threw the brick up into the air */ - } - else if (tmpstab == sigstab) { /* same thing, only different */ - str->str_link.str_magic = tmpstab; - signame = savestr(str_get(sarg[1])); - } + else if (tmpstab == sigstab) + str_magic(str, tmpstab, 'S', tmps, anum); +#ifdef SOME_DBM + else if (stab_hash(tmpstab)->tbl_dbm) + str_magic(str, tmpstab, 'D', tmps, anum); +#endif break; + case O_ASLICE: + anum = TRUE; + argtype = FALSE; + goto do_slice_already; + case O_HSLICE: + anum = FALSE; + argtype = FALSE; + goto do_slice_already; + case O_LASLICE: + anum = TRUE; + argtype = TRUE; + goto do_slice_already; + case O_LHSLICE: + anum = FALSE; + argtype = TRUE; + do_slice_already: + sp = do_slice(arg[1].arg_ptr.arg_stab,anum,argtype, + gimme,arglast); + goto array_return; case O_PUSH: - if (arg[1].arg_flags & AF_SPECIAL) - str = do_push(arg,arg[2].arg_ptr.arg_stab->stab_array); + if (arglast[2] - arglast[1] != 1) + str = do_push(stab_array(arg[1].arg_ptr.arg_stab),arglast); else { - str = str_new(0); /* must copy the STR */ - str_sset(str,sarg[1]); - apush(arg[2].arg_ptr.arg_stab->stab_array,str); + str = Str_new(51,0); /* must copy the STR */ + str_sset(str,st[2]); + (void)apush(stab_array(arg[1].arg_ptr.arg_stab),str); } break; case O_POP: - str = apop(arg[1].arg_ptr.arg_stab->stab_array); - if (!str) { - str = &str_no; - break; - } -#ifdef STRUCTCOPY - *(arg->arg_ptr.arg_str) = *str; -#else - bcopy((char*)str, (char*)arg->arg_ptr.arg_str, sizeof *str); -#endif - safefree((char*)str); - str = arg->arg_ptr.arg_str; - break; + str = apop(ary = stab_array(arg[1].arg_ptr.arg_stab)); + goto staticalization; case O_SHIFT: - str = ashift(arg[1].arg_ptr.arg_stab->stab_array); - if (!str) { - str = &str_no; - break; - } -#ifdef STRUCTCOPY - *(arg->arg_ptr.arg_str) = *str; -#else - bcopy((char*)str, (char*)arg->arg_ptr.arg_str, sizeof *str); -#endif - safefree((char*)str); - str = arg->arg_ptr.arg_str; + str = ashift(ary = stab_array(arg[1].arg_ptr.arg_stab)); + staticalization: + if (!str) + goto say_undef; + if (ary->ary_flags & ARF_REAL) + (void)str_2static(str); break; + case O_UNPACK: + sp = do_unpack(str,gimme,arglast); + goto array_return; case O_SPLIT: - value = (double) do_split(arg[2].arg_ptr.arg_spat, - retary,sarg,&maxsarg,sargoff,cushion); - if (retary) { - sarg = *retary; /* they realloc it */ - goto array_return; - } - goto donumset; + value = str_gnum(st[3]); + sp = do_split(str, arg[2].arg_ptr.arg_spat, (int)value, + gimme,arglast); + goto array_return; case O_LENGTH: - value = (double) str_len(sarg[1]); + if (maxarg < 1) + value = (double)str_len(stab_val(defstab)); + else + value = (double)str_len(st[1]); goto donumset; case O_SPRINTF: - sarg[maxsarg+1] = Nullstr; - do_sprintf(str,arg->arg_len,sarg); + do_sprintf(str, sp-arglast[0], st+1); break; case O_SUBSTR: - anum = ((int)str_gnum(sarg[2])) - arybase; - for (tmps = str_get(sarg[1]); *tmps && anum > 0; tmps++,anum--) ; - anum = (int)str_gnum(sarg[3]); - if (anum >= 0 && strlen(tmps) > anum) + anum = ((int)str_gnum(st[2])) - arybase; /* anum=where to start*/ + tmps = str_get(st[1]); /* force conversion to string */ + if (argtype = (str == st[1])) + str = arg->arg_ptr.arg_str; + if (anum < 0) + anum += st[1]->str_cur + arybase; + if (anum < 0 || anum > st[1]->str_cur) + str_nset(str,"",0); + else { + optype = (int)str_gnum(st[3]); + if (optype < 0) + optype = 0; + tmps += anum; + anum = st[1]->str_cur - anum; /* anum=how many bytes left*/ + if (anum > optype) + anum = optype; str_nset(str, tmps, anum); - else - str_set(str, tmps); + if (argtype) { /* it's an lvalue! */ + lstr = (struct lstring*)str; + str->str_magic = st[1]; + st[1]->str_rare = 's'; + lstr->lstr_offset = tmps - str_get(st[1]); + lstr->lstr_len = anum; + } + } + break; + case O_PACK: + (void)do_pack(str,arglast); break; + case O_GREP: + sp = do_grep(arg,str,gimme,arglast); + goto array_return; case O_JOIN: - if (arg[2].arg_flags & AF_SPECIAL && arg[2].arg_type == A_EXPR) - do_join(arg,str_get(sarg[1]),str); - else - ajoin(arg[2].arg_ptr.arg_stab->stab_array,str_get(sarg[1]),str); + do_join(str,arglast); break; case O_SLT: - tmps = str_get(sarg[1]); - value = (double) strLT(tmps,str_get(sarg[2])); + tmps = str_get(st[1]); + value = (double) (str_cmp(st[1],st[2]) < 0); goto donumset; case O_SGT: - tmps = str_get(sarg[1]); - value = (double) strGT(tmps,str_get(sarg[2])); + tmps = str_get(st[1]); + value = (double) (str_cmp(st[1],st[2]) > 0); goto donumset; case O_SLE: - tmps = str_get(sarg[1]); - value = (double) strLE(tmps,str_get(sarg[2])); + tmps = str_get(st[1]); + value = (double) (str_cmp(st[1],st[2]) <= 0); goto donumset; case O_SGE: - tmps = str_get(sarg[1]); - value = (double) strGE(tmps,str_get(sarg[2])); + tmps = str_get(st[1]); + value = (double) (str_cmp(st[1],st[2]) >= 0); goto donumset; case O_SEQ: - tmps = str_get(sarg[1]); - value = (double) strEQ(tmps,str_get(sarg[2])); + tmps = str_get(st[1]); + value = (double) str_eq(st[1],st[2]); goto donumset; case O_SNE: - tmps = str_get(sarg[1]); - value = (double) strNE(tmps,str_get(sarg[2])); + tmps = str_get(st[1]); + value = (double) !str_eq(st[1],st[2]); goto donumset; case O_SUBR: - str_sset(str,do_subr(arg,sarg)); - STABSET(str); - break; + sp = do_subr(arg,gimme,arglast); + st = stack->ary_array + arglast[0]; /* maybe realloced */ + goto array_return; + case O_DBSUBR: + sp = do_dbsubr(arg,gimme,arglast); + st = stack->ary_array + arglast[0]; /* maybe realloced */ + goto array_return; case O_SORT: - if (maxarg <= 1) + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + if (!stab) stab = defoutstab; + sp = do_sort(str,stab, + gimme,arglast); + goto array_return; + case O_REVERSE: + sp = do_reverse(str, + gimme,arglast); + goto array_return; + case O_WARN: + if (arglast[2] - arglast[1] != 1) { + do_join(str,arglast); + tmps = str_get(st[1]); + } else { - if (arg[2].arg_type == A_WORD) - stab = arg[2].arg_ptr.arg_stab; - else - stab = stabent(str_get(sarg[2]),TRUE); - if (!stab) - stab = defoutstab; + str = st[2]; + tmps = str_get(st[2]); } - value = (double)do_sort(arg,stab, - retary,sarg,&maxsarg,sargoff,cushion); - if (retary) { - sarg = *retary; /* they realloc it */ - goto array_return; + if (!tmps || !*tmps) + tmps = "Warning: something's wrong"; + warn("%s",tmps); + goto say_yes; + case O_DIE: + if (arglast[2] - arglast[1] != 1) { + do_join(str,arglast); + tmps = str_get(st[1]); } - goto donumset; + else { + str = st[2]; + tmps = str_get(st[2]); + } + if (!tmps || !*tmps) + exit(1); + fatal("%s",tmps); + goto say_zero; case O_PRTF: case O_PRINT: - if (maxarg <= 1) + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + if (!stab) stab = defoutstab; - else { - if (arg[2].arg_type == A_WORD) - stab = arg[2].arg_ptr.arg_stab; - else - stab = stabent(str_get(sarg[2]),TRUE); - if (!stab) - stab = defoutstab; + if (!stab_io(stab)) { + if (dowarn) + warn("Filehandle never opened"); + goto say_zero; + } + if (!(fp = stab_io(stab)->ofp)) { + if (dowarn) { + if (stab_io(stab)->ifp) + warn("Filehandle opened only for input"); + else + warn("Print on closed filehandle"); + } + goto say_zero; } - if (!stab->stab_io || !(fp = stab->stab_io->fp)) - value = 0.0; else { - if (arg[1].arg_flags & AF_SPECIAL) - value = (double)do_aprint(arg,fp); + if (optype == O_PRTF || arglast[2] - arglast[1] != 1) + value = (double)do_aprint(arg,fp,arglast); else { - value = (double)do_print(sarg[1],fp); - if (ors && optype == O_PRINT) - fputs(ors, fp); + value = (double)do_print(st[2],fp); + if (orslen && optype == O_PRINT) + if (fwrite(ors, 1, orslen, fp) == 0) + goto say_zero; } - if (stab->stab_io->flags & IOF_FLUSH) - fflush(fp); + if (stab_io(stab)->flags & IOF_FLUSH) + if (fflush(fp) == EOF) + goto say_zero; } goto donumset; case O_CHDIR: - tmps = str_get(sarg[1]); - if (!tmps || !*tmps) - tmps = getenv("HOME"); - if (!tmps || !*tmps) - tmps = getenv("LOGDIR"); + if (maxarg < 1) + tmps = str_get(stab_val(defstab)); + else + tmps = str_get(st[1]); + if (!tmps || !*tmps) { + tmpstr = hfetch(stab_hash(envstab),"HOME",4,FALSE); + if (tmpstr) + tmps = str_get(tmpstr); + } + if (!tmps || !*tmps) { + tmpstr = hfetch(stab_hash(envstab),"LOGDIR",6,FALSE); + if (tmpstr) + tmps = str_get(tmpstr); + } +#ifdef TAINT + taintproper("Insecure dependency in chdir"); +#endif value = (double)(chdir(tmps) >= 0); goto donumset; - case O_DIE: - tmps = str_get(sarg[1]); - if (!tmps || !*tmps) - exit(1); - fatal("%s",str_get(sarg[1])); - value = 0.0; - goto donumset; case O_EXIT: - exit((int)str_gnum(sarg[1])); - value = 0.0; - goto donumset; + if (maxarg < 1) + anum = 0; + else + anum = (int)str_gnum(st[1]); + exit(anum); + goto say_zero; case O_RESET: - str_reset(str_get(sarg[1])); + if (maxarg < 1) + tmps = ""; + else + tmps = str_get(st[1]); + str_reset(tmps,arg[2].arg_ptr.arg_hash); value = 1.0; goto donumset; case O_LIST: - if (arg->arg_flags & AF_LOCAL) - savelist(sarg,maxsarg); + if (gimme == G_ARRAY) + goto array_return; if (maxarg > 0) - str = sarg[maxsarg]; /* unwanted list, return last item */ + str = st[sp - arglast[0]]; /* unwanted list, return last item */ else - str = &str_no; - if (retary) - goto array_return; + str = &str_undef; break; case O_EOF: if (maxarg <= 0) stab = last_in_stab; - else if (arg[1].arg_type == A_WORD) + else if ((arg[1].arg_type & A_MASK) == A_WORD) stab = arg[1].arg_ptr.arg_stab; else - stab = stabent(str_get(sarg[1]),TRUE); + stab = stabent(str_get(st[1]),TRUE); str_set(str, do_eof(stab) ? Yes : No); STABSET(str); break; + case O_GETC: + if (maxarg <= 0) + stab = stdinstab; + else if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + if (do_eof(stab)) /* make sure we have fp with something */ + str_set(str, No); + else { +#ifdef TAINT + tainted = 1; +#endif + str_set(str," "); + *str->str_ptr = getc(stab_io(stab)->ifp); /* should never be EOF */ + } + STABSET(str); + break; case O_TELL: if (maxarg <= 0) stab = last_in_stab; - else if (arg[1].arg_type == A_WORD) + else if ((arg[1].arg_type & A_MASK) == A_WORD) stab = arg[1].arg_ptr.arg_stab; else - stab = stabent(str_get(sarg[1]),TRUE); + stab = stabent(str_get(st[1]),TRUE); +#ifndef lint value = (double)do_tell(stab); +#else + (void)do_tell(stab); +#endif goto donumset; + case O_RECV: + case O_READ: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + tmps = str_get(st[2]); + anum = (int)str_gnum(st[3]); + STR_GROW(st[2], anum+1), (tmps = str_get(st[2])); /* sneaky */ + errno = 0; + if (!stab_io(stab) || !stab_io(stab)->ifp) + goto say_zero; +#ifdef SOCKET + else if (optype == O_RECV) { + argtype = sizeof buf; + optype = (int)str_gnum(st[4]); + anum = recvfrom(fileno(stab_io(stab)->ifp), tmps, anum, optype, + buf, &argtype); + if (anum >= 0) { + st[2]->str_cur = anum; + st[2]->str_ptr[anum] = '\0'; + str_nset(str,buf,argtype); + } + else + str_sset(str,&str_undef); + break; + } + else if (stab_io(stab)->type == 's') { + argtype = sizeof buf; + anum = recvfrom(fileno(stab_io(stab)->ifp), tmps, anum, 0, + buf, &argtype); + } +#else + else if (optype == O_RECV) + goto badsock; +#endif + else + anum = fread(tmps, 1, anum, stab_io(stab)->ifp); + if (anum < 0) + goto say_undef; + st[2]->str_cur = anum; + st[2]->str_ptr[anum] = '\0'; + value = (double)anum; + goto donumset; + case O_SEND: +#ifdef SOCKET + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + tmps = str_get(st[2]); + anum = (int)str_gnum(st[3]); + optype = sp - arglast[0]; + errno = 0; + if (optype > 4) + warn("Too many args on send"); + if (optype >= 4) { + tmps2 = str_get(st[4]); + anum = sendto(fileno(stab_io(stab)->ifp), tmps, st[2]->str_cur, + anum, tmps2, st[4]->str_cur); + } + else + anum = send(fileno(stab_io(stab)->ifp), tmps, st[2]->str_cur, anum); + if (anum < 0) + goto say_undef; + value = (double)anum; + goto donumset; +#else + goto badsock; +#endif case O_SEEK: - if (arg[1].arg_type == A_WORD) + if ((arg[1].arg_type & A_MASK) == A_WORD) stab = arg[1].arg_ptr.arg_stab; else - stab = stabent(str_get(sarg[1]),TRUE); - value = str_gnum(sarg[2]); + stab = stabent(str_get(st[1]),TRUE); + value = str_gnum(st[2]); str_set(str, do_seek(stab, - (long)value, (int)str_gnum(sarg[3]) ) ? Yes : No); + (long)value, (int)str_gnum(st[3]) ) ? Yes : No); STABSET(str); break; + case O_RETURN: + tmps = "SUB"; /* just fake up a "last SUB" */ + optype = O_LAST; + if (gimme == G_ARRAY) { + lastretstr = Nullstr; + lastspbase = arglast[1]; + lastsize = arglast[2] - arglast[1]; + } + else + lastretstr = str_static(st[arglast[2] - arglast[0]]); + goto dopop; case O_REDO: case O_NEXT: case O_LAST: if (maxarg > 0) { - tmps = str_get(sarg[1]); + tmps = str_get(arg[1].arg_ptr.arg_str); + dopop: while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label || strNE(tmps,loop_stack[loop_ptr].loop_label) )) { #ifdef DEBUGGING @@ -931,129 +1015,303 @@ int sargoff; /* how many elements in sarg are already assigned */ } if (loop_ptr < 0) fatal("Bad label: %s", maxarg > 0 ? tmps : "<null>"); + if (!lastretstr && optype == O_LAST && lastsize) { + st -= arglast[0]; + st += lastspbase + 1; + optype = loop_stack[loop_ptr].loop_sp - lastspbase; /* negative */ + if (optype) { + for (anum = lastsize; anum > 0; anum--,st++) + st[optype] = str_static(st[0]); + } + longjmp(loop_stack[loop_ptr].loop_env, O_LAST); + } longjmp(loop_stack[loop_ptr].loop_env, optype); + case O_DUMP: case O_GOTO:/* shudder */ - goto_targ = str_get(sarg[1]); + goto_targ = str_get(arg[1].arg_ptr.arg_str); + if (!*goto_targ) + goto_targ = Nullch; /* just restart from top */ + if (optype == O_DUMP) { + do_undump = 1; + abort(); + } longjmp(top_env, 1); case O_INDEX: - tmps = str_get(sarg[1]); - if (!(tmps2 = fbminstr(tmps, tmps + sarg[1]->str_cur, sarg[2]))) + tmps = str_get(st[1]); +#ifndef lint + if (!(tmps2 = fbminstr((unsigned char*)tmps, + (unsigned char*)tmps + st[1]->str_cur, st[2]))) +#else + if (tmps2 = fbminstr(Null(unsigned char*),Null(unsigned char*),Nullstr)) +#endif + value = (double)(-1 + arybase); + else + value = (double)(tmps2 - tmps + arybase); + goto donumset; + case O_RINDEX: + tmps = str_get(st[1]); + tmps2 = str_get(st[2]); +#ifndef lint + if (!(tmps2 = rninstr(tmps, tmps + st[1]->str_cur, + tmps2, tmps2 + st[2]->str_cur))) +#else + if (tmps2 = rninstr(Nullch,Nullch,Nullch,Nullch)) +#endif value = (double)(-1 + arybase); else value = (double)(tmps2 - tmps + arybase); goto donumset; case O_TIME: +#ifndef lint value = (double) time(Null(long*)); +#endif goto donumset; case O_TMS: - value = (double) do_tms(retary,sarg,&maxsarg,sargoff,cushion); - if (retary) { - sarg = *retary; /* they realloc it */ - goto array_return; - } - goto donumset; + sp = do_tms(str,gimme,arglast); + goto array_return; case O_LOCALTIME: - when = (long)str_gnum(sarg[1]); - value = (double)do_time(localtime(&when), - retary,sarg,&maxsarg,sargoff,cushion); - if (retary) { - sarg = *retary; /* they realloc it */ - goto array_return; - } - goto donumset; + if (maxarg < 1) + (void)time(&when); + else + when = (long)str_gnum(st[1]); + sp = do_time(str,localtime(&when), + gimme,arglast); + goto array_return; case O_GMTIME: - when = (long)str_gnum(sarg[1]); - value = (double)do_time(gmtime(&when), - retary,sarg,&maxsarg,sargoff,cushion); - if (retary) { - sarg = *retary; /* they realloc it */ - goto array_return; - } - goto donumset; + if (maxarg < 1) + (void)time(&when); + else + when = (long)str_gnum(st[1]); + sp = do_time(str,gmtime(&when), + gimme,arglast); + goto array_return; + case O_LSTAT: case O_STAT: - value = (double) do_stat(arg, - retary,sarg,&maxsarg,sargoff,cushion); - if (retary) { - sarg = *retary; /* they realloc it */ - goto array_return; - } - goto donumset; + sp = do_stat(str,arg, + gimme,arglast); + goto array_return; case O_CRYPT: #ifdef CRYPT - tmps = str_get(sarg[1]); - str_set(str,crypt(tmps,str_get(sarg[2]))); + tmps = str_get(st[1]); +#ifdef FCRYPT + str_set(str,fcrypt(tmps,str_get(st[2]))); +#else + str_set(str,crypt(tmps,str_get(st[2]))); +#endif #else fatal( "The crypt() function is unimplemented due to excessive paranoia."); #endif break; + case O_ATAN2: + value = str_gnum(st[1]); + value = atan2(value,str_gnum(st[2])); + goto donumset; + case O_SIN: + if (maxarg < 1) + value = str_gnum(stab_val(defstab)); + else + value = str_gnum(st[1]); + value = sin(value); + goto donumset; + case O_COS: + if (maxarg < 1) + value = str_gnum(stab_val(defstab)); + else + value = str_gnum(st[1]); + value = cos(value); + goto donumset; + case O_RAND: + if (maxarg < 1) + value = 1.0; + else + value = str_gnum(st[1]); + if (value == 0.0) + value = 1.0; +#if RANDBITS == 31 + value = rand() * value / 2147483648.0; +#else +#if RANDBITS == 16 + value = rand() * value / 65536.0; +#else +#if RANDBITS == 15 + value = rand() * value / 32768.0; +#else + value = rand() * value / (double)(((unsigned long)1) << RANDBITS); +#endif +#endif +#endif + goto donumset; + case O_SRAND: + if (maxarg < 1) { + (void)time(&when); + anum = when; + } + else + anum = (int)str_gnum(st[1]); + (void)srand(anum); + goto say_yes; case O_EXP: - value = exp(str_gnum(sarg[1])); + if (maxarg < 1) + value = str_gnum(stab_val(defstab)); + else + value = str_gnum(st[1]); + value = exp(value); goto donumset; case O_LOG: - value = log(str_gnum(sarg[1])); + if (maxarg < 1) + value = str_gnum(stab_val(defstab)); + else + value = str_gnum(st[1]); + value = log(value); goto donumset; case O_SQRT: - value = sqrt(str_gnum(sarg[1])); + if (maxarg < 1) + value = str_gnum(stab_val(defstab)); + else + value = str_gnum(st[1]); + value = sqrt(value); goto donumset; case O_INT: - value = str_gnum(sarg[1]); + if (maxarg < 1) + value = str_gnum(stab_val(defstab)); + else + value = str_gnum(st[1]); if (value >= 0.0) - modf(value,&value); + (void)modf(value,&value); else { - modf(-value,&value); + (void)modf(-value,&value); value = -value; } goto donumset; case O_ORD: - value = (double) *str_get(sarg[1]); + if (maxarg < 1) + tmps = str_get(stab_val(defstab)); + else + tmps = str_get(st[1]); +#ifndef I286 + value = (double) *tmps; +#else + anum = (int) *tmps; + value = (double) anum; +#endif goto donumset; case O_SLEEP: - tmps = str_get(sarg[1]); - time(&when); + if (maxarg < 1) + tmps = Nullch; + else + tmps = str_get(st[1]); + (void)time(&when); if (!tmps || !*tmps) sleep((32767<<16)+32767); else - sleep((unsigned)atoi(tmps)); + sleep((unsigned int)atoi(tmps)); +#ifndef lint value = (double)when; - time(&when); + (void)time(&when); value = ((double)when) - value; +#endif goto donumset; + case O_RANGE: + sp = do_range(gimme,arglast); + goto array_return; + case O_F_OR_R: + if (gimme == G_ARRAY) { /* it's a range */ + /* can we optimize to constant array? */ + if ((arg[1].arg_type & A_MASK) == A_SINGLE && + (arg[2].arg_type & A_MASK) == A_SINGLE) { + st[2] = arg[2].arg_ptr.arg_str; + sp = do_range(gimme,arglast); + st = stack->ary_array; + maxarg = sp - arglast[0]; + str_free(arg[1].arg_ptr.arg_str); + str_free(arg[2].arg_ptr.arg_str); + arg->arg_type = O_ARRAY; + arg[1].arg_type = A_STAB|A_DONT; + arg->arg_len = 1; + stab = arg[1].arg_ptr.arg_stab = aadd(genstab()); + ary = stab_array(stab); + afill(ary,maxarg - 1); + st += arglast[0]+1; + while (maxarg-- > 0) + ary->ary_array[maxarg] = str_smake(st[maxarg]); + goto array_return; + } + arg->arg_type = optype = O_RANGE; + maxarg = arg->arg_len = 2; + anum = 2; + arg[anum].arg_flags &= ~AF_ARYOK; + argflags = arg[anum].arg_flags; + argtype = arg[anum].arg_type & A_MASK; + arg[anum].arg_type = argtype; + argptr = arg[anum].arg_ptr; + sp = arglast[0]; + st -= sp; + sp++; + goto re_eval; + } + arg->arg_type = O_FLIP; + /* FALL THROUGH */ case O_FLIP: - if (str_true(sarg[1])) { + if ((arg[1].arg_type & A_MASK) == A_SINGLE ? + last_in_stab && (int)str_gnum(st[1]) == stab_io(last_in_stab)->lines + : + str_true(st[1]) ) { str_numset(str,0.0); anum = 2; arg->arg_type = optype = O_FLOP; - arg[2].arg_flags &= ~AF_SPECIAL; - arg[1].arg_flags |= AF_SPECIAL; + arg[2].arg_type &= ~A_DONT; + arg[1].arg_type |= A_DONT; argflags = arg[2].arg_flags; - argtype = arg[2].arg_type; + argtype = arg[2].arg_type & A_MASK; argptr = arg[2].arg_ptr; + sp = arglast[0]; + st -= sp; goto re_eval; } str_set(str,""); break; case O_FLOP: str_inc(str); - if (str_true(sarg[2])) { + if ((arg[2].arg_type & A_MASK) == A_SINGLE ? + last_in_stab && (int)str_gnum(st[2]) == stab_io(last_in_stab)->lines + : + str_true(st[2]) ) { arg->arg_type = O_FLIP; - arg[1].arg_flags &= ~AF_SPECIAL; - arg[2].arg_flags |= AF_SPECIAL; + arg[1].arg_type &= ~A_DONT; + arg[2].arg_type |= A_DONT; str_cat(str,"E0"); } break; case O_FORK: - value = (double)fork(); + anum = fork(); + if (!anum && (tmpstab = stabent("$",allstabs))) + str_numset(STAB_STR(tmpstab),(double)getpid()); + value = (double)anum; goto donumset; case O_WAIT: +#ifndef lint ihand = signal(SIGINT, SIG_IGN); qhand = signal(SIGQUIT, SIG_IGN); - value = (double)wait(&argflags); - signal(SIGINT, ihand); - signal(SIGQUIT, qhand); + anum = wait(&argflags); + if (anum > 0) + pidgone(anum,argflags); + value = (double)anum; +#else + ihand = qhand = 0; +#endif + (void)signal(SIGINT, ihand); + (void)signal(SIGQUIT, qhand); statusvalue = (unsigned short)argflags; goto donumset; case O_SYSTEM: +#ifdef TAINT + if (arglast[2] - arglast[1] == 1) { + taintenv(); + tainted |= st[2]->str_tainted; + taintproper("Insecure dependency in system"); + } +#endif while ((anum = vfork()) == -1) { if (errno != EAGAIN) { value = -1.0; @@ -1062,12 +1320,16 @@ int sargoff; /* how many elements in sarg are already assigned */ sleep(5); } if (anum > 0) { +#ifndef lint ihand = signal(SIGINT, SIG_IGN); qhand = signal(SIGQUIT, SIG_IGN); - while ((argtype = wait(&argflags)) != anum && argtype != -1) - ; - signal(SIGINT, ihand); - signal(SIGQUIT, qhand); + while ((argtype = wait(&argflags)) != anum && argtype >= 0) + pidgone(argtype,argflags); +#else + ihand = qhand = 0; +#endif + (void)signal(SIGINT, ihand); + (void)signal(SIGQUIT, qhand); statusvalue = (unsigned short)argflags; if (argtype == -1) value = -1.0; @@ -1076,17 +1338,21 @@ int sargoff; /* how many elements in sarg are already assigned */ } goto donumset; } - if (arg[1].arg_flags & AF_SPECIAL) - value = (double)do_aexec(arg); + if ((arg[1].arg_type & A_MASK) == A_STAB) + value = (double)do_aexec(st[1],arglast); + else if (arglast[2] - arglast[1] != 1) + value = (double)do_aexec(Nullstr,arglast); else { - value = (double)do_exec(str_static(sarg[1])); + value = (double)do_exec(str_get(str_static(st[2]))); } _exit(-1); case O_EXEC: - if (arg[1].arg_flags & AF_SPECIAL) - value = (double)do_aexec(arg); + if ((arg[1].arg_type & A_MASK) == A_STAB) + value = (double)do_aexec(st[1],arglast); + else if (arglast[2] - arglast[1] != 1) + value = (double)do_aexec(Nullstr,arglast); else { - value = (double)do_exec(str_static(sarg[1])); + value = (double)do_exec(str_get(str_static(st[2]))); } goto donumset; case O_HEX: @@ -1098,7 +1364,10 @@ int sargoff; /* how many elements in sarg are already assigned */ snarfnum: anum = 0; - tmps = str_get(sarg[1]); + if (maxarg < 1) + tmps = str_get(stab_val(defstab)); + else + tmps = str_get(st[1]); for (;;) { switch (*tmps) { default: @@ -1133,53 +1402,222 @@ int sargoff; /* how many elements in sarg are already assigned */ case O_KILL: case O_UNLINK: case O_UTIME: - if (arg[1].arg_flags & AF_SPECIAL) - value = (double)apply(optype,arg,Null(STR**)); - else { - sarg[2] = Nullstr; - value = (double)apply(optype,arg,sarg); - } + value = (double)apply(optype,arglast); goto donumset; case O_UMASK: - value = (double)umask((int)str_gnum(sarg[1])); + if (maxarg < 1) { + anum = umask(0); + (void)umask(anum); + } + else + anum = umask((int)str_gnum(st[1])); + value = (double)anum; +#ifdef TAINT + taintproper("Insecure dependency in umask"); +#endif goto donumset; case O_RENAME: - tmps = str_get(sarg[1]); + tmps = str_get(st[1]); + tmps2 = str_get(st[2]); +#ifdef TAINT + taintproper("Insecure dependency in rename"); +#endif #ifdef RENAME - value = (double)(rename(tmps,str_get(sarg[2])) >= 0); + value = (double)(rename(tmps,tmps2) >= 0); #else - tmps2 = str_get(sarg[2]); if (euid || stat(tmps2,&statbuf) < 0 || (statbuf.st_mode & S_IFMT) != S_IFDIR ) - UNLINK(tmps2); /* avoid unlinking a directory */ + (void)UNLINK(tmps2); /* avoid unlinking a directory */ if (!(anum = link(tmps,tmps2))) anum = UNLINK(tmps); value = (double)(anum >= 0); #endif goto donumset; case O_LINK: - tmps = str_get(sarg[1]); - value = (double)(link(tmps,str_get(sarg[2])) >= 0); + tmps = str_get(st[1]); + tmps2 = str_get(st[2]); +#ifdef TAINT + taintproper("Insecure dependency in link"); +#endif + value = (double)(link(tmps,tmps2) >= 0); goto donumset; + case O_MKDIR: + tmps = str_get(st[1]); + anum = (int)str_gnum(st[2]); +#ifdef TAINT + taintproper("Insecure dependency in mkdir"); +#endif +#ifdef MKDIR + value = (double)(mkdir(tmps,anum) >= 0); +#else + (void)sprintf(buf,"mkdir %s 2>&1",tmps); + one_liner: + rsfp = mypopen(buf,"r"); + if (rsfp) { + *buf = '\0'; + tmps2 = fgets(buf,sizeof buf,rsfp); + (void)mypclose(rsfp); + if (tmps2 != Nullch) { + for (errno = 1; errno <= sys_nerr; errno++) { + if (instr(buf,sys_errlist[errno])) /* you don't see this */ + goto say_zero; + } + errno = 0; + goto say_zero; + } + else + value = 1.0; + } + else + goto say_zero; +#endif + goto donumset; + case O_RMDIR: + if (maxarg < 1) + tmps = str_get(stab_val(defstab)); + else + tmps = str_get(st[1]); +#ifdef TAINT + taintproper("Insecure dependency in rmdir"); +#endif +#ifdef RMDIR + value = (double)(rmdir(tmps) >= 0); + goto donumset; +#else + (void)sprintf(buf,"rmdir %s 2>&1",tmps); + goto one_liner; /* see above in MKDIR */ +#endif + case O_GETPPID: + value = (double)getppid(); + goto donumset; + case O_GETPGRP: +#ifdef GETPGRP + if (maxarg < 1) + anum = 0; + else + anum = (int)str_gnum(st[1]); + value = (double)getpgrp(anum); + goto donumset; +#else + fatal("The getpgrp() function is unimplemented on this machine"); + break; +#endif + case O_SETPGRP: +#ifdef SETPGRP + argtype = (int)str_gnum(st[1]); + anum = (int)str_gnum(st[2]); +#ifdef TAINT + taintproper("Insecure dependency in setpgrp"); +#endif + value = (double)(setpgrp(argtype,anum) >= 0); + goto donumset; +#else + fatal("The setpgrp() function is unimplemented on this machine"); + break; +#endif + case O_GETPRIORITY: +#ifdef GETPRIORITY + argtype = (int)str_gnum(st[1]); + anum = (int)str_gnum(st[2]); + value = (double)getpriority(argtype,anum); + goto donumset; +#else + fatal("The getpriority() function is unimplemented on this machine"); + break; +#endif + case O_SETPRIORITY: +#ifdef SETPRIORITY + argtype = (int)str_gnum(st[1]); + anum = (int)str_gnum(st[2]); + optype = (int)str_gnum(st[3]); +#ifdef TAINT + taintproper("Insecure dependency in setpriority"); +#endif + value = (double)(setpriority(argtype,anum,optype) >= 0); + goto donumset; +#else + fatal("The setpriority() function is unimplemented on this machine"); + break; +#endif + case O_CHROOT: + if (maxarg < 1) + tmps = str_get(stab_val(defstab)); + else + tmps = str_get(st[1]); +#ifdef TAINT + taintproper("Insecure dependency in chroot"); +#endif + value = (double)(chroot(tmps) >= 0); + goto donumset; + case O_FCNTL: + case O_IOCTL: + if (maxarg <= 0) + stab = last_in_stab; + else if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + argtype = (int)str_gnum(st[2]); +#ifdef TAINT + taintproper("Insecure dependency in ioctl"); +#endif + anum = do_ctl(optype,stab,argtype,st[3]); + if (anum == -1) + goto say_undef; + if (anum != 0) + goto donumset; + str_set(str,"0 but true"); + STABSET(str); + break; + case O_FLOCK: +#ifdef FLOCK + if (maxarg <= 0) + stab = last_in_stab; + else if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + if (stab && stab_io(stab)) + fp = stab_io(stab)->ifp; + else + fp = Nullfp; + if (fp) { + argtype = (int)str_gnum(st[2]); + value = (double)(flock(fileno(fp),argtype) >= 0); + } + else + value = 0; + goto donumset; +#else + fatal("The flock() function is unimplemented on this machine"); + break; +#endif case O_UNSHIFT: - ary = arg[2].arg_ptr.arg_stab->stab_array; - if (arg[1].arg_flags & AF_SPECIAL) - do_unshift(arg,ary); + ary = stab_array(arg[1].arg_ptr.arg_stab); + if (arglast[2] - arglast[1] != 1) + do_unshift(ary,arglast); else { - str = str_new(0); /* must copy the STR */ - str_sset(str,sarg[1]); + str = Str_new(52,0); /* must copy the STR */ + str_sset(str,st[2]); aunshift(ary,1); - astore(ary,0,str); + (void)astore(ary,0,str); } value = (double)(ary->ary_fill + 1); break; case O_DOFILE: case O_EVAL: - str_sset(str, - do_eval(arg[1].arg_type != A_NULL ? sarg[1] : defstab->stab_val, - optype) ); - STABSET(str); - break; + if (maxarg < 1) + tmpstr = stab_val(defstab); + else + tmpstr = + (arg[1].arg_type & A_MASK) != A_NULL ? st[1] : stab_val(defstab); +#ifdef TAINT + tainted |= tmpstr->str_tainted; + taintproper("Insecure dependency in eval"); +#endif + sp = do_eval(tmpstr, optype, arg[2].arg_ptr.arg_hash, + gimme,arglast); + goto array_return; case O_FTRREAD: argtype = 0; @@ -1205,47 +1643,42 @@ int sargoff; /* how many elements in sarg are already assigned */ argtype = 1; anum = S_IEXEC; check_perm: - str = &str_no; - if (mystat(arg,sarg[1]) < 0) - break; - if (cando(anum,argtype)) - str = &str_yes; - break; + if (mystat(arg,st[1]) < 0) + goto say_undef; + if (cando(anum,argtype,&statcache)) + goto say_yes; + goto say_no; case O_FTIS: - if (mystat(arg,sarg[1]) >= 0) - str = &str_yes; - else - str = &str_no; - break; + if (mystat(arg,st[1]) < 0) + goto say_undef; + goto say_yes; case O_FTEOWNED: case O_FTROWNED: - if (mystat(arg,sarg[1]) >= 0 && - statbuf.st_uid == (optype == O_FTEOWNED ? euid : uid) ) - str = &str_yes; - else - str = &str_no; - break; + if (mystat(arg,st[1]) < 0) + goto say_undef; + if (statcache.st_uid == (optype == O_FTEOWNED ? euid : uid) ) + goto say_yes; + goto say_no; case O_FTZERO: - if (mystat(arg,sarg[1]) >= 0 && !statbuf.st_size) - str = &str_yes; - else - str = &str_no; - break; + if (mystat(arg,st[1]) < 0) + goto say_undef; + if (!statcache.st_size) + goto say_yes; + goto say_no; case O_FTSIZE: - if (mystat(arg,sarg[1]) >= 0 && statbuf.st_size) - str = &str_yes; - else - str = &str_no; - break; + if (mystat(arg,st[1]) < 0) + goto say_undef; + if (statcache.st_size) + goto say_yes; + goto say_no; case O_FTSOCK: #ifdef S_IFSOCK anum = S_IFSOCK; goto check_file_type; #else - str = &str_no; - break; + goto say_no; #endif case O_FTCHR: anum = S_IFCHR; @@ -1259,37 +1692,52 @@ int sargoff; /* how many elements in sarg are already assigned */ case O_FTDIR: anum = S_IFDIR; check_file_type: - if (mystat(arg,sarg[1]) >= 0 && - (statbuf.st_mode & S_IFMT) == anum ) - str = &str_yes; - else - str = &str_no; - break; + if (mystat(arg,st[1]) < 0) + goto say_undef; + if ((statcache.st_mode & S_IFMT) == anum ) + goto say_yes; + goto say_no; case O_FTPIPE: #ifdef S_IFIFO anum = S_IFIFO; goto check_file_type; #else - str = &str_no; - break; + goto say_no; #endif case O_FTLINK: -#ifdef S_IFLNK - if (lstat(str_get(sarg[1]),&statbuf) >= 0 && - (statbuf.st_mode & S_IFMT) == S_IFLNK ) - str = &str_yes; - else +#ifdef SYMLINK + if (lstat(str_get(st[1]),&statcache) < 0) + goto say_undef; + if ((statcache.st_mode & S_IFMT) == S_IFLNK ) + goto say_yes; #endif - str = &str_no; - break; + goto say_no; case O_SYMLINK: #ifdef SYMLINK - tmps = str_get(sarg[1]); - value = (double)(symlink(tmps,str_get(sarg[2])) >= 0); + tmps = str_get(st[1]); + tmps2 = str_get(st[2]); +#ifdef TAINT + taintproper("Insecure dependency in symlink"); +#endif + value = (double)(symlink(tmps,tmps2) >= 0); goto donumset; #else fatal("Unsupported function symlink()"); #endif + case O_READLINK: +#ifdef SYMLINK + if (maxarg < 1) + tmps = str_get(stab_val(defstab)); + else + tmps = str_get(st[1]); + anum = readlink(tmps,buf,sizeof buf); + if (anum < 0) + goto say_undef; + str_nset(str,buf,anum); + break; +#else + fatal("Unsupported function readlink()"); +#endif case O_FTSUID: anum = S_ISUID; goto check_xid; @@ -1299,38 +1747,286 @@ int sargoff; /* how many elements in sarg are already assigned */ case O_FTSVTX: anum = S_ISVTX; check_xid: - if (mystat(arg,sarg[1]) >= 0 && statbuf.st_mode & anum) - str = &str_yes; - else - str = &str_no; - break; + if (mystat(arg,st[1]) < 0) + goto say_undef; + if (statcache.st_mode & anum) + goto say_yes; + goto say_no; case O_FTTTY: - if (arg[1].arg_flags & AF_SPECIAL) { + if (arg[1].arg_type & A_DONT) { stab = arg[1].arg_ptr.arg_stab; tmps = ""; } else - stab = stabent(tmps = str_get(sarg[1]),FALSE); - if (stab && stab->stab_io && stab->stab_io->fp) - anum = fileno(stab->stab_io->fp); + stab = stabent(tmps = str_get(st[1]),FALSE); + if (stab && stab_io(stab) && stab_io(stab)->ifp) + anum = fileno(stab_io(stab)->ifp); else if (isdigit(*tmps)) anum = atoi(tmps); else - anum = -1; + goto say_undef; if (isatty(anum)) - str = &str_yes; - else - str = &str_no; - break; + goto say_yes; + goto say_no; case O_FTTEXT: case O_FTBINARY: - str = do_fttext(arg,sarg[1]); + str = do_fttext(arg,st[1]); break; +#ifdef SOCKET + case O_SOCKET: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); +#ifndef lint + value = (double)do_socket(stab,arglast); +#else + (void)do_socket(stab,arglast); +#endif + goto donumset; + case O_BIND: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); +#ifndef lint + value = (double)do_bind(stab,arglast); +#else + (void)do_bind(stab,arglast); +#endif + goto donumset; + case O_CONNECT: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); +#ifndef lint + value = (double)do_connect(stab,arglast); +#else + (void)do_connect(stab,arglast); +#endif + goto donumset; + case O_LISTEN: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); +#ifndef lint + value = (double)do_listen(stab,arglast); +#else + (void)do_listen(stab,arglast); +#endif + goto donumset; + case O_ACCEPT: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + if ((arg[2].arg_type & A_MASK) == A_WORD) + stab2 = arg[2].arg_ptr.arg_stab; + else + stab2 = stabent(str_get(st[2]),TRUE); + do_accept(str,stab,stab2); + STABSET(str); + break; + case O_GHBYNAME: + if (maxarg < 1) + goto say_undef; + case O_GHBYADDR: + case O_GHOSTENT: + sp = do_ghent(optype, + gimme,arglast); + goto array_return; + case O_GNBYNAME: + if (maxarg < 1) + goto say_undef; + case O_GNBYADDR: + case O_GNETENT: + sp = do_gnent(optype, + gimme,arglast); + goto array_return; + case O_GPBYNAME: + if (maxarg < 1) + goto say_undef; + case O_GPBYNUMBER: + case O_GPROTOENT: + sp = do_gpent(optype, + gimme,arglast); + goto array_return; + case O_GSBYNAME: + if (maxarg < 1) + goto say_undef; + case O_GSBYPORT: + case O_GSERVENT: + sp = do_gsent(optype, + gimme,arglast); + goto array_return; + case O_SHOSTENT: + value = (double) sethostent((int)str_gnum(st[1])); + goto donumset; + case O_SNETENT: + value = (double) setnetent((int)str_gnum(st[1])); + goto donumset; + case O_SPROTOENT: + value = (double) setprotoent((int)str_gnum(st[1])); + goto donumset; + case O_SSERVENT: + value = (double) setservent((int)str_gnum(st[1])); + goto donumset; + case O_EHOSTENT: + value = (double) endhostent(); + goto donumset; + case O_ENETENT: + value = (double) endnetent(); + goto donumset; + case O_EPROTOENT: + value = (double) endprotoent(); + goto donumset; + case O_ESERVENT: + value = (double) endservent(); + goto donumset; + case O_SSELECT: + sp = do_select(gimme,arglast); + goto array_return; + case O_SOCKETPAIR: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + if ((arg[2].arg_type & A_MASK) == A_WORD) + stab2 = arg[2].arg_ptr.arg_stab; + else + stab2 = stabent(str_get(st[2]),TRUE); +#ifndef lint + value = (double)do_spair(stab,stab2,arglast); +#else + (void)do_spair(stab,stab2,arglast); +#endif + goto donumset; + case O_SHUTDOWN: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); +#ifndef lint + value = (double)do_shutdown(stab,arglast); +#else + (void)do_shutdown(stab,arglast); +#endif + goto donumset; + case O_GSOCKOPT: + case O_SSOCKOPT: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + sp = do_sopt(optype,stab,arglast); + goto array_return; + case O_GETSOCKNAME: + case O_GETPEERNAME: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + sp = do_getsockname(optype,stab,arglast); + goto array_return; + +#else /* SOCKET not defined */ + case O_SOCKET: + case O_BIND: + case O_CONNECT: + case O_LISTEN: + case O_ACCEPT: + case O_SSELECT: + case O_SOCKETPAIR: + case O_GHBYNAME: + case O_GHBYADDR: + case O_GHOSTENT: + case O_GNBYNAME: + case O_GNBYADDR: + case O_GNETENT: + case O_GPBYNAME: + case O_GPBYNUMBER: + case O_GPROTOENT: + case O_GSBYNAME: + case O_GSBYPORT: + case O_GSERVENT: + case O_SHOSTENT: + case O_SNETENT: + case O_SPROTOENT: + case O_SSERVENT: + case O_EHOSTENT: + case O_ENETENT: + case O_EPROTOENT: + case O_ESERVENT: + case O_SHUTDOWN: + case O_GSOCKOPT: + case O_SSOCKOPT: + case O_GETSOCKNAME: + case O_GETPEERNAME: + badsock: + fatal("Unsupported socket function"); +#endif /* SOCKET */ + case O_FILENO: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + if (!stab || !(stio = stab_io(stab)) || !(fp = stio->ifp)) + goto say_undef; + value = fileno(fp); + goto donumset; + case O_VEC: + sp = do_vec(str == st[1], arg->arg_ptr.arg_str, arglast); + goto array_return; + case O_GPWNAM: + case O_GPWUID: + case O_GPWENT: + sp = do_gpwent(optype, + gimme,arglast); + goto array_return; + case O_SPWENT: + value = (double) setpwent(); + goto donumset; + case O_EPWENT: + value = (double) endpwent(); + goto donumset; + case O_GGRNAM: + case O_GGRGID: + case O_GGRENT: + sp = do_ggrent(optype, + gimme,arglast); + goto array_return; + case O_SGRENT: + value = (double) setgrent(); + goto donumset; + case O_EGRENT: + value = (double) endgrent(); + goto donumset; + case O_GETLOGIN: + if (!(tmps = getlogin())) + goto say_undef; + str_set(str,tmps); + break; + case O_OPENDIR: + case O_READDIR: + case O_TELLDIR: + case O_SEEKDIR: + case O_REWINDDIR: + case O_CLOSEDIR: + if ((arg[1].arg_type & A_MASK) == A_WORD) + stab = arg[1].arg_ptr.arg_stab; + else + stab = stabent(str_get(st[1]),TRUE); + sp = do_dirop(optype,stab,gimme,arglast); + goto array_return; + case O_SYSCALL: + value = (double)do_syscall(arglast); + goto donumset; } - if (retary) { - sarg[1] = str; - maxsarg = sargoff + 1; - } + + normal_return: + st[1] = str; #ifdef DEBUGGING if (debug) { dlevel--; @@ -1338,25 +2034,38 @@ int sargoff; /* how many elements in sarg are already assigned */ deb("%s RETURNS \"%s\"\n",opname[optype],str_get(str)); } #endif - goto freeargs; + return arglast[0] + 1; array_return: #ifdef DEBUGGING if (debug) { dlevel--; if (debug & 8) - deb("%s RETURNS ARRAY OF %d ARGS\n",opname[optype],maxsarg-sargoff); + deb("%s RETURNS ARRAY OF %d ARGS\n",opname[optype],sp - arglast[0]); } #endif - goto freeargs; + return sp; + +say_yes: + str = &str_yes; + goto normal_return; + +say_no: + str = &str_no; + goto normal_return; + +say_undef: + str = &str_undef; + goto normal_return; + +say_zero: + value = 0.0; + /* FALL THROUGH */ donumset: str_numset(str,value); STABSET(str); - if (retary) { - sarg[1] = str; - maxsarg = sargoff + 1; - } + st[1] = str; #ifdef DEBUGGING if (debug) { dlevel--; @@ -1364,72 +2073,5 @@ donumset: deb("%s RETURNS \"%f\"\n",opname[optype],value); } #endif - -freeargs: - sarg -= sargoff; - if (sarg != quicksarg) { - if (retary) { - sarg[0] = &str_args; - str_numset(sarg[0], (double)(maxsarg)); - sarg[maxsarg+1] = Nullstr; - *retary = sarg; /* up to them to free it */ - } - else - safefree((char*)sarg); - } - return str; -} - -int -ingroup(gid,effective) -int gid; -int effective; -{ - if (gid == (effective ? getegid() : getgid())) - return TRUE; -#ifdef GETGROUPS -#ifndef NGROUPS -#define NGROUPS 32 -#endif - { - GIDTYPE gary[NGROUPS]; - int anum; - - anum = getgroups(NGROUPS,gary); - while (--anum >= 0) - if (gary[anum] == gid) - return TRUE; - } -#endif - return FALSE; -} - -/* Do the permissions allow some operation? Assumes statbuf already set. */ - -int -cando(bit, effective) -int bit; -int effective; -{ - if ((effective ? euid : uid) == 0) { /* root is special */ - if (bit == S_IEXEC) { - if (statbuf.st_mode & 0111 || - (statbuf.st_mode & S_IFMT) == S_IFDIR ) - return TRUE; - } - else - return TRUE; /* root reads and writes anything */ - return FALSE; - } - if (statbuf.st_uid == (effective ? euid : uid) ) { - if (statbuf.st_mode & bit) - return TRUE; /* ok as "user" */ - } - else if (ingroup((int)statbuf.st_gid,effective)) { - if (statbuf.st_mode & bit >> 3) - return TRUE; /* ok as "group" */ - } - else if (statbuf.st_mode & bit >> 6) - return TRUE; /* ok as "other" */ - return FALSE; + return arglast[0] + 1; } |