[alt.sources] perl 3.0 beta kit 5/23

lwall@jato.Jpl.Nasa.Gov (Larry Wall) (09/03/89)

#! /bin/sh

# Make a new directory for the perl sources, cd to it, and run kits 1
# thru 23 through sh.  When all 23 kits have been run, read README.

echo "This is perl 3.0 kit 5 (of 23).  If kit 5 is complete, the line"
echo '"'"End of kit 5 (of 23)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir t 2>/dev/null
echo Extracting eval.c
sed >eval.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: eval.c,v 2.0.1.8 88/11/18 23:54:42 lwall Locked $
X *
X *    Copyright (c) 1989, Larry Wall
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the perl 3.0 kit.
X *
X * $Log:	eval.c,v $
X */
X
X#include "EXTERN.h"
X#include "perl.h"
X
X#include <signal.h>
X#include <errno.h>
X
Xextern int errno;
X
X#ifdef VOIDSIG
Xstatic void (*ihand)();
Xstatic void (*qhand)();
X#else
Xstatic int (*ihand)();
Xstatic int (*qhand)();
X#endif
X
XARG *debarg;
XSTR str_args;
Xstatic STAB *stab2;
Xstatic STIO *stio;
Xstatic struct lstring *lstr;
Xstatic char old_record_separator;
X
Xdouble sin(), cos(), atan2(), pow();
X
Xextern int sys_nerr;
Xextern char *sys_errlist[];
X
Xint
Xeval(arg,gimme,sp)
Xregister ARG *arg;
Xint gimme;
Xregister int sp;
X{
X    register STR *str;
X    register int anum;
X    register int optype;
X    register STR **st;
X    int maxarg;
X    double value;
X    register char *tmps;
X    char *tmps2;
X    int argflags;
X    int argtype;
X    union argptr argptr;
X    int arglast[8];	/* highest sp for arg--valid only for non-O_LIST args */
X    unsigned long tmplong;
X    long when;
X    FILE *fp;
X    STR *tmpstr;
X    FCMD *form;
X    STAB *stab;
X    ARRAY *ary;
X    bool assigning = FALSE;
X    double exp(), log(), sqrt(), modf();
X    char *crypt(), *getenv();
X
X    if (!arg)
X	goto say_undef;
X    optype = arg->arg_type;
X    maxarg = arg->arg_len;
X    arglast[0] = sp;
X    str = arg->arg_ptr.arg_str;
X    if (sp + maxarg > stack->ary_max)
X	astore(stack, sp + maxarg, Nullstr);
X    st = stack->ary_array;
X
X#ifdef DEBUGGING
X    if (debug) {
X	if (debug & 8) {
X	    deb("%s (%lx) %d args:\n",opname[optype],arg,maxarg);
X	}
X	debname[dlevel] = opname[optype][0];
X	debdelim[dlevel++] = ':';
X    }
X#endif
X
X#include "evalargs.xc";
X
X    st += arglast[0];
X    switch (optype) {
X    case O_RCAT:
X	STABSET(str);
X	break;
X    case O_ITEM:
X	if (gimme == G_ARRAY)
X	    goto array_return;
X	STR_SSET(str,st[1]);
X	STABSET(str);
X	break;
X    case O_ITEM2:
X	if (gimme == G_ARRAY)
X	    goto array_return;
X	--anum;
X	STR_SSET(str,st[arglast[anum]-arglast[0]]);
X	STABSET(str);
X	break;
X    case O_ITEM3:
X	if (gimme == G_ARRAY)
X	goto array_return;
X	--anum;
X	STR_SSET(str,st[arglast[anum]-arglast[0]]);
X	STABSET(str);
X	break;
X    case O_CONCAT:
X	STR_SSET(str,st[1]);
X	str_scat(str,st[2]);
X	STABSET(str);
X	break;
X    case O_REPEAT:
X	STR_SSET(str,st[1]);
X	anum = (int)str_gnum(st[2]);
X	if (anum >= 1) {
X	    tmpstr = str_new(0);
X	    str_sset(tmpstr,str);
X	    while (--anum > 0)
X		str_scat(str,tmpstr);
X	}
X	else
X	    str_sset(str,&str_no);
X	STABSET(str);
X	break;
X    case O_MATCH:
X	sp = do_match(str,arg,
X	  gimme,arglast);
X	if (gimme == G_ARRAY)
X	    goto array_return;
X	STABSET(str);
X	break;
X    case O_NMATCH:
X	sp = do_match(str,arg,
X	  gimme,arglast);
X	if (gimme == G_ARRAY)
X	    goto array_return;
X	str_sset(str, str_true(str) ? &str_no : &str_yes);
X	STABSET(str);
X	break;
X    case O_SUBST:
X	sp = do_subst(str,arg,sp);
X	goto array_return;
X    case O_NSUBST:
X	sp = do_subst(str,arg,sp);
X	str = arg->arg_ptr.arg_str;
X	str_set(str, str_true(str) ? No : Yes);
X	goto array_return;
X    case O_ASSIGN:
X	if (arg[1].arg_flags & AF_ARYOK) {
X	    if (arg->arg_len == 1) {
X		arg->arg_type = O_LOCAL;
X		arg->arg_flags |= AF_LOCAL;
X		goto local;
X	    }
X	    else {
X		arg->arg_type = O_AASSIGN;
X		goto aassign;
X	    }
X	}
X	else {
X	    arg->arg_type = O_SASSIGN;
X	    goto sassign;
X	}
X    case O_LOCAL:
X      local:
X	arglast[2] = arglast[1];	/* push a null array */
X	/* FALL THROUGH */
X    case O_AASSIGN:
X      aassign:
X	sp = do_assign(arg,
X	  gimme,arglast);
X	goto array_return;
X    case O_SASSIGN:
X      sassign:
X	STR_SSET(str, st[2]);
X	STABSET(str);
X	break;
X    case O_CHOP:
X	st -= arglast[0];
X	str = arg->arg_ptr.arg_str;
X	for (sp = arglast[0] + 1; sp <= arglast[1]; sp++)
X	    do_chop(str,st[sp]);
X	break;
X    case O_DEFINED:
X	if (arg[1].arg_type & A_DONT) {
X	    sp = do_defined(str,arg,
X		  gimme,arglast);
X	    goto array_return;
X	}
X	else if (str->str_pok || str->str_nok)
X	    goto say_yes;
X	goto say_no;
X    case O_UNDEF:
X	if (arg[1].arg_type & A_DONT) {
X	    sp = do_undef(str,arg,
X	      gimme,arglast);
X	    goto array_return;
X	}
X	else if (str != stab_val(defstab)) {
X	    str->str_pok = str->str_nok = 0;
X	    STABSET(str);
X	}
X	goto say_undef;
X    case O_STUDY:
X	sp = do_study(str,arg,
X	  gimme,arglast);
X	goto array_return;
X    case O_POW:
X	value = str_gnum(st[1]);
X	value = pow(value,str_gnum(st[2]));
X	goto donumset;
X    case O_MULTIPLY:
X	value = str_gnum(st[1]);
X	value *= str_gnum(st[2]);
X	goto donumset;
X    case O_DIVIDE:
X    	if ((value = str_gnum(st[2])) == 0.0)
X    	    fatal("Illegal division by zero");
X	value = str_gnum(st[1]) / value;
X	goto donumset;
X    case O_MODULO:
X	tmplong = (long) str_gnum(st[2]);
X    	if (tmplong == 0L)
X    	    fatal("Illegal modulus zero");
X	when = (long)str_gnum(st[1]);
X#ifndef lint
X	if (when >= 0)
X	    value = (double)(when % tmplong);
X	else
X	    value = (double)(tmplong - (-when % tmplong));
X#endif
X	goto donumset;
X    case O_ADD:
X	value = str_gnum(st[1]);
X	value += str_gnum(st[2]);
X	goto donumset;
X    case O_SUBTRACT:
X	value = str_gnum(st[1]);
X	value -= str_gnum(st[2]);
X	goto donumset;
X    case O_LEFT_SHIFT:
X	value = str_gnum(st[1]);
X	anum = (int)str_gnum(st[2]);
X#ifndef lint
X	value = (double)(((long)value) << anum);
X#endif
X	goto donumset;
X    case O_RIGHT_SHIFT:
X	value = str_gnum(st[1]);
X	anum = (int)str_gnum(st[2]);
X#ifndef lint
X	value = (double)(((long)value) >> anum);
X#endif
X	goto donumset;
X    case O_LT:
X	value = str_gnum(st[1]);
X	value = (value < str_gnum(st[2])) ? 1.0 : 0.0;
X	goto donumset;
X    case O_GT:
X	value = str_gnum(st[1]);
X	value = (value > str_gnum(st[2])) ? 1.0 : 0.0;
X	goto donumset;
X    case O_LE:
X	value = str_gnum(st[1]);
X	value = (value <= str_gnum(st[2])) ? 1.0 : 0.0;
X	goto donumset;
X    case O_GE:
X	value = str_gnum(st[1]);
X	value = (value >= str_gnum(st[2])) ? 1.0 : 0.0;
X	goto donumset;
X    case O_EQ:
X	if (dowarn) {
X	    if ((!st[1]->str_nok && !looks_like_number(st[1])) ||
X		(!st[2]->str_nok && !looks_like_number(st[2])) )
X		warn("Possible use of == on string value");
X	}
X	value = str_gnum(st[1]);
X	value = (value == str_gnum(st[2])) ? 1.0 : 0.0;
X	goto donumset;
X    case O_NE:
X	value = str_gnum(st[1]);
X	value = (value != str_gnum(st[2])) ? 1.0 : 0.0;
X	goto donumset;
X    case O_BIT_AND:
X	if (!sawvec || st[1]->str_nok || st[2]->str_nok) {
X	    value = str_gnum(st[1]);
X#ifndef lint
X	    value = (double)(((long)value) & (long)str_gnum(st[2]));
X#endif
X	    goto donumset;
X	}
X	else
X	    do_vop(optype,str,st[1],st[2]);
X	break;
X    case O_XOR:
X	if (!sawvec || st[1]->str_nok || st[2]->str_nok) {
X	    value = str_gnum(st[1]);
X#ifndef lint
X	    value = (double)(((long)value) ^ (long)str_gnum(st[2]));
X#endif
X	    goto donumset;
X	}
X	else
X	    do_vop(optype,str,st[1],st[2]);
X	break;
X    case O_BIT_OR:
X	if (!sawvec || st[1]->str_nok || st[2]->str_nok) {
X	    value = str_gnum(st[1]);
X#ifndef lint
X	    value = (double)(((long)value) | (long)str_gnum(st[2]));
X#endif
X	    goto donumset;
X	}
X	else
X	    do_vop(optype,str,st[1],st[2]);
X	break;
X/* use register in evaluating str_true() */
X    case O_AND:
X	if (str_true(st[1])) {
X	    anum = 2;
X	    optype = O_ITEM2;
X	    argflags = arg[anum].arg_flags;
X	    if (gimme == G_ARRAY)
X		argflags |= AF_ARYOK;
X	    argtype = arg[anum].arg_type & A_MASK;
X	    argptr = arg[anum].arg_ptr;
X	    maxarg = anum = 1;
X	    sp = arglast[0];
X	    st -= sp;
X	    goto re_eval;
X	}
X	else {
X	    if (assigning) {
X		str_sset(str, st[1]);
X		STABSET(str);
X	    }
X	    else
X		str = st[1];
X	    break;
X	}
X    case O_OR:
X	if (str_true(st[1])) {
X	    if (assigning) {
X		str_sset(str, st[1]);
X		STABSET(str);
X	    }
X	    else
X		str = st[1];
X	    break;
X	}
X	else {
X	    anum = 2;
X	    optype = O_ITEM2;
X	    argflags = arg[anum].arg_flags;
X	    if (gimme == G_ARRAY)
X		argflags |= AF_ARYOK;
X	    argtype = arg[anum].arg_type & A_MASK;
X	    argptr = arg[anum].arg_ptr;
X	    maxarg = anum = 1;
X	    sp = arglast[0];
X	    st -= sp;
X	    goto re_eval;
X	}
X    case O_COND_EXPR:
X	anum = (str_true(st[1]) ? 2 : 3);
X	optype = (anum == 2 ? O_ITEM2 : O_ITEM3);
X	argflags = arg[anum].arg_flags;
X	if (gimme == G_ARRAY)
X	    argflags |= AF_ARYOK;
X	argtype = arg[anum].arg_type & A_MASK;
X	argptr = arg[anum].arg_ptr;
X	maxarg = anum = 1;
X	sp = arglast[0];
X	st -= sp;
X	goto re_eval;
X    case O_COMMA:
X	if (gimme == G_ARRAY)
X	    goto array_return;
X	str = st[2];
X	break;
X    case O_NEGATE:
X	value = -str_gnum(st[1]);
X	goto donumset;
X    case O_NOT:
X	value = (double) !str_true(st[1]);
X	goto donumset;
X    case O_COMPLEMENT:
X#ifndef lint
X	value = (double) ~(long)str_gnum(st[1]);
X#endif
X	goto donumset;
X    case O_SELECT:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    defoutstab = arg[1].arg_ptr.arg_stab;
X	else
X	    defoutstab = stabent(str_get(st[1]),TRUE);
X	if (!stab_io(defoutstab))
X	    stab_io(defoutstab) = stio_new();
X	curoutstab = defoutstab;
X	str_set(str,stab_io(curoutstab)->ofp ? Yes : No);
X	STABSET(str);
X	break;
X    case O_WRITE:
X	if (maxarg == 0)
X	    stab = defoutstab;
X	else if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	if (!stab_io(stab)) {
X	    str_set(str, No);
X	    STABSET(str);
X	    break;
X	}
X	curoutstab = stab;
X	fp = stab_io(stab)->ofp;
X	debarg = arg;
X	if (stab_io(stab)->fmt_stab)
X	    form = stab_form(stab_io(stab)->fmt_stab);
X	else
X	    form = stab_form(stab);
X	if (!form || !fp) {
X	    str_set(str, No);
X	    STABSET(str);
X	    break;
X	}
X	format(&outrec,form,sp);
X	do_write(&outrec,stab_io(stab),sp);
X	if (stab_io(stab)->flags & IOF_FLUSH)
X	    (void)fflush(fp);
X	str_set(str, Yes);
X	STABSET(str);
X	break;
X    case O_DBMOPEN:
X#ifdef SOME_DBM
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	anum = (int)str_gnum(st[3]);
X	value = (double)hdbmopen(stab_hash(stab),str_get(st[2]),anum);
X	goto donumset;
X#else
X	fatal("No dbm or ndbm on this machine");
X#endif
X    case O_DBMCLOSE:
X#ifdef SOME_DBM
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	hdbmclose(stab_hash(stab));
X	goto say_yes;
X#else
X	fatal("No dbm or ndbm on this machine");
X#endif
X    case O_OPEN:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	if (do_open(stab,str_get(st[2]))) {
X	    value = (double)forkprocess;
X	    stab_io(stab)->lines = 0;
X	    goto donumset;
X	}
X	else
X	    str_set(str, No);
X	STABSET(str);
X	break;
X    case O_TRANS:
X	value = (double) do_trans(str,arg);
X	str = arg->arg_ptr.arg_str;
X	goto donumset;
X    case O_NTRANS:
X	str_set(arg->arg_ptr.arg_str, do_trans(str,arg) == 0 ? Yes : No);
X	str = arg->arg_ptr.arg_str;
X	break;
X    case O_CLOSE:
X	if (maxarg == 0)
X	    stab = defoutstab;
X	else if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	str_set(str, do_close(stab,TRUE) ? Yes : No );
X	STABSET(str);
X	break;
X    case O_EACH:
X	sp = do_each(str,stab_hash(arg[1].arg_ptr.arg_stab),
X	  gimme,arglast);
X	goto array_return;
X    case O_VALUES:
X    case O_KEYS:
X	sp = do_kv(str,stab_hash(arg[1].arg_ptr.arg_stab), optype,
X	  gimme,arglast);
X	goto array_return;
X    case O_LARRAY:
X	str->str_nok = str->str_pok = 0;
X	str->str_u.str_stab = arg[1].arg_ptr.arg_stab;
X	str->str_state = SS_ARY;
X	break;
X    case O_ARRAY:
X	ary = stab_array(arg[1].arg_ptr.arg_stab);
X	maxarg = ary->ary_fill + 1;
X	if (gimme == G_ARRAY) { /* array wanted */
X	    sp = arglast[0];
X	    st -= sp;
X	    if (maxarg > 0 && sp + maxarg > stack->ary_max) {
X		astore(stack,sp + maxarg, Nullstr);
X		st = stack->ary_array;
X	    }
X	    Copy(ary->ary_array, &st[sp+1], maxarg, STR*);
X	    sp += maxarg;
X	    goto array_return;
X	}
X	else
X	    str = afetch(ary,maxarg - 1,FALSE);
X	break;
X    case O_AELEM:
X	str = afetch(stab_array(arg[1].arg_ptr.arg_stab),
X	    ((int)str_gnum(st[2])) - arybase,FALSE);
X	if (!str)
X	    goto say_undef;
X	break;
X    case O_DELETE:
X	tmpstab = arg[1].arg_ptr.arg_stab;
X	tmps = str_get(st[2]);
X	str = hdelete(stab_hash(tmpstab),tmps,st[2]->str_cur);
X	if (tmpstab == envstab)
X	    setenv(tmps,Nullch);
X	if (!str)
X	    goto say_undef;
X	break;
X    case O_LHASH:
X	str->str_nok = str->str_pok = 0;
X	str->str_u.str_stab = arg[1].arg_ptr.arg_stab;
X	str->str_state = SS_HASH;
X	break;
X    case O_HASH:
X	if (gimme == G_ARRAY) { /* array wanted */
X	    sp = do_kv(str,stab_hash(arg[1].arg_ptr.arg_stab), optype,
X		gimme,arglast);
X	    goto array_return;
X	}
X	else {
X	    tmpstab = arg[1].arg_ptr.arg_stab;
X	    sprintf(buf,"%d/%d",stab_hash(tmpstab)->tbl_fill,
X		stab_hash(tmpstab)->tbl_max+1);
X	    str_set(str,buf);
X	}
X	break;
X    case O_HELEM:
X	tmpstab = arg[1].arg_ptr.arg_stab;
X	tmps = str_get(st[2]);
X	str = hfetch(stab_hash(tmpstab),tmps,st[2]->str_cur,FALSE);
X	if (!str)
X	    goto say_undef;
X	break;
X    case O_LAELEM:
X	anum = ((int)str_gnum(st[2])) - arybase;
X	str = afetch(stab_array(arg[1].arg_ptr.arg_stab),anum,TRUE);
X	break;
X    case O_LHELEM:
X	tmpstab = arg[1].arg_ptr.arg_stab;
X	tmps = str_get(st[2]);
X	anum = st[2]->str_cur;
X	str = hfetch(stab_hash(tmpstab),tmps,anum,TRUE);
X	if (tmpstab == envstab)		/* heavy wizardry going on here */
X	    str_magic(str, tmpstab, 'E', tmps, anum);	/* str is now magic */
X					/* he threw the brick up into the air */
X	else if (tmpstab == sigstab)
X	    str_magic(str, tmpstab, 'S', tmps, anum);
X#ifdef SOME_DBM
X	else if (stab_hash(tmpstab)->tbl_dbm)
X	    str_magic(str, tmpstab, 'D', tmps, anum);
X#endif
X	break;
X    case O_ASLICE:
X	anum = TRUE;
X	argtype = FALSE;
X	goto do_slice_already;
X    case O_HSLICE:
X	anum = FALSE;
X	argtype = FALSE;
X	goto do_slice_already;
X    case O_LASLICE:
X	anum = TRUE;
X	argtype = TRUE;
X	goto do_slice_already;
X    case O_LHSLICE:
X	anum = FALSE;
X	argtype = TRUE;
X      do_slice_already:
X	sp = do_slice(arg[1].arg_ptr.arg_stab,anum,argtype,
X	    gimme,arglast);
X	goto array_return;
X    case O_PUSH:
X	if (arglast[2] - arglast[1] != 1)
X	    str = do_push(stab_array(arg[1].arg_ptr.arg_stab),arglast);
X	else {
X	    str = str_new(0);		/* must copy the STR */
X	    str_sset(str,st[2]);
X	    (void)apush(stab_array(arg[1].arg_ptr.arg_stab),str);
X	}
X	break;
X    case O_POP:
X	str = apop(stab_array(arg[1].arg_ptr.arg_stab));
X	if (!str)
X	    goto say_undef;
X	str_free(arg->arg_ptr.arg_str);
X	arg->arg_ptr.arg_str = str;
X	break;
X    case O_SHIFT:
X	str = ashift(stab_array(arg[1].arg_ptr.arg_stab));
X	if (!str)
X	    goto say_undef;
X	str_free(arg->arg_ptr.arg_str);
X	arg->arg_ptr.arg_str = str;
X	break;
X    case O_UNPACK:
X	sp = do_unpack(str,gimme,arglast);
X	goto array_return;
X    case O_SPLIT:
X	value = str_gnum(st[3]);
X	sp = do_split(str, arg[2].arg_ptr.arg_spat, (int)value,
X	  gimme,arglast);
X	goto array_return;
X    case O_LENGTH:
X	value = (double) str_len(st[1]);
X	goto donumset;
X    case O_SPRINTF:
X	do_sprintf(str, sp-arglast[0], st+1);
X	break;
X    case O_SUBSTR:
X	anum = ((int)str_gnum(st[2])) - arybase;	/* anum=where to start*/
X	tmps = str_get(st[1]);		/* force conversion to string */
X	if (argtype = (str == st[1]))
X	    str = arg->arg_ptr.arg_str;
X	if (anum < 0)
X	    anum += st[1]->str_cur + arybase;
X	if (anum < 0 || anum > st[1]->str_cur)
X	    str_nset(str,"",0);
X	else {
X	    optype = (int)str_gnum(st[3]);
X	    if (optype < 0)
X		optype = 0;
X	    tmps += anum;
X	    anum = st[1]->str_cur - anum;	/* anum=how many bytes left*/
X	    if (anum > optype)
X		anum = optype;
X	    str_nset(str, tmps, anum);
X	    if (argtype) {			/* it's an lvalue! */
X		lstr = (struct lstring*)str;
X		str->str_magic = st[1];
X		st[1]->str_rare = 's';
X		lstr->lstr_offset = tmps - str_get(st[1]); 
X		lstr->lstr_len = anum; 
X	    }
X	}
X	break;
X    case O_PACK:
X	(void)do_pack(str,arglast);
X	break;
X    case O_GREP:
X	sp = do_grep(arg,str,gimme,arglast);
X	goto array_return;
X    case O_JOIN:
X	do_join(str,arglast);
X	break;
X    case O_SLT:
X	tmps = str_get(st[1]);
X	value = (double) (str_cmp(st[1],st[2]) < 0);
X	goto donumset;
X    case O_SGT:
X	tmps = str_get(st[1]);
X	value = (double) (str_cmp(st[1],st[2]) > 0);
X	goto donumset;
X    case O_SLE:
X	tmps = str_get(st[1]);
X	value = (double) (str_cmp(st[1],st[2]) <= 0);
X	goto donumset;
X    case O_SGE:
X	tmps = str_get(st[1]);
X	value = (double) (str_cmp(st[1],st[2]) >= 0);
X	goto donumset;
X    case O_SEQ:
X	tmps = str_get(st[1]);
X	value = (double) str_eq(st[1],st[2]);
X	goto donumset;
X    case O_SNE:
X	tmps = str_get(st[1]);
X	value = (double) !str_eq(st[1],st[2]);
X	goto donumset;
X    case O_SUBR:
X	sp = do_subr(arg,gimme,arglast);
X	st = stack->ary_array + arglast[0];		/* maybe realloced */
X	goto array_return;
X    case O_DBSUBR:
X	sp = do_dbsubr(arg,gimme,arglast);
X	st = stack->ary_array + arglast[0];		/* maybe realloced */
X	goto array_return;
X    case O_SORT:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	if (!stab)
X	    stab = defoutstab;
X	sp = do_sort(str,stab,
X	  gimme,arglast);
X	goto array_return;
X    case O_REVERSE:
X	sp = do_reverse(str,
X	  gimme,arglast);
X	goto array_return;
X    case O_WARN:
X	if (arglast[2] - arglast[1] != 1) {
X	    do_join(str,arglast);
X	    tmps = str_get(st[1]);
X	}
X	else {
X	    str = st[2];
X	    tmps = str_get(st[2]);
X	}
X	if (!tmps || !*tmps)
X	    tmps = "Warning: something's wrong";
X	warn("%s",tmps);
X	goto say_yes;
X    case O_DIE:
X	if (arglast[2] - arglast[1] != 1) {
X	    do_join(str,arglast);
X	    tmps = str_get(st[1]);
X	}
X	else {
X	    str = st[2];
X	    tmps = str_get(st[2]);
X	}
X	if (!tmps || !*tmps)
X	    exit(1);
X	fatal("%s",tmps);
X	goto say_zero;
X    case O_PRTF:
X    case O_PRINT:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	if (!stab)
X	    stab = defoutstab;
X	if (!stab_io(stab) || !(fp = stab_io(stab)->ofp))
X	    goto say_zero;
X	else {
X	    if (arglast[2] - arglast[1] != 1)
X		value = (double)do_aprint(arg,fp,arglast);
X	    else {
X		value = (double)do_print(st[2],fp);
X		if (orslen && optype == O_PRINT)
X		    if (fwrite(ors, 1, orslen, fp) == 0)
X			goto say_zero;
X	    }
X	    if (stab_io(stab)->flags & IOF_FLUSH)
X		if (fflush(fp) == EOF)
X		    goto say_zero;
X	}
X	goto donumset;
X    case O_CHDIR:
X	tmps = str_get(st[1]);
X	if (!tmps || !*tmps) {
X	    tmpstr = hfetch(stab_hash(envstab),"HOME",4,FALSE);
X	    if (tmpstr)
X		tmps = str_get(tmpstr);
X	}
X	if (!tmps || !*tmps) {
X	    tmpstr = hfetch(stab_hash(envstab),"LOGDIR",6,FALSE);
X	    if (tmpstr)
X		tmps = str_get(tmpstr);
X	}
X#ifdef TAINT
X	taintproper("Insecure dependency in chdir");
X#endif
X	value = (double)(chdir(tmps) >= 0);
X	goto donumset;
X    case O_EXIT:
X	exit((int)str_gnum(st[1]));
X	goto say_zero;
X    case O_RESET:
X	str_reset(str_get(st[1]),arg[2].arg_ptr.arg_hash);
X	value = 1.0;
X	goto donumset;
X    case O_LIST:
X	if (gimme == G_ARRAY)
X	    goto array_return;
X	if (maxarg > 0)
X	    str = st[sp - arglast[0]];	/* unwanted list, return last item */
X	else
X	    str = &str_undef;
X	break;
X    case O_EOF:
X	if (maxarg <= 0)
X	    stab = last_in_stab;
X	else if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	str_set(str, do_eof(stab) ? Yes : No);
X	STABSET(str);
X	break;
X    case O_GETC:
X	if (maxarg <= 0)
X	    stab = stdinstab;
X	else if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	if (do_eof(stab))	/* make sure we have fp with something */
X	    str_set(str, No);
X	else {
X#ifdef TAINT
X	    tainted = 1;
X#endif
X	    str_set(str," ");
X	    *str->str_ptr = getc(stab_io(stab)->ifp); /* should never be EOF */
X	}
X	STABSET(str);
X	break;
X    case O_TELL:
X	if (maxarg <= 0)
X	    stab = last_in_stab;
X	else if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X#ifndef lint
X	value = (double)do_tell(stab);
X#else
X	(void)do_tell(stab);
X#endif
X	goto donumset;
X    case O_RECV:
X    case O_READ:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	tmps = str_get(st[2]);
X	anum = (int)str_gnum(st[3]);
X	STR_GROW(st[2], anum+1), (tmps = str_get(st[2]));	/* sneaky */
X	errno = 0;
X	if (!stab_io(stab) || !stab_io(stab)->ifp)
X	    goto say_zero;
X#ifdef SOCKET
X	else if (optype == O_RECV) {
X	    argtype = sizeof buf;
X	    optype = (int)str_gnum(st[4]);
X	    anum = recvfrom(fileno(stab_io(stab)->ifp), tmps, anum, optype,
X		buf, &argtype);
X	    if (anum >= 0) {
X		st[2]->str_cur = anum;
X		st[2]->str_ptr[anum] = '\0';
X		str_nset(str,buf,argtype);
X	    }
X	    else
X		str_sset(str,&str_undef);
X	    break;
X	}
X	else if (stab_io(stab)->type == 's') {
X	    argtype = sizeof buf;
X	    anum = recvfrom(fileno(stab_io(stab)->ifp), tmps, anum, 0,
X		buf, &argtype);
X	}
X#else
X	else if (optype == O_RECV)
X	    goto badsock;
X#endif
X	else
X	    anum = fread(tmps, 1, anum, stab_io(stab)->ifp);
X	if (anum < 0)
X	    goto say_undef;
X	st[2]->str_cur = anum;
X	st[2]->str_ptr[anum] = '\0';
X	value = (double)anum;
X	goto donumset;
X    case O_SEND:
X#ifdef SOCKET
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	tmps = str_get(st[2]);
X	anum = (int)str_gnum(st[3]);
X	optype = sp - arglast[0];
X	errno = 0;
X	if (optype > 4)
X	    warn("Too many args on send");
X	if (optype >= 4) {
X	    tmps2 = str_get(st[4]);
X	    anum = sendto(fileno(stab_io(stab)->ifp), tmps, st[2]->str_cur,
X	      anum, tmps2, st[4]->str_cur);
X	}
X	else
X	    anum = send(fileno(stab_io(stab)->ifp), tmps, st[2]->str_cur, anum);
X	if (anum < 0)
X	    goto say_undef;
X	value = (double)anum;
X	goto donumset;
X#else
X	goto badsock;
X#endif
X    case O_SEEK:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	value = str_gnum(st[2]);
X	str_set(str, do_seek(stab,
X	  (long)value, (int)str_gnum(st[3]) ) ? Yes : No);
X	STABSET(str);
X	break;
X    case O_RETURN:
X	tmps = "SUB";		/* just fake up a "last SUB" */
X	optype = O_LAST;
X	if (gimme == G_ARRAY) {
X	    lastretstr = Nullstr;
X	    lastspbase = arglast[0];
X	    lastsize = arglast[1] - arglast[0];
X	}
X	else
X	    lastretstr = str_static(st[arglast[1] - arglast[0]]);
X	goto dopop;
X    case O_REDO:
X    case O_NEXT:
X    case O_LAST:
X	if (maxarg > 0) {
X	    tmps = str_get(arg[1].arg_ptr.arg_str);
X	  dopop:
X	    while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
X	      strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
X#ifdef DEBUGGING
X		if (debug & 4) {
X		    deb("(Skipping label #%d %s)\n",loop_ptr,
X			loop_stack[loop_ptr].loop_label);
X		}
X#endif
X		loop_ptr--;
X	    }
X#ifdef DEBUGGING
X	    if (debug & 4) {
X		deb("(Found label #%d %s)\n",loop_ptr,
X		    loop_stack[loop_ptr].loop_label);
X	    }
X#endif
X	}
X	if (loop_ptr < 0)
X	    fatal("Bad label: %s", maxarg > 0 ? tmps : "<null>");
X	if (!lastretstr && optype == O_LAST && lastsize) {
X	    st -= arglast[0];
X	    st += lastspbase + 1;
X	    optype = loop_stack[loop_ptr].loop_sp - lastspbase; /* negative */
X	    if (optype) {
X		for (anum = lastsize; anum > 0; anum--,st++)
X		    st[optype] = str_static(st[0]);
X	    }
X	    longjmp(loop_stack[loop_ptr].loop_env, O_LAST);
X	}
X	longjmp(loop_stack[loop_ptr].loop_env, optype);
X    case O_DUMP:
X    case O_GOTO:/* shudder */
X	goto_targ = str_get(arg[1].arg_ptr.arg_str);
X	if (!*goto_targ)
X	    goto_targ = Nullch;		/* just restart from top */
X	if (optype == O_DUMP)
X	    abort();
X	longjmp(top_env, 1);
X    case O_INDEX:
X	tmps = str_get(st[1]);
X#ifndef lint
X	if (!(tmps2 = fbminstr((unsigned char*)tmps,
X	  (unsigned char*)tmps + st[1]->str_cur, st[2])))
X#else
X	if (tmps2 = fbminstr(Null(unsigned char*),Null(unsigned char*),Nullstr))
X#endif
X	    value = (double)(-1 + arybase);
X	else
X	    value = (double)(tmps2 - tmps + arybase);
X	goto donumset;
X    case O_RINDEX:
X	tmps = str_get(st[1]);
X	tmps2 = str_get(st[2]);
X#ifndef lint
X	if (!(tmps2 = rninstr(tmps,  tmps  + st[1]->str_cur,
X			      tmps2, tmps2 + st[2]->str_cur)))
X#else
X	if (tmps2 = rninstr(Nullch,Nullch,Nullch,Nullch))
X#endif
X	    value = (double)(-1 + arybase);
X	else
X	    value = (double)(tmps2 - tmps + arybase);
X	goto donumset;
X    case O_TIME:
X#ifndef lint
X	value = (double) time(Null(long*));
X#endif
X	goto donumset;
X    case O_TMS:
X	sp = do_tms(str,gimme,arglast);
X	goto array_return;
X    case O_LOCALTIME:
X	when = (long)str_gnum(st[1]);
X	sp = do_time(str,localtime(&when),
X	  gimme,arglast);
X	goto array_return;
X    case O_GMTIME:
X	when = (long)str_gnum(st[1]);
X	sp = do_time(str,gmtime(&when),
X	  gimme,arglast);
X	goto array_return;
X    case O_LSTAT:
X    case O_STAT:
X	sp = do_stat(str,arg,
X	  gimme,arglast);
X	goto array_return;
X    case O_CRYPT:
X#ifdef CRYPT
X	tmps = str_get(st[1]);
X#ifdef FCRYPT
X	str_set(str,fcrypt(tmps,str_get(st[2])));
X#else
X	str_set(str,crypt(tmps,str_get(st[2])));
X#endif
X#else
X	fatal(
X	  "The crypt() function is unimplemented due to excessive paranoia.");
X#endif
X	break;
X    case O_ATAN2:
X	value = str_gnum(st[1]);
X	value = atan2(value,str_gnum(st[2]));
X	goto donumset;
X    case O_SIN:
X	value = sin(str_gnum(st[1]));
X	goto donumset;
X    case O_COS:
X	value = cos(str_gnum(st[1]));
X	goto donumset;
X    case O_RAND:
X	value = str_gnum(st[1]);
X	if (value == 0.0)
X	    value = 1.0;
X#if RANDBITS == 31
X	value = rand() * value / 2147483648.0;
X#else
X#if RANDBITS == 16
X	value = rand() * value / 65536.0;
X#else
X#if RANDBITS == 15
X	value = rand() * value / 32768.0;
X#else
X	value = rand() * value / (double)(((unsigned long)1) << RANDBITS);
X#endif
X#endif
X#endif
X	goto donumset;
X    case O_SRAND:
X	(void)srand((int)str_gnum(st[1]));
X	goto say_yes;
X    case O_EXP:
X	value = exp(str_gnum(st[1]));
X	goto donumset;
X    case O_LOG:
X	value = log(str_gnum(st[1]));
X	goto donumset;
X    case O_SQRT:
X	value = sqrt(str_gnum(st[1]));
X	goto donumset;
X    case O_INT:
X	value = str_gnum(st[1]);
X	if (value >= 0.0)
X	    (void)modf(value,&value);
X	else {
X	    (void)modf(-value,&value);
X	    value = -value;
X	}
X	goto donumset;
X    case O_ORD:
X#ifndef I286
X	value = (double) *str_get(st[1]);
X#else
X	{   int  zapc;
X	    char *zaps;
X
X	    zaps = str_get(st[1]);
X	    zapc = (int) *zaps;
X	    value = (double) zapc;
X	}
X#endif
X	goto donumset;
X    case O_SLEEP:
X	tmps = str_get(st[1]);
X	(void)time(&when);
X	if (!tmps || !*tmps)
X	    sleep((32767<<16)+32767);
X	else
X	    sleep((unsigned int)atoi(tmps));
X#ifndef lint
X	value = (double)when;
X	(void)time(&when);
X	value = ((double)when) - value;
X#endif
X	goto donumset;
X    case O_RANGE:
X	sp = do_range(gimme,arglast);
X	goto array_return;
X    case O_F_OR_R:
X	if (gimme == G_ARRAY) {		/* it's a range */
X	    /* can we optimize to constant array? */
X	    if ((arg[1].arg_type & A_MASK) == A_SINGLE &&
X	      (arg[2].arg_type & A_MASK) == A_SINGLE) {
X		st[2] = arg[2].arg_ptr.arg_str;
X		sp = do_range(gimme,arglast);
X		st = stack->ary_array;
X		maxarg = sp - arglast[0];
X		str_free(arg[1].arg_ptr.arg_str);
X		str_free(arg[2].arg_ptr.arg_str);
X		arg->arg_type = O_ARRAY;
X		arg[1].arg_type = A_STAB|A_DONT;
X		arg->arg_len = 1;
X		stab = arg[1].arg_ptr.arg_stab = aadd(genstab());
X		ary = stab_array(stab);
X		afill(ary,maxarg - 1);
X		st += arglast[0]+1;
X		while (maxarg-- > 0)
X		    ary->ary_array[maxarg] = str_smake(st[maxarg]);
X		goto array_return;
X	    }
X	    arg->arg_type = optype = O_RANGE;
X	    maxarg = arg->arg_len = 2;
X	    anum = 2;
X	    arg[anum].arg_flags &= ~AF_ARYOK;
X	    argflags = arg[anum].arg_flags;
X	    argtype = arg[anum].arg_type & A_MASK;
X	    arg[anum].arg_type = argtype;
X	    argptr = arg[anum].arg_ptr;
X	    sp = arglast[0];
X	    st -= sp;
X	    sp++;
X	    goto re_eval;
X	}
X	arg->arg_type = O_FLIP;
X	/* FALL THROUGH */
X    case O_FLIP:
X	if ((arg[1].arg_type & A_MASK) == A_SINGLE ?
X	  last_in_stab && (int)str_gnum(st[1]) == stab_io(last_in_stab)->lines
X	  :
X	  str_true(st[1]) ) {
X	    str_numset(str,0.0);
X	    anum = 2;
X	    arg->arg_type = optype = O_FLOP;
X	    arg[2].arg_type &= ~A_DONT;
X	    arg[1].arg_type |= A_DONT;
X	    argflags = arg[2].arg_flags;
X	    argtype = arg[2].arg_type & A_MASK;
X	    argptr = arg[2].arg_ptr;
X	    sp = arglast[0];
X	    st -= sp;
X	    goto re_eval;
X	}
X	str_set(str,"");
X	break;
X    case O_FLOP:
X	str_inc(str);
X	if ((arg[2].arg_type & A_MASK) == A_SINGLE ?
X	  last_in_stab && (int)str_gnum(st[2]) == stab_io(last_in_stab)->lines
X	  :
X	  str_true(st[2]) ) {
X	    arg->arg_type = O_FLIP;
X	    arg[1].arg_type &= ~A_DONT;
X	    arg[2].arg_type |= A_DONT;
X	    str_cat(str,"E0");
X	}
X	break;
X    case O_FORK:
X	anum = fork();
X	if (!anum && (tmpstab = stabent("$",allstabs)))
X	    str_numset(STAB_STR(tmpstab),(double)getpid());
X	value = (double)anum;
X	goto donumset;
X    case O_WAIT:
X#ifndef lint
X	ihand = signal(SIGINT, SIG_IGN);
X	qhand = signal(SIGQUIT, SIG_IGN);
X	anum = wait(&argflags);
X	if (anum > 0)
X	    pidgone(anum,argflags);
X	value = (double)anum;
X#else
X	ihand = qhand = 0;
X#endif
X	(void)signal(SIGINT, ihand);
X	(void)signal(SIGQUIT, qhand);
X	statusvalue = (unsigned short)argflags;
X	goto donumset;
X    case O_SYSTEM:
X#ifdef TAINT
X	if (arglast[2] - arglast[1] == 1) {
X	    taintenv();
X	    tainted |= st[2]->str_tainted;
X	    taintproper("Insecure dependency in system");
X	}
X#endif
X	while ((anum = vfork()) == -1) {
X	    if (errno != EAGAIN) {
X		value = -1.0;
X		goto donumset;
X	    }
X	    sleep(5);
X	}
X	if (anum > 0) {
X#ifndef lint
X	    ihand = signal(SIGINT, SIG_IGN);
X	    qhand = signal(SIGQUIT, SIG_IGN);
X	    while ((argtype = wait(&argflags)) != anum && argtype >= 0)
X		pidgone(argtype,argflags);
X#else
X	    ihand = qhand = 0;
X#endif
X	    (void)signal(SIGINT, ihand);
X	    (void)signal(SIGQUIT, qhand);
X	    statusvalue = (unsigned short)argflags;
X	    if (argtype == -1)
X		value = -1.0;
X	    else {
X		value = (double)((unsigned int)argflags & 0xffff);
X	    }
X	    goto donumset;
X	}
X	if ((arg[1].arg_type & A_MASK) == A_STAB)
X	    value = (double)do_aexec(st[1],arglast);
X	else if (arglast[2] - arglast[1] != 1)
X	    value = (double)do_aexec(Nullstr,arglast);
X	else {
X	    value = (double)do_exec(str_get(str_static(st[2])));
X	}
X	_exit(-1);
X    case O_EXEC:
X	if ((arg[1].arg_type & A_MASK) == A_STAB)
X	    value = (double)do_aexec(st[1],arglast);
X	else if (arglast[2] - arglast[1] != 1)
X	    value = (double)do_aexec(Nullstr,arglast);
X	else {
X	    value = (double)do_exec(str_get(str_static(st[2])));
X	}
X	goto donumset;
X    case O_HEX:
X	argtype = 4;
X	goto snarfnum;
X
X    case O_OCT:
X	argtype = 3;
X
X      snarfnum:
X	anum = 0;
X	tmps = str_get(st[1]);
X	for (;;) {
X	    switch (*tmps) {
X	    default:
X		goto out;
X	    case '8': case '9':
X		if (argtype != 4)
X		    goto out;
X		/* FALL THROUGH */
X	    case '0': case '1': case '2': case '3': case '4':
X	    case '5': case '6': case '7':
X		anum <<= argtype;
X		anum += *tmps++ & 15;
X		break;
X	    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
X	    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
X		if (argtype != 4)
X		    goto out;
X		anum <<= 4;
X		anum += (*tmps++ & 7) + 9;
X		break;
X	    case 'x':
X		argtype = 4;
X		tmps++;
X		break;
X	    }
X	}
X      out:
X	value = (double)anum;
X	goto donumset;
X    case O_CHMOD:
X    case O_CHOWN:
X    case O_KILL:
X    case O_UNLINK:
X    case O_UTIME:
X	value = (double)apply(optype,arglast);
X	goto donumset;
X    case O_UMASK:
X	value = (double)umask((int)str_gnum(st[1]));
X#ifdef TAINT
X	taintproper("Insecure dependency in umask");
X#endif
X	goto donumset;
X    case O_RENAME:
X	tmps = str_get(st[1]);
X	tmps2 = str_get(st[2]);
X#ifdef TAINT
X	taintproper("Insecure dependency in rename");
X#endif
X#ifdef RENAME
X	value = (double)(rename(tmps,tmps2) >= 0);
X#else
X	if (euid || stat(tmps2,&statbuf) < 0 ||
X	  (statbuf.st_mode & S_IFMT) != S_IFDIR )
X	    (void)UNLINK(tmps2);	/* avoid unlinking a directory */
X	if (!(anum = link(tmps,tmps2)))
X	    anum = UNLINK(tmps);
X	value = (double)(anum >= 0);
X#endif
X	goto donumset;
X    case O_LINK:
X	tmps = str_get(st[1]);
X	tmps2 = str_get(st[2]);
X#ifdef TAINT
X	taintproper("Insecure dependency in link");
X#endif
X	value = (double)(link(tmps,tmps2) >= 0);
X	goto donumset;
X    case O_MKDIR:
X	tmps = str_get(st[1]);
X	anum = (int)str_gnum(st[2]);
X#ifdef TAINT
X	taintproper("Insecure dependency in mkdir");
X#endif
X#ifdef MKDIR
X	value = (double)(mkdir(tmps,anum) >= 0);
X#else
X	(void)sprintf(buf,"mkdir %s 2>&1",tmps);
X      one_liner:
X	rsfp = mypopen(buf,"r");
X	if (rsfp) {
X	    *buf = '\0';
X	    tmps2 = fgets(buf,sizeof buf,rsfp);
X	    (void)mypclose(rsfp);
X	    if (tmps2 != Nullch) {
X		for (errno = 1; errno <= sys_nerr; errno++) {
X		    if (instr(buf,sys_errlist[errno]))	/* you don't see this */
X			goto say_zero;
X		}
X		errno = 0;
X	    }
X	    else
X		value = 1.0;
X	}
X	else
X	    goto say_zero;
X#endif
X	goto donumset;
X    case O_RMDIR:
X	tmps = str_get(st[1]);
X#ifdef TAINT
X	taintproper("Insecure dependency in rmdir");
X#endif
X#ifdef RMDIR
X	value = (double)(rmdir(tmps) >= 0);
X	goto donumset;
X#else
X	(void)sprintf(buf,"rmdir %s 2>&1",tmps);
X	goto one_liner;		/* see above in MKDIR */
X#endif
X    case O_GETPPID:
X	value = (double)getppid();
X	goto donumset;
X    case O_GETPGRP:
X#ifdef GETPGRP
X	value = (double)getpgrp((int)str_gnum(st[1]));
X	goto donumset;
X#else
X	fatal("The getpgrp() function is unimplemented on this machine");
X	break;
X#endif
X    case O_SETPGRP:
X#ifdef SETPGRP
X	argtype = (int)str_gnum(st[1]);
X	anum = (int)str_gnum(st[2]);
X#ifdef TAINT
X	taintproper("Insecure dependency in setpgrp");
X#endif
X	value = (double)(setpgrp(argtype,anum) >= 0);
X	goto donumset;
X#else
X	fatal("The setpgrp() function is unimplemented on this machine");
X	break;
X#endif
X    case O_GETPRIORITY:
X#ifdef GETPRIORITY
X	argtype = (int)str_gnum(st[1]);
X	anum = (int)str_gnum(st[2]);
X	value = (double)getpriority(argtype,anum);
X	goto donumset;
X#else
X	fatal("The getpriority() function is unimplemented on this machine");
X	break;
X#endif
X    case O_SETPRIORITY:
X#ifdef SETPRIORITY
X	argtype = (int)str_gnum(st[1]);
X	anum = (int)str_gnum(st[2]);
X	optype = (int)str_gnum(st[3]);
X#ifdef TAINT
X	taintproper("Insecure dependency in setpriority");
X#endif
X	value = (double)(setpriority(argtype,anum,optype) >= 0);
X	goto donumset;
X#else
X	fatal("The setpriority() function is unimplemented on this machine");
X	break;
X#endif
X    case O_CHROOT:
X	tmps = str_get(st[1]);
X#ifdef TAINT
X	taintproper("Insecure dependency in chroot");
X#endif
X	value = (double)(chroot(tmps) >= 0);
X	goto donumset;
X    case O_FCNTL:
X    case O_IOCTL:
X	if (maxarg <= 0)
X	    stab = last_in_stab;
X	else if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	argtype = (int)str_gnum(st[2]);
X#ifdef TAINT
X	taintproper("Insecure dependency in ioctl");
X#endif
X	value = (double)do_ctl(optype,stab,argtype,st[3]);
X	goto donumset;
X    case O_FLOCK:
X#ifdef FLOCK
X	if (maxarg <= 0)
X	    stab = last_in_stab;
X	else if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	if (stab && stab_io(stab))
X	    fp = stab_io(stab)->ifp;
X	else
X	    fp = Nullfp;
X	if (fp) {
X	    argtype = (int)str_gnum(st[2]);
X	    value = (double)(flock(fileno(fp),argtype) >= 0);
X	}
X	else
X	    value = 0;
X	goto donumset;
X#else
X	fatal("The flock() function is unimplemented on this machine");
X	break;
X#endif
X    case O_UNSHIFT:
X	ary = stab_array(arg[1].arg_ptr.arg_stab);
X	if (arglast[2] - arglast[1] != 1)
X	    do_unshift(ary,arglast);
X	else {
X	    str = str_new(0);		/* must copy the STR */
X	    str_sset(str,st[2]);
X	    aunshift(ary,1);
X	    (void)astore(ary,0,str);
X	}
X	value = (double)(ary->ary_fill + 1);
X	break;
X    case O_DOFILE:
X    case O_EVAL:
X	tmpstr =
X	  (arg[1].arg_type & A_MASK) != A_NULL ? st[1] : stab_val(defstab);
X#ifdef TAINT
X	tainted |= tmpstr->str_tainted;
X	taintproper("Insecure dependency in eval");
X#endif
X	sp = do_eval(tmpstr, optype, arg[2].arg_ptr.arg_hash,
X	    gimme,arglast);
X	goto array_return;
X
X    case O_FTRREAD:
X	argtype = 0;
X	anum = S_IREAD;
X	goto check_perm;
X    case O_FTRWRITE:
X	argtype = 0;
X	anum = S_IWRITE;
X	goto check_perm;
X    case O_FTREXEC:
X	argtype = 0;
X	anum = S_IEXEC;
X	goto check_perm;
X    case O_FTEREAD:
X	argtype = 1;
X	anum = S_IREAD;
X	goto check_perm;
X    case O_FTEWRITE:
X	argtype = 1;
X	anum = S_IWRITE;
X	goto check_perm;
X    case O_FTEEXEC:
X	argtype = 1;
X	anum = S_IEXEC;
X      check_perm:
X	if (mystat(arg,st[1]) < 0)
X	    goto say_undef;
X	if (cando(anum,argtype,&statcache))
X	    goto say_yes;
X	goto say_no;
X
X    case O_FTIS:
X	if (mystat(arg,st[1]) < 0)
X	    goto say_undef;
X	goto say_yes;
X    case O_FTEOWNED:
X    case O_FTROWNED:
X	if (mystat(arg,st[1]) < 0)
X	    goto say_undef;
X	if (statcache.st_uid == (optype == O_FTEOWNED ? euid : uid) )
X	    goto say_yes;
X	goto say_no;
X    case O_FTZERO:
X	if (mystat(arg,st[1]) < 0)
X	    goto say_undef;
X	if (!statcache.st_size)
X	    goto say_yes;
X	goto say_no;
X    case O_FTSIZE:
X	if (mystat(arg,st[1]) < 0)
X	    goto say_undef;
X	if (statcache.st_size)
X	    goto say_yes;
X	goto say_no;
X
X    case O_FTSOCK:
X#ifdef S_IFSOCK
X	anum = S_IFSOCK;
X	goto check_file_type;
X#else
X	goto say_no;
X#endif
X    case O_FTCHR:
X	anum = S_IFCHR;
X	goto check_file_type;
X    case O_FTBLK:
X	anum = S_IFBLK;
X	goto check_file_type;
X    case O_FTFILE:
X	anum = S_IFREG;
X	goto check_file_type;
X    case O_FTDIR:
X	anum = S_IFDIR;
X      check_file_type:
X	if (mystat(arg,st[1]) < 0)
X	    goto say_undef;
X	if ((statcache.st_mode & S_IFMT) == anum )
X	    goto say_yes;
X	goto say_no;
X    case O_FTPIPE:
X#ifdef S_IFIFO
X	anum = S_IFIFO;
X	goto check_file_type;
X#else
X	goto say_no;
X#endif
X    case O_FTLINK:
X#ifdef SYMLINK
X	if (lstat(str_get(st[1]),&statcache) < 0)
X	    goto say_undef;
X	if ((statcache.st_mode & S_IFMT) == S_IFLNK )
X	    goto say_yes;
X#endif
X	goto say_no;
X    case O_SYMLINK:
X#ifdef SYMLINK
X	tmps = str_get(st[1]);
X	tmps2 = str_get(st[2]);
X#ifdef TAINT
X	taintproper("Insecure dependency in symlink");
X#endif
X	value = (double)(symlink(tmps,tmps2) >= 0);
X	goto donumset;
X#else
X	fatal("Unsupported function symlink()");
X#endif
X    case O_READLINK:
X#ifdef SYMLINK
X	anum = readlink(str_get(st[1]),buf,sizeof buf);
X	if (anum < 0)
X	    goto say_undef;
X	str_nset(str,buf,anum);
X	break;
X#else
X	fatal("Unsupported function readlink()");
X#endif
X    case O_FTSUID:
X	anum = S_ISUID;
X	goto check_xid;
X    case O_FTSGID:
X	anum = S_ISGID;
X	goto check_xid;
X    case O_FTSVTX:
X	anum = S_ISVTX;
X      check_xid:
X	if (mystat(arg,st[1]) < 0)
X	    goto say_undef;
X	if (statcache.st_mode & anum)
X	    goto say_yes;
X	goto say_no;
X    case O_FTTTY:
X	if (arg[1].arg_type & A_DONT) {
X	    stab = arg[1].arg_ptr.arg_stab;
X	    tmps = "";
X	}
X	else
X	    stab = stabent(tmps = str_get(st[1]),FALSE);
X	if (stab && stab_io(stab) && stab_io(stab)->ifp)
X	    anum = fileno(stab_io(stab)->ifp);
X	else if (isdigit(*tmps))
X	    anum = atoi(tmps);
X	else
X	    goto say_undef;
X	if (isatty(anum))
X	    goto say_yes;
X	goto say_no;
X    case O_FTTEXT:
X    case O_FTBINARY:
X	str = do_fttext(arg,st[1]);
X	break;
X#ifdef SOCKET
X    case O_SOCKET:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X#ifndef lint
X	value = (double)do_socket(stab,arglast);
X#else
X	(void)do_socket(stab,arglast);
X#endif
X	goto donumset;
X    case O_BIND:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X#ifndef lint
X	value = (double)do_bind(stab,arglast);
X#else
X	(void)do_bind(stab,arglast);
X#endif
X	goto donumset;
X    case O_CONNECT:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X#ifndef lint
X	value = (double)do_connect(stab,arglast);
X#else
X	(void)do_connect(stab,arglast);
X#endif
X	goto donumset;
X    case O_LISTEN:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X#ifndef lint
X	value = (double)do_listen(stab,arglast);
X#else
X	(void)do_listen(stab,arglast);
X#endif
X	goto donumset;
X    case O_ACCEPT:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	if ((arg[2].arg_type & A_MASK) == A_WORD)
X	    stab2 = arg[2].arg_ptr.arg_stab;
X	else
X	    stab2 = stabent(str_get(st[2]),TRUE);
X	do_accept(str,stab,stab2);
X	STABSET(str);
X	break;
X    case O_GHBYNAME:
X    case O_GHBYADDR:
X    case O_GHOSTENT:
X	sp = do_ghent(optype,
X	  gimme,arglast);
X	goto array_return;
X    case O_GNBYNAME:
X    case O_GNBYADDR:
X    case O_GNETENT:
X	sp = do_gnent(optype,
X	  gimme,arglast);
X	goto array_return;
X    case O_GPBYNAME:
X    case O_GPBYNUMBER:
X    case O_GPROTOENT:
X	sp = do_gpent(optype,
X	  gimme,arglast);
X	goto array_return;
X    case O_GSBYNAME:
X    case O_GSBYPORT:
X    case O_GSERVENT:
X	sp = do_gsent(optype,
X	  gimme,arglast);
X	goto array_return;
X    case O_SHOSTENT:
X	value = (double) sethostent((int)str_gnum(st[1]));
X	goto donumset;
X    case O_SNETENT:
X	value = (double) setnetent((int)str_gnum(st[1]));
X	goto donumset;
X    case O_SPROTOENT:
X	value = (double) setprotoent((int)str_gnum(st[1]));
X	goto donumset;
X    case O_SSERVENT:
X	value = (double) setservent((int)str_gnum(st[1]));
X	goto donumset;
X    case O_EHOSTENT:
X	value = (double) endhostent();
X	goto donumset;
X    case O_ENETENT:
X	value = (double) endnetent();
X	goto donumset;
X    case O_EPROTOENT:
X	value = (double) endprotoent();
X	goto donumset;
X    case O_ESERVENT:
X	value = (double) endservent();
X	goto donumset;
X    case O_SSELECT:
X	sp = do_select(gimme,arglast);
X	goto array_return;
X    case O_SOCKETPAIR:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	if ((arg[2].arg_type & A_MASK) == A_WORD)
X	    stab2 = arg[2].arg_ptr.arg_stab;
X	else
X	    stab2 = stabent(str_get(st[2]),TRUE);
X#ifndef lint
X	value = (double)do_spair(stab,stab2,arglast);
X#else
X	(void)do_spair(stab,stab2,arglast);
X#endif
X	goto donumset;
X
X#else /* SOCKET not defined */
X    case O_SOCKET:
X    case O_BIND:
X    case O_CONNECT:
X    case O_LISTEN:
X    case O_ACCEPT:
X    case O_SSELECT:
X    case O_SOCKETPAIR:
X    case O_GHBYNAME:
X    case O_GHBYADDR:
X    case O_GHOSTENT:
X    case O_GNBYNAME:
X    case O_GNBYADDR:
X    case O_GNETENT:
X    case O_GPBYNAME:
X    case O_GPBYNUMBER:
X    case O_GPROTOENT:
X    case O_GSBYNAME:
X    case O_GSBYPORT:
X    case O_GSERVENT:
X    case O_SHOSTENT:
X    case O_SNETENT:
X    case O_SPROTOENT:
X    case O_SSERVENT:
X    case O_EHOSTENT:
X    case O_ENETENT:
X    case O_EPROTOENT:
X    case O_ESERVENT:
X      badsock:
X	fatal("Unsupported socket function");
X#endif /* SOCKET */
X    case O_WANTARRAY:
X	if (gimme == G_ARRAY)
X	    goto say_yes;
X	goto say_no;
X    case O_FILENO:
X	if ((arg[1].arg_type & A_MASK) == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(st[1]),TRUE);
X	if (!stab || !(stio = stab_io(stab)) || !(fp = stio->ifp))
X	    goto say_undef;
X	value = fileno(fp);
X	goto donumset;
X    case O_VEC:
X	sp = do_vec(str == st[1], arg->arg_ptr.arg_str, arglast);
X	goto array_return;
X    }
X
X  normal_return:
X    st[1] = str;
X#ifdef DEBUGGING
X    if (debug) {
X	dlevel--;
X	if (debug & 8)
X	    deb("%s RETURNS \"%s\"\n",opname[optype],str_get(str));
X    }
X#endif
X    return arglast[0] + 1;
X
Xarray_return:
X#ifdef DEBUGGING
X    if (debug) {
X	dlevel--;
X	if (debug & 8)
X	    deb("%s RETURNS ARRAY OF %d ARGS\n",opname[optype],sp - arglast[0]);
X    }
X#endif
X    return sp;
X
Xsay_yes:
X    str = &str_yes;
X    goto normal_return;
X
Xsay_no:
X    str = &str_no;
X    goto normal_return;
X
Xsay_undef:
X    str = &str_undef;
X    goto normal_return;
X
Xsay_zero:
X    value = 0.0;
X    /* FALL THROUGH */
X
Xdonumset:
X    str_numset(str,value);
X    STABSET(str);
X    st[1] = str;
X#ifdef DEBUGGING
X    if (debug) {
X	dlevel--;
X	if (debug & 8)
X	    deb("%s RETURNS \"%f\"\n",opname[optype],value);
X    }
X#endif
X    return arglast[0] + 1;
X}
!STUFFY!FUNK!
echo Extracting t/op.array
sed >t/op.array <<'!STUFFY!FUNK!' -e 's/X//'
X#!./perl
X
X# $Header$
X
Xprint "1..30\n";
X
X@ary = (1,2,3,4,5);
Xif (join('',@ary) eq '12345') {print "ok 1\n";} else {print "not ok 1\n";}
X
X$tmp = $ary[$#ary]; --$#ary;
Xif ($tmp == 5) {print "ok 2\n";} else {print "not ok 2\n";}
Xif ($#ary == 3) {print "ok 3\n";} else {print "not ok 3\n";}
Xif (join('',@ary) eq '1234') {print "ok 4\n";} else {print "not ok 4\n";}
X
X$[ = 1;
X@ary = (1,2,3,4,5);
Xif (join('',@ary) eq '12345') {print "ok 5\n";} else {print "not ok 5\n";}
X
X$tmp = $ary[$#ary]; --$#ary;
Xif ($tmp == 5) {print "ok 6\n";} else {print "not ok 6\n";}
Xif ($#ary == 4) {print "ok 7\n";} else {print "not ok 7\n";}
Xif (join('',@ary) eq '1234') {print "ok 8\n";} else {print "not ok 8\n";}
X
Xif ($ary[5] eq '') {print "ok 9\n";} else {print "not ok 9\n";}
X
X$#ary += 1;	# see if we can recover element 5
Xif ($#ary == 5) {print "ok 10\n";} else {print "not ok 10\n";}
Xif ($ary[5] == 5) {print "ok 11\n";} else {print "not ok 11\n";}
X
X$[ = 0;
X@foo = ();
X$r = join(',', $#foo, @foo);
Xif ($r eq "-1") {print "ok 12\n";} else {print "not ok 12 $r\n";}
X$foo[0] = '0';
X$r = join(',', $#foo, @foo);
Xif ($r eq "0,0") {print "ok 13\n";} else {print "not ok 13 $r\n";}
X$foo[2] = '2';
X$r = join(',', $#foo, @foo);
Xif ($r eq "2,0,,2") {print "ok 14\n";} else {print "not ok 14 $r\n";}
X@bar = ();
X$bar[0] = '0';
X$bar[1] = '1';
X$r = join(',', $#bar, @bar);
Xif ($r eq "1,0,1") {print "ok 15\n";} else {print "not ok 15 $r\n";}
X@bar = ();
X$r = join(',', $#bar, @bar);
Xif ($r eq "-1") {print "ok 16\n";} else {print "not ok 16 $r\n";}
X$bar[0] = '0';
X$r = join(',', $#bar, @bar);
Xif ($r eq "0,0") {print "ok 17\n";} else {print "not ok 17 $r\n";}
X$bar[2] = '2';
X$r = join(',', $#bar, @bar);
Xif ($r eq "2,0,,2") {print "ok 18\n";} else {print "not ok 18 $r\n";}
Xreset 'b';
X@bar = ();
X$bar[0] = '0';
X$r = join(',', $#bar, @bar);
Xif ($r eq "0,0") {print "ok 19\n";} else {print "not ok 19 $r\n";}
X$bar[2] = '2';
X$r = join(',', $#bar, @bar);
Xif ($r eq "2,0,,2") {print "ok 20\n";} else {print "not ok 20 $r\n";}
X
X$foo = 'now is the time';
Xif (($F1,$F2,$Etc) = ($foo =~ /^(\S+)\s+(\S+)\s*(.*)/)) {
X    if ($F1 eq 'now' && $F2 eq 'is' && $Etc eq 'the time') {
X	print "ok 21\n";
X    }
X    else {
X	print "not ok 21\n";
X    }
X}
Xelse {
X    print "not ok 21\n";
X}
X
X$foo = 'lskjdf';
Xif ($cnt = (($F1,$F2,$Etc) = ($foo =~ /^(\S+)\s+(\S+)\s*(.*)/))) {
X    print "not ok 22 $cnt $F1:$F2:$Etc\n";
X}
Xelse {
X    print "ok 22\n";
X}
X
X%foo = ('blurfl','dyick','foo','bar','etc.','etc.');
X%bar = %foo;
Xprint $bar{'foo'} eq 'bar' ? "ok 23\n" : "not ok 23\n";
X%bar = ();
Xprint $bar{'foo'} eq '' ? "ok 24\n" : "not ok 24\n";
X(%bar,$a,$b) = (%foo,'how','now');
Xprint $bar{'foo'} eq 'bar' ? "ok 25\n" : "not ok 25\n";
Xprint $bar{'how'} eq 'now' ? "ok 26\n" : "not ok 26\n";
X@bar{keys %foo} = values %foo;
Xprint $bar{'foo'} eq 'bar' ? "ok 27\n" : "not ok 27\n";
Xprint $bar{'how'} eq 'now' ? "ok 28\n" : "not ok 28\n";
X
X@foo = grep(/e/,split(' ','now is the time for all good men to come to'));
Xprint join(' ',@foo) eq 'the time men come' ? "ok 29\n" : "not ok 29\n";
X
X@foo = grep(!/e/,split(' ','now is the time for all good men to come to'));
Xprint join(' ',@foo) eq 'now is for all good to to' ? "ok 30\n" : "not ok 30\n";
!STUFFY!FUNK!
echo ""
echo "End of kit 5 (of 23)"
cat /dev/null >kit5isdone
run=''
config=''
for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23; do
    if test -f kit${iskit}isdone; then
	run="$run $iskit"
    else
	todo="$todo $iskit"
    fi
done
case $todo in
    '')
	echo "You have run all your kits.  Please read README and then type Configure."
	chmod 755 Configure
	;;
    *)  echo "You have run$run."
	echo "You still need to run$todo."
	;;
esac
: Someone might mail this, so...
exit