[comp.sources.unix] v15i097: Perl, release 2, Part08/15

rsalz@uunet.uu.net (Rich Salz) (07/12/88)

Submitted-by: Larry Wall <lwall@jpl-devvax.jpl.nasa.gov>
Posting-number: Volume 15, Issue 97
Archive-name: perl2/part08

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

echo "This is perl 2.0 kit 8 (of 15).  If kit 8 is complete, the line"
echo '"'"End of kit 8 (of 15)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir eg eg/scan 2>/dev/null
echo Extracting eval.c
sed >eval.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: eval.c,v 2.0 88/06/05 00:08:48 root Exp $
X *
X * $Log:	eval.c,v $
X * Revision 2.0  88/06/05  00:08:48  root
X * Baseline version 2.0.
X * 
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;
X
XSTR *
Xeval(arg,retary,sargoff)
Xregister ARG *arg;
XSTR ***retary;		/* where to return an array to, null if nowhere */
Xint sargoff;		/* how many elements in sarg are already assigned */
X{
X    register STR *str;
X    register int anum;
X    register int optype;
X    int maxarg;
X    int maxsarg;
X    double value;
X    STR *quicksarg[5];
X    register STR **sarg = quicksarg;
X    register char *tmps;
X    char *tmps2;
X    int argflags;
X    int argtype;
X    union argptr argptr;
X    int cushion;
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	return &str_no;
X    str = arg->arg_ptr.arg_str;
X    optype = arg->arg_type;
X    maxsarg = maxarg = arg->arg_len;
X    if (maxsarg > 3 || retary) {
X	if (sargoff >= 0) {	/* array already exists, just append to it */
X	    cushion = 10;
X	    sarg = (STR **)saferealloc((char*)*retary,
X	      (maxsarg+sargoff+2+cushion) * sizeof(STR*)) + sargoff;
X	      /* Note that sarg points into the middle of the array */
X	}
X	else {
X	    sargoff = cushion = 0;
X	    sarg = (STR **)safemalloc((maxsarg+2) * sizeof(STR*));
X	}
X    }
X    else
X	sargoff = 0;
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    for (anum = 1; anum <= maxarg; anum++) {
X	argflags = arg[anum].arg_flags;
X	if (argflags & AF_SPECIAL)
X	    continue;
X	argtype = arg[anum].arg_type;
X	argptr = arg[anum].arg_ptr;
X      re_eval:
X	switch (argtype) {
X	default:
X	    sarg[anum] = &str_no;
X#ifdef DEBUGGING
X	    tmps = "NULL";
X#endif
X	    break;
X	case A_EXPR:
X#ifdef DEBUGGING
X	    if (debug & 8) {
X		tmps = "EXPR";
X		deb("%d.EXPR =>\n",anum);
X	    }
X#endif
X	    if (retary &&
X	      (optype == O_LIST || optype == O_ITEM2 || optype == O_ITEM3)) {
X		*retary = sarg - sargoff;
X		eval(argptr.arg_arg, retary, anum - 1 + sargoff);
X		sarg = *retary;		/* they do realloc it... */
X		argtype = maxarg - anum;	/* how many left? */
X		maxsarg = (int)(str_gnum(sarg[0])) + argtype;
X		sargoff = maxsarg - maxarg;
X		if (argtype > 9 - cushion) {	/* we don't have room left */
X		    sarg = (STR **)saferealloc((char*)sarg,
X		      (maxsarg+2+cushion) * sizeof(STR*));
X		}
X		sarg += sargoff;
X	    }
X	    else
X		sarg[anum] = eval(argptr.arg_arg, Null(STR***),-1);
X	    break;
X	case A_CMD:
X#ifdef DEBUGGING
X	    if (debug & 8) {
X		tmps = "CMD";
X		deb("%d.CMD (%lx) =>\n",anum,argptr.arg_cmd);
X	    }
X#endif
X	    sarg[anum] = cmd_exec(argptr.arg_cmd);
X	    break;
X	case A_STAB:
X	    sarg[anum] = STAB_STR(argptr.arg_stab);
X#ifdef DEBUGGING
X	    if (debug & 8) {
X		sprintf(buf,"STAB $%s",argptr.arg_stab->stab_name);
X		tmps = buf;
X	    }
X#endif
X	    break;
X	case A_LEXPR:
X#ifdef DEBUGGING
X	    if (debug & 8) {
X		tmps = "LEXPR";
X		deb("%d.LEXPR =>\n",anum);
X	    }
X#endif
X	    str = eval(argptr.arg_arg,Null(STR***),-1);
X	    if (!str)
X		fatal("panic: A_LEXPR");
X	    goto do_crement;
X	case A_LVAL:
X#ifdef DEBUGGING
X	    if (debug & 8) {
X		sprintf(buf,"LVAL $%s",argptr.arg_stab->stab_name);
X		tmps = buf;
X	    }
X#endif
X	    str = STAB_STR(argptr.arg_stab);
X	    if (!str)
X		fatal("panic: A_LVAL");
X	  do_crement:
X	    assigning = TRUE;
X	    if (argflags & AF_PRE) {
X		if (argflags & AF_UP)
X		    str_inc(str);
X		else
X		    str_dec(str);
X		STABSET(str);
X		sarg[anum] = str;
X		str = arg->arg_ptr.arg_str;
X	    }
X	    else if (argflags & AF_POST) {
X		sarg[anum] = str_static(str);
X		if (argflags & AF_UP)
X		    str_inc(str);
X		else
X		    str_dec(str);
X		STABSET(str);
X		str = arg->arg_ptr.arg_str;
X	    }
X	    else {
X		sarg[anum] = str;
X	    }
X	    break;
X	case A_LARYLEN:
X	    str = sarg[anum] =
X	      argptr.arg_stab->stab_array->ary_magic;
X#ifdef DEBUGGING
X	    tmps = "LARYLEN";
X#endif
X	    if (!str)
X		fatal("panic: A_LEXPR");
X	    goto do_crement;
X	case A_ARYLEN:
X	    stab = argptr.arg_stab;
X	    sarg[anum] = stab->stab_array->ary_magic;
X	    str_numset(sarg[anum],(double)(stab->stab_array->ary_fill+arybase));
X#ifdef DEBUGGING
X	    tmps = "ARYLEN";
X#endif
X	    break;
X	case A_SINGLE:
X	    sarg[anum] = argptr.arg_str;
X#ifdef DEBUGGING
X	    tmps = "SINGLE";
X#endif
X	    break;
X	case A_DOUBLE:
X	    (void) interp(str,str_get(argptr.arg_str));
X	    sarg[anum] = str;
X#ifdef DEBUGGING
X	    tmps = "DOUBLE";
X#endif
X	    break;
X	case A_BACKTICK:
X	    tmps = str_get(argptr.arg_str);
X	    fp = popen(str_get(interp(str,tmps)),"r");
X	    tmpstr = str_new(80);
X	    str_set(str,"");
X	    if (fp) {
X		while (str_gets(tmpstr,fp) != Nullch) {
X		    str_scat(str,tmpstr);
X		}
X		statusvalue = pclose(fp);
X	    }
X	    else
X		statusvalue = -1;
X	    str_free(tmpstr);
X
X	    sarg[anum] = str;
X#ifdef DEBUGGING
X	    tmps = "BACK";
X#endif
X	    break;
X	case A_INDREAD:
X	    last_in_stab = stabent(str_get(STAB_STR(argptr.arg_stab)),TRUE);
X	    goto do_read;
X	case A_GLOB:
X	    argflags |= AF_POST;	/* enable newline chopping */
X	case A_READ:
X	    last_in_stab = argptr.arg_stab;
X	  do_read:
X	    fp = Nullfp;
X	    if (last_in_stab->stab_io) {
X		fp = last_in_stab->stab_io->fp;
X		if (!fp) {
X		    if (last_in_stab->stab_io->flags & IOF_ARGV) {
X			if (last_in_stab->stab_io->flags & IOF_START) {
X			    last_in_stab->stab_io->flags &= ~IOF_START;
X			    last_in_stab->stab_io->lines = 0;
X			    if (alen(last_in_stab->stab_array) < 0) {
X				tmpstr = str_make("-");	/* assume stdin */
X				apush(last_in_stab->stab_array, tmpstr);
X			    }
X			}
X			fp = nextargv(last_in_stab);
X			if (!fp)  /* Note: fp != last_in_stab->stab_io->fp */
X			    do_close(last_in_stab,FALSE);  /* now it does */
X		    }
X		    else if (argtype == A_GLOB) {
X			(void) interp(str,str_get(last_in_stab->stab_val));
X			tmps = str->str_ptr;
X			if (*tmps == '!')
X			    sprintf(tokenbuf,"%s|",tmps+1);
X			else {
X			    if (*tmps == ';')
X				sprintf(tokenbuf, "%s", tmps+1);
X			    else
X				sprintf(tokenbuf, "echo %s", tmps);
X			    strcat(tokenbuf,
X			      "|tr -s ' \t\f\r' '\\012\\012\\012\\012'|");
X			}
X			do_open(last_in_stab,tokenbuf);
X			fp = last_in_stab->stab_io->fp;
X		    }
X		}
X	    }
X	    if (!fp && dowarn)
X		warn("Read on closed filehandle <%s>",last_in_stab->stab_name);
X	  keepgoing:
X	    if (!fp)
X		sarg[anum] = &str_no;
X	    else if (!str_gets(str,fp)) {
X		if (last_in_stab->stab_io->flags & IOF_ARGV) {
X		    fp = nextargv(last_in_stab);
X		    if (fp)
X			goto keepgoing;
X		    do_close(last_in_stab,FALSE);
X		    last_in_stab->stab_io->flags |= IOF_START;
X		}
X		else if (argflags & AF_POST) {
X		    do_close(last_in_stab,FALSE);
X		}
X		if (fp == stdin) {
X		    clearerr(fp);
X		}
X		sarg[anum] = &str_no;
X		if (retary) {
X		    maxarg = anum - 1;
X		    maxsarg = maxarg + sargoff;
X		}
X		break;
X	    }
X	    else {
X		last_in_stab->stab_io->lines++;
X		sarg[anum] = str;
X		if (argflags & AF_POST) {
X		    if (str->str_cur > 0)
X			str->str_cur--;
X		    str->str_ptr[str->str_cur] = '\0';
X		}
X		if (retary) {
X		    sarg[anum] = str_static(sarg[anum]);
X		    anum++;
X		    if (anum > maxarg) {
X			maxarg = anum + anum;
X			maxsarg = maxarg + sargoff;
X			sarg = (STR **)saferealloc((char*)(sarg-sargoff),
X			  (maxsarg+2+cushion) * sizeof(STR*)) + sargoff;
X		    }
X		    goto keepgoing;
X		}
X	    }
X	    if (retary) {
X		maxarg = anum - 1;
X		maxsarg = maxarg + sargoff;
X	    }
X#ifdef DEBUGGING
X	    tmps = "READ";
X#endif
X	    break;
X	}
X#ifdef DEBUGGING
X	if (debug & 8)
X	    deb("%d.%s = '%s'\n",anum,tmps,str_peek(sarg[anum]));
X#endif
X    }
X    switch (optype) {
X    case O_ITEM:
X	if (maxarg > arg->arg_len)
X	    goto array_return;
X	if (str != sarg[1])
X	    str_sset(str,sarg[1]);
X	STABSET(str);
X	break;
X    case O_ITEM2:
X	if (str != sarg[--anum])
X	    str_sset(str,sarg[anum]);
X	STABSET(str);
X	break;
X    case O_ITEM3:
X	if (str != sarg[--anum])
X	    str_sset(str,sarg[anum]);
X	STABSET(str);
X	break;
X    case O_CONCAT:
X	if (str != sarg[1])
X	    str_sset(str,sarg[1]);
X	str_scat(str,sarg[2]);
X	STABSET(str);
X	break;
X    case O_REPEAT:
X	if (str != sarg[1])
X	    str_sset(str,sarg[1]);
X	anum = (int)str_gnum(sarg[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	str_sset(str, do_match(arg,
X	  retary,sarg,&maxsarg,sargoff,cushion));
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;
X	}
X	STABSET(str);
X	break;
X    case O_NMATCH:
X	str_sset(str, do_match(arg,
X	  retary,sarg,&maxsarg,sargoff,cushion));
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;	/* ignore negation */
X	}
X	str_set(str, str_true(str) ? No : Yes);
X	STABSET(str);
X	break;
X    case O_SUBST:
X	value = (double) do_subst(str, arg);
X	str = arg->arg_ptr.arg_str;
X	goto donumset;
X    case O_NSUBST:
X	str_set(arg->arg_ptr.arg_str, do_subst(str, arg) ? No : Yes);
X	str = arg->arg_ptr.arg_str;
X	break;
X    case O_ASSIGN:
X	if (arg[1].arg_flags & AF_SPECIAL)
X	    do_assign(str,arg,sarg);
X	else {
X	    if (str != sarg[2])
X		str_sset(str, sarg[2]);
X	    STABSET(str);
X	}
X	break;
X    case O_CHOP:
X	tmps = str_get(str);
X	tmps += str->str_cur - (str->str_cur != 0);
X	str_set(arg->arg_ptr.arg_str,tmps);	/* remember last char */
X	*tmps = '\0';				/* wipe it out */
X	str->str_cur = tmps - str->str_ptr;
X	str->str_nok = 0;
X	str = arg->arg_ptr.arg_str;
X	break;
X    case O_STUDY:
X	value = (double)do_study(str);
X	str = arg->arg_ptr.arg_str;
X	goto donumset;
X    case O_MULTIPLY:
X	value = str_gnum(sarg[1]);
X	value *= str_gnum(sarg[2]);
X	goto donumset;
X    case O_DIVIDE:
X    	if ((value = str_gnum(sarg[2])) == 0.0)
X    	    fatal("Illegal division by zero");
X	value = str_gnum(sarg[1]) / value;
X	goto donumset;
X    case O_MODULO:
X    	if ((tmplong = (unsigned long) str_gnum(sarg[2])) == 0L)
X    	    fatal("Illegal modulus zero");
X	value = str_gnum(sarg[1]);
X	value = (double)(((unsigned long)value) % tmplong);
X	goto donumset;
X    case O_ADD:
X	value = str_gnum(sarg[1]);
X	value += str_gnum(sarg[2]);
X	goto donumset;
X    case O_SUBTRACT:
X	value = str_gnum(sarg[1]);
X	value -= str_gnum(sarg[2]);
X	goto donumset;
X    case O_LEFT_SHIFT:
X	value = str_gnum(sarg[1]);
X	anum = (int)str_gnum(sarg[2]);
X	value = (double)(((unsigned long)value) << anum);
X	goto donumset;
X    case O_RIGHT_SHIFT:
X	value = str_gnum(sarg[1]);
X	anum = (int)str_gnum(sarg[2]);
X	value = (double)(((unsigned long)value) >> anum);
X	goto donumset;
X    case O_LT:
X	value = str_gnum(sarg[1]);
X	value = (double)(value < str_gnum(sarg[2]));
X	goto donumset;
X    case O_GT:
X	value = str_gnum(sarg[1]);
X	value = (double)(value > str_gnum(sarg[2]));
X	goto donumset;
X    case O_LE:
X	value = str_gnum(sarg[1]);
X	value = (double)(value <= str_gnum(sarg[2]));
X	goto donumset;
X    case O_GE:
X	value = str_gnum(sarg[1]);
X	value = (double)(value >= str_gnum(sarg[2]));
X	goto donumset;
X    case O_EQ:
X	value = str_gnum(sarg[1]);
X	value = (double)(value == str_gnum(sarg[2]));
X	goto donumset;
X    case O_NE:
X	value = str_gnum(sarg[1]);
X	value = (double)(value != str_gnum(sarg[2]));
X	goto donumset;
X    case O_BIT_AND:
X	value = str_gnum(sarg[1]);
X	value = (double)(((unsigned long)value) &
X	    (unsigned long)str_gnum(sarg[2]));
X	goto donumset;
X    case O_XOR:
X	value = str_gnum(sarg[1]);
X	value = (double)(((unsigned long)value) ^
X	    (unsigned long)str_gnum(sarg[2]));
X	goto donumset;
X    case O_BIT_OR:
X	value = str_gnum(sarg[1]);
X	value = (double)(((unsigned long)value) |
X	    (unsigned long)str_gnum(sarg[2]));
X	goto donumset;
X    case O_AND:
X	if (str_true(sarg[1])) {
X	    anum = 2;
X	    optype = O_ITEM2;
X	    argflags = arg[anum].arg_flags;
X	    argtype = arg[anum].arg_type;
X	    argptr = arg[anum].arg_ptr;
X	    maxarg = anum = 1;
X	    goto re_eval;
X	}
X	else {
X	    if (assigning) {
X		str_sset(str, sarg[1]);
X		STABSET(str);
X	    }
X	    else
X		str = sarg[1];
X	    break;
X	}
X    case O_OR:
X	if (str_true(sarg[1])) {
X	    if (assigning) {
X		str_sset(str, sarg[1]);
X		STABSET(str);
X	    }
X	    else
X		str = sarg[1];
X	    break;
X	}
X	else {
X	    anum = 2;
X	    optype = O_ITEM2;
X	    argflags = arg[anum].arg_flags;
X	    argtype = arg[anum].arg_type;
X	    argptr = arg[anum].arg_ptr;
X	    maxarg = anum = 1;
X	    goto re_eval;
X	}
X    case O_COND_EXPR:
X	anum = (str_true(sarg[1]) ? 2 : 3);
X	optype = (anum == 2 ? O_ITEM2 : O_ITEM3);
X	argflags = arg[anum].arg_flags;
X	argtype = arg[anum].arg_type;
X	argptr = arg[anum].arg_ptr;
X	maxarg = anum = 1;
X	goto re_eval;
X    case O_COMMA:
X	str = sarg[2];
X	break;
X    case O_NEGATE:
X	value = -str_gnum(sarg[1]);
X	goto donumset;
X    case O_NOT:
X	value = (double) !str_true(sarg[1]);
X	goto donumset;
X    case O_COMPLEMENT:
X	value = (double) ~(long)str_gnum(sarg[1]);
X	goto donumset;
X    case O_SELECT:
X	if (arg[1].arg_type == A_LVAL)
X	    defoutstab = arg[1].arg_ptr.arg_stab;
X	else
X	    defoutstab = stabent(str_get(sarg[1]),TRUE);
X	if (!defoutstab->stab_io)
X	    defoutstab->stab_io = stio_new();
X	curoutstab = defoutstab;
X	str_set(str,curoutstab->stab_io->fp ? 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_LVAL)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(sarg[1]),TRUE);
X	if (!stab->stab_io) {
X	    str_set(str, No);
X	    STABSET(str);
X	    break;
X	}
X	curoutstab = stab;
X	fp = stab->stab_io->fp;
X	debarg = arg;
X	if (stab->stab_io->fmt_stab)
X	    form = stab->stab_io->fmt_stab->stab_form;
X	else
X	    form = stab->stab_form;
X	if (!form || !fp) {
X	    str_set(str, No);
X	    STABSET(str);
X	    break;
X	}
X	format(&outrec,form);
X	do_write(&outrec,stab->stab_io);
X	if (stab->stab_io->flags & IOF_FLUSH)
X	    fflush(fp);
X	str_set(str, Yes);
X	STABSET(str);
X	break;
X    case O_OPEN:
X	if (arg[1].arg_type == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(sarg[1]),TRUE);
X	if (do_open(stab,str_get(sarg[2]))) {
X	    value = (double)forkprocess;
X	    stab->stab_io->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 (arg[1].arg_type == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(sarg[1]),TRUE);
X	str_set(str, do_close(stab,TRUE) ? Yes : No );
X	STABSET(str);
X	break;
X    case O_EACH:
X	str_sset(str,do_each(arg[1].arg_ptr.arg_stab->stab_hash,
X	  retary,sarg,&maxsarg,sargoff,cushion));
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;
X	}
X	STABSET(str);
X	break;
X    case O_VALUES:
X    case O_KEYS:
X	value = (double) do_kv(arg[1].arg_ptr.arg_stab->stab_hash, optype,
X	  retary,sarg,&maxsarg,sargoff,cushion);
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;
X	}
X	goto donumset;
X    case O_ARRAY:
X	if (maxarg == 1) {
X	    ary = arg[1].arg_ptr.arg_stab->stab_array;
X	    maxarg = ary->ary_fill;
X	    maxsarg = maxarg + sargoff;
X	    if (retary) { /* array wanted */
X		sarg = (STR **)saferealloc((char*)(sarg-sargoff),
X		  (maxsarg+3+cushion)*sizeof(STR*)) + sargoff;
X		for (anum = 0; anum <= maxarg; anum++) {
X		    sarg[anum+1] = str = afetch(ary,anum);
X		}
X		maxarg++;
X		maxsarg++;
X		goto array_return;
X	    }
X	    else
X		str = afetch(ary,maxarg);
X	}
X	else
X	    str = afetch(arg[2].arg_ptr.arg_stab->stab_array,
X		((int)str_gnum(sarg[1])) - arybase);
X	if (!str)
X	    str = &str_no;
X	break;
X    case O_DELETE:
X	tmpstab = arg[2].arg_ptr.arg_stab;		/* XXX */
X	str = hdelete(tmpstab->stab_hash,str_get(sarg[1]));
X	if (!str)
X	    str = &str_no;
X	break;
X    case O_HASH:
X	tmpstab = arg[2].arg_ptr.arg_stab;		/* XXX */
X	str = hfetch(tmpstab->stab_hash,str_get(sarg[1]));
X	if (!str)
X	    str = &str_no;
X	break;
X    case O_LARRAY:
X	anum = ((int)str_gnum(sarg[1])) - arybase;
X	str = afetch(arg[2].arg_ptr.arg_stab->stab_array,anum);
X	if (!str || str == &str_no) {
X	    str = str_new(0);
X	    astore(arg[2].arg_ptr.arg_stab->stab_array,anum,str);
X	}
X	break;
X    case O_LHASH:
X	tmpstab = arg[2].arg_ptr.arg_stab;
X	str = hfetch(tmpstab->stab_hash,str_get(sarg[1]));
X	if (!str) {
X	    str = str_new(0);
X	    hstore(tmpstab->stab_hash,str_get(sarg[1]),str);
X	}
X	if (tmpstab == envstab) {	/* heavy wizardry going on here */
X	    str->str_link.str_magic = tmpstab;/* str is now magic */
X	    envname = savestr(str_get(sarg[1]));
X					/* he threw the brick up into the air */
X	}
X	else if (tmpstab == sigstab) {	/* same thing, only different */
X	    str->str_link.str_magic = tmpstab;
X	    signame = savestr(str_get(sarg[1]));
X	}
X	break;
X    case O_PUSH:
X	if (arg[1].arg_flags & AF_SPECIAL)
X	    str = do_push(arg,arg[2].arg_ptr.arg_stab->stab_array);
X	else {
X	    str = str_new(0);		/* must copy the STR */
X	    str_sset(str,sarg[1]);
X	    apush(arg[2].arg_ptr.arg_stab->stab_array,str);
X	}
X	break;
X    case O_POP:
X	str = apop(arg[1].arg_ptr.arg_stab->stab_array);
X	if (!str) {
X	    str = &str_no;
X	    break;
X	}
X#ifdef STRUCTCOPY
X	*(arg->arg_ptr.arg_str) = *str;
X#else
X	bcopy((char*)str, (char*)arg->arg_ptr.arg_str, sizeof *str);
X#endif
X	safefree((char*)str);
X	str = arg->arg_ptr.arg_str;
X	break;
X    case O_SHIFT:
X	str = ashift(arg[1].arg_ptr.arg_stab->stab_array);
X	if (!str) {
X	    str = &str_no;
X	    break;
X	}
X#ifdef STRUCTCOPY
X	*(arg->arg_ptr.arg_str) = *str;
X#else
X	bcopy((char*)str, (char*)arg->arg_ptr.arg_str, sizeof *str);
X#endif
X	safefree((char*)str);
X	str = arg->arg_ptr.arg_str;
X	break;
X    case O_SPLIT:
X	value = (double) do_split(arg[2].arg_ptr.arg_spat,
X	  retary,sarg,&maxsarg,sargoff,cushion);
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;
X	}
X	goto donumset;
X    case O_LENGTH:
X	value = (double) str_len(sarg[1]);
X	goto donumset;
X    case O_SPRINTF:
X	sarg[maxsarg+1] = Nullstr;
X	do_sprintf(str,arg->arg_len,sarg);
X	break;
X    case O_SUBSTR:
X	anum = ((int)str_gnum(sarg[2])) - arybase;
X	for (tmps = str_get(sarg[1]); *tmps && anum > 0; tmps++,anum--) ;
X	anum = (int)str_gnum(sarg[3]);
X	if (anum >= 0 && strlen(tmps) > anum)
X	    str_nset(str, tmps, anum);
X	else
X	    str_set(str, tmps);
X	break;
X    case O_JOIN:
X	if (arg[2].arg_flags & AF_SPECIAL && arg[2].arg_type == A_EXPR)
X	    do_join(arg,str_get(sarg[1]),str);
X	else
X	    ajoin(arg[2].arg_ptr.arg_stab->stab_array,str_get(sarg[1]),str);
X	break;
X    case O_SLT:
X	tmps = str_get(sarg[1]);
X	value = (double) strLT(tmps,str_get(sarg[2]));
X	goto donumset;
X    case O_SGT:
X	tmps = str_get(sarg[1]);
X	value = (double) strGT(tmps,str_get(sarg[2]));
X	goto donumset;
X    case O_SLE:
X	tmps = str_get(sarg[1]);
X	value = (double) strLE(tmps,str_get(sarg[2]));
X	goto donumset;
X    case O_SGE:
X	tmps = str_get(sarg[1]);
X	value = (double) strGE(tmps,str_get(sarg[2]));
X	goto donumset;
X    case O_SEQ:
X	tmps = str_get(sarg[1]);
X	value = (double) strEQ(tmps,str_get(sarg[2]));
X	goto donumset;
X    case O_SNE:
X	tmps = str_get(sarg[1]);
X	value = (double) strNE(tmps,str_get(sarg[2]));
X	goto donumset;
X    case O_SUBR:
X	str_sset(str,do_subr(arg,sarg));
X	STABSET(str);
X	break;
X    case O_SORT:
X	if (maxarg <= 1)
X	    stab = defoutstab;
X	else {
X	    if (arg[2].arg_type == A_WORD)
X		stab = arg[2].arg_ptr.arg_stab;
X	    else
X		stab = stabent(str_get(sarg[2]),TRUE);
X	    if (!stab)
X		stab = defoutstab;
X	}
X	value = (double)do_sort(arg,stab,
X	  retary,sarg,&maxsarg,sargoff,cushion);
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;
X	}
X	goto donumset;
X    case O_PRTF:
X    case O_PRINT:
X	if (maxarg <= 1)
X	    stab = defoutstab;
X	else {
X	    if (arg[2].arg_type == A_WORD)
X		stab = arg[2].arg_ptr.arg_stab;
X	    else
X		stab = stabent(str_get(sarg[2]),TRUE);
X	    if (!stab)
X		stab = defoutstab;
X	}
X	if (!stab->stab_io || !(fp = stab->stab_io->fp))
X	    value = 0.0;
X	else {
X	    if (arg[1].arg_flags & AF_SPECIAL)
X		value = (double)do_aprint(arg,fp);
X	    else {
X		value = (double)do_print(sarg[1],fp);
X		if (ors && optype == O_PRINT)
X		    fputs(ors, fp);
X	    }
X	    if (stab->stab_io->flags & IOF_FLUSH)
X		fflush(fp);
X	}
X	goto donumset;
X    case O_CHDIR:
X	tmps = str_get(sarg[1]);
X	if (!tmps || !*tmps)
X	    tmps = getenv("HOME");
X	if (!tmps || !*tmps)
X	    tmps = getenv("LOGDIR");
X	value = (double)(chdir(tmps) >= 0);
X	goto donumset;
X    case O_DIE:
X	tmps = str_get(sarg[1]);
X	if (!tmps || !*tmps)
X	    exit(1);
X	fatal("%s",str_get(sarg[1]));
X	value = 0.0;
X	goto donumset;
X    case O_EXIT:
X	exit((int)str_gnum(sarg[1]));
X	value = 0.0;
X	goto donumset;
X    case O_RESET:
X	str_reset(str_get(sarg[1]));
X	value = 1.0;
X	goto donumset;
X    case O_LIST:
X	if (arg->arg_flags & AF_LOCAL)
X	    savelist(sarg,maxsarg);
X	if (maxarg > 0)
X	    str = sarg[maxsarg];	/* unwanted list, return last item */
X	else
X	    str = &str_no;
X	if (retary)
X	    goto array_return;
X	break;
X    case O_EOF:
X	if (maxarg <= 0)
X	    stab = last_in_stab;
X	else if (arg[1].arg_type == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(sarg[1]),TRUE);
X	str_set(str, do_eof(stab) ? Yes : No);
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_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(sarg[1]),TRUE);
X	value = (double)do_tell(stab);
X	goto donumset;
X    case O_SEEK:
X	if (arg[1].arg_type == A_WORD)
X	    stab = arg[1].arg_ptr.arg_stab;
X	else
X	    stab = stabent(str_get(sarg[1]),TRUE);
X	value = str_gnum(sarg[2]);
X	str_set(str, do_seek(stab,
X	  (long)value, (int)str_gnum(sarg[3]) ) ? Yes : No);
X	STABSET(str);
X	break;
X    case O_REDO:
X    case O_NEXT:
X    case O_LAST:
X	if (maxarg > 0) {
X	    tmps = str_get(sarg[1]);
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	longjmp(loop_stack[loop_ptr].loop_env, optype);
X    case O_GOTO:/* shudder */
X	goto_targ = str_get(sarg[1]);
X	longjmp(top_env, 1);
X    case O_INDEX:
X	tmps = str_get(sarg[1]);
X	if (!(tmps2 = fbminstr(tmps, tmps + sarg[1]->str_cur, sarg[2])))
X	    value = (double)(-1 + arybase);
X	else
X	    value = (double)(tmps2 - tmps + arybase);
X	goto donumset;
X    case O_TIME:
X	value = (double) time(Null(long*));
X	goto donumset;
X    case O_TMS:
X	value = (double) do_tms(retary,sarg,&maxsarg,sargoff,cushion);
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;
X	}
X	goto donumset;
X    case O_LOCALTIME:
X	when = (long)str_gnum(sarg[1]);
X	value = (double)do_time(localtime(&when),
X	  retary,sarg,&maxsarg,sargoff,cushion);
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;
X	}
X	goto donumset;
X    case O_GMTIME:
X	when = (long)str_gnum(sarg[1]);
X	value = (double)do_time(gmtime(&when),
X	  retary,sarg,&maxsarg,sargoff,cushion);
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;
X	}
X	goto donumset;
X    case O_STAT:
X	value = (double) do_stat(arg,
X	  retary,sarg,&maxsarg,sargoff,cushion);
X	if (retary) {
X	    sarg = *retary;	/* they realloc it */
X	    goto array_return;
X	}
X	goto donumset;
X    case O_CRYPT:
X#ifdef CRYPT
X	tmps = str_get(sarg[1]);
X	str_set(str,crypt(tmps,str_get(sarg[2])));
X#else
X	fatal(
X	  "The crypt() function is unimplemented due to excessive paranoia.");
X#endif
X	break;
X    case O_EXP:
X	value = exp(str_gnum(sarg[1]));
X	goto donumset;
X    case O_LOG:
X	value = log(str_gnum(sarg[1]));
X	goto donumset;
X    case O_SQRT:
X	value = sqrt(str_gnum(sarg[1]));
X	goto donumset;
X    case O_INT:
X	value = str_gnum(sarg[1]);
X	if (value >= 0.0)
X	    modf(value,&value);
X	else {
X	    modf(-value,&value);
X	    value = -value;
X	}
X	goto donumset;
X    case O_ORD:
X	value = (double) *str_get(sarg[1]);
X	goto donumset;
X    case O_SLEEP:
X	tmps = str_get(sarg[1]);
X	time(&when);
X	if (!tmps || !*tmps)
X	    sleep((32767<<16)+32767);
X	else
X	    sleep((unsigned)atoi(tmps));
X	value = (double)when;
X	time(&when);
X	value = ((double)when) - value;
X	goto donumset;
X    case O_FLIP:
X	if (str_true(sarg[1])) {
X	    str_numset(str,0.0);
X	    anum = 2;
X	    arg->arg_type = optype = O_FLOP;
X	    arg[2].arg_flags &= ~AF_SPECIAL;
X	    arg[1].arg_flags |= AF_SPECIAL;
X	    argflags = arg[2].arg_flags;
X	    argtype = arg[2].arg_type;
X	    argptr = arg[2].arg_ptr;
X	    goto re_eval;
X	}
X	str_set(str,"");
X	break;
X    case O_FLOP:
X	str_inc(str);
X	if (str_true(sarg[2])) {
X	    arg->arg_type = O_FLIP;
X	    arg[1].arg_flags &= ~AF_SPECIAL;
X	    arg[2].arg_flags |= AF_SPECIAL;
X	    str_cat(str,"E0");
X	}
X	break;
X    case O_FORK:
X	value = (double)fork();
X	goto donumset;
X    case O_WAIT:
X	ihand = signal(SIGINT, SIG_IGN);
X	qhand = signal(SIGQUIT, SIG_IGN);
X	value = (double)wait(&argflags);
X	signal(SIGINT, ihand);
X	signal(SIGQUIT, qhand);
X	statusvalue = (unsigned short)argflags;
X	goto donumset;
X    case O_SYSTEM:
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	    ihand = signal(SIGINT, SIG_IGN);
X	    qhand = signal(SIGQUIT, SIG_IGN);
X	    while ((argtype = wait(&argflags)) != anum && argtype != -1)
X		;
X	    signal(SIGINT, ihand);
X	    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_flags & AF_SPECIAL)
X	    value = (double)do_aexec(arg);
X	else {
X	    value = (double)do_exec(str_static(sarg[1]));
X	}
X	_exit(-1);
X    case O_EXEC:
X	if (arg[1].arg_flags & AF_SPECIAL)
X	    value = (double)do_aexec(arg);
X	else {
X	    value = (double)do_exec(str_static(sarg[1]));
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(sarg[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	if (arg[1].arg_flags & AF_SPECIAL)
X	    value = (double)apply(optype,arg,Null(STR**));
X	else {
X	    sarg[2] = Nullstr;
X	    value = (double)apply(optype,arg,sarg);
X	}
X	goto donumset;
X    case O_UMASK:
X	value = (double)umask((int)str_gnum(sarg[1]));
X	goto donumset;
X    case O_RENAME:
X	tmps = str_get(sarg[1]);
X#ifdef RENAME
X	value = (double)(rename(tmps,str_get(sarg[2])) >= 0);
X#else
X	tmps2 = str_get(sarg[2]);
X	if (euid || stat(tmps2,&statbuf) < 0 ||
X	  (statbuf.st_mode & S_IFMT) != S_IFDIR )
X	    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(sarg[1]);
X	value = (double)(link(tmps,str_get(sarg[2])) >= 0);
X	goto donumset;
X    case O_UNSHIFT:
X	ary = arg[2].arg_ptr.arg_stab->stab_array;
X	if (arg[1].arg_flags & AF_SPECIAL)
X	    do_unshift(arg,ary);
X	else {
X	    str = str_new(0);		/* must copy the STR */
X	    str_sset(str,sarg[1]);
X	    aunshift(ary,1);
X	    astore(ary,0,str);
X	}
X	value = (double)(ary->ary_fill + 1);
X	break;
X    case O_DOFILE:
X    case O_EVAL:
X	str_sset(str,
X	    do_eval(arg[1].arg_type != A_NULL ? sarg[1] : defstab->stab_val,
X	      optype) );
X	STABSET(str);
X	break;
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	str = &str_no;
X	if (mystat(arg,sarg[1]) < 0)
X	    break;
X	if (cando(anum,argtype))
X	    str = &str_yes;
X	break;
X
X    case O_FTIS:
X	if (mystat(arg,sarg[1]) >= 0)
X	    str = &str_yes;
X	else
X	    str = &str_no;
X	break;
X    case O_FTEOWNED:
X    case O_FTROWNED:
X	if (mystat(arg,sarg[1]) >= 0 &&
X	  statbuf.st_uid == (optype == O_FTEOWNED ? euid : uid) )
X	    str = &str_yes;
X	else
X	    str = &str_no;
X	break;
X    case O_FTZERO:
X	if (mystat(arg,sarg[1]) >= 0 && !statbuf.st_size)
X	    str = &str_yes;
X	else
X	    str = &str_no;
X	break;
X    case O_FTSIZE:
X	if (mystat(arg,sarg[1]) >= 0 && statbuf.st_size)
X	    str = &str_yes;
X	else
X	    str = &str_no;
X	break;
X
X    case O_FTSOCK:
X#ifdef S_IFSOCK
X	anum = S_IFSOCK;
X	goto check_file_type;
X#else
X	str = &str_no;
X	break;
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,sarg[1]) >= 0 &&
X	  (statbuf.st_mode & S_IFMT) == anum )
X	    str = &str_yes;
X	else
X	    str = &str_no;
X	break;
X    case O_FTPIPE:
X#ifdef S_IFIFO
X	anum = S_IFIFO;
X	goto check_file_type;
X#else
X	str = &str_no;
X	break;
X#endif
X    case O_FTLINK:
X#ifdef S_IFLNK
X	if (lstat(str_get(sarg[1]),&statbuf) >= 0 &&
X	  (statbuf.st_mode & S_IFMT) == S_IFLNK )
X	    str = &str_yes;
X	else
X#endif
X	    str = &str_no;
X	break;
X    case O_SYMLINK:
X#ifdef SYMLINK
X	tmps = str_get(sarg[1]);
X	value = (double)(symlink(tmps,str_get(sarg[2])) >= 0);
X	goto donumset;
X#else
X	fatal("Unsupported function symlink()");
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,sarg[1]) >= 0 && statbuf.st_mode & anum)
X	    str = &str_yes;
X	else
X	    str = &str_no;
X	break;
X    case O_FTTTY:
X	if (arg[1].arg_flags & AF_SPECIAL) {
X	    stab = arg[1].arg_ptr.arg_stab;
X	    tmps = "";
X	}
X	else
X	    stab = stabent(tmps = str_get(sarg[1]),FALSE);
X	if (stab && stab->stab_io && stab->stab_io->fp)
X	    anum = fileno(stab->stab_io->fp);
X	else if (isdigit(*tmps))
X	    anum = atoi(tmps);
X	else
X	    anum = -1;
X	if (isatty(anum))
X	    str = &str_yes;
X	else
X	    str = &str_no;
X	break;
X    case O_FTTEXT:
X    case O_FTBINARY:
X	str = do_fttext(arg,sarg[1]);
X	break;
X    }
X    if (retary) {
X	sarg[1] = str;
X	maxsarg = sargoff + 1;
X    }
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    goto freeargs;
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],maxsarg-sargoff);
X    }
X#endif
X    goto freeargs;
X
Xdonumset:
X    str_numset(str,value);
X    STABSET(str);
X    if (retary) {
X	sarg[1] = str;
X	maxsarg = sargoff + 1;
X    }
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
Xfreeargs:
X    sarg -= sargoff;
X    if (sarg != quicksarg) {
X	if (retary) {
X	    sarg[0] = &str_args;
X	    str_numset(sarg[0], (double)(maxsarg));
X	    sarg[maxsarg+1] = Nullstr;
X	    *retary = sarg;	/* up to them to free it */
X	}
X	else
X	    safefree((char*)sarg);
X    }
X    return str;
X}
X
Xint
Xingroup(gid,effective)
Xint gid;
Xint effective;
X{
X    if (gid == (effective ? getegid() : getgid()))
X	return TRUE;
X#ifdef GETGROUPS
X#ifndef NGROUPS
X#define NGROUPS 32
X#endif
X    {
X	GIDTYPE gary[NGROUPS];
X	int anum;
X
X	anum = getgroups(NGROUPS,gary);
X	while (--anum >= 0)
X	    if (gary[anum] == gid)
X		return TRUE;
X    }
X#endif
X    return FALSE;
X}
X
X/* Do the permissions allow some operation?  Assumes statbuf already set. */
X
Xint
Xcando(bit, effective)
Xint bit;
Xint effective;
X{
X    if ((effective ? euid : uid) == 0) {	/* root is special */
X	if (bit == S_IEXEC) {
X	    if (statbuf.st_mode & 0111 ||
X	      (statbuf.st_mode & S_IFMT) == S_IFDIR )
X		return TRUE;
X	}
X	else
X	    return TRUE;		/* root reads and writes anything */
X	return FALSE;
X    }
X    if (statbuf.st_uid == (effective ? euid : uid) ) {
X	if (statbuf.st_mode & bit)
X	    return TRUE;	/* ok as "user" */
X    }
X    else if (ingroup((int)statbuf.st_gid,effective)) {
X	if (statbuf.st_mode & bit >> 3)
X	    return TRUE;	/* ok as "group" */
X    }
X    else if (statbuf.st_mode & bit >> 6)
X	return TRUE;	/* ok as "other" */
X    return FALSE;
X}
!STUFFY!FUNK!
echo Extracting util.c
sed >util.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: util.c,v 2.0 88/06/05 00:15:11 root Exp $
X *
X * $Log:	util.c,v $
X * Revision 2.0  88/06/05  00:15:11  root
X * Baseline version 2.0.
X * 
X */
X
X#include "EXTERN.h"
X#include "perl.h"
X
X#define FLUSH
X
Xstatic char nomem[] = "Out of memory!\n";
X
X/* paranoid version of malloc */
X
X#ifdef DEBUGGING
Xstatic int an = 0;
X#endif
X
Xchar *
Xsafemalloc(size)
XMEM_SIZE size;
X{
X    char *ptr;
X    char *malloc();
X
X    ptr = malloc(size?size:1);	/* malloc(0) is NASTY on our system */
X#ifdef DEBUGGING
X    if (debug & 128)
X	fprintf(stderr,"0x%x: (%05d) malloc %d bytes\n",ptr,an++,size);
X#endif
X    if (ptr != Nullch)
X	return ptr;
X    else {
X	fputs(nomem,stdout) FLUSH;
X	exit(1);
X    }
X    /*NOTREACHED*/
X}
X
X/* paranoid version of realloc */
X
Xchar *
Xsaferealloc(where,size)
Xchar *where;
XMEM_SIZE size;
X{
X    char *ptr;
X    char *realloc();
X
X    if (!where)
X	fatal("Null realloc");
X    ptr = realloc(where,size?size:1);	/* realloc(0) is NASTY on our system */
X#ifdef DEBUGGING
X    if (debug & 128) {
X	fprintf(stderr,"0x%x: (%05d) rfree\n",where,an++);
X	fprintf(stderr,"0x%x: (%05d) realloc %d bytes\n",ptr,an++,size);
X    }
X#endif
X    if (ptr != Nullch)
X	return ptr;
X    else {
X	fputs(nomem,stdout) FLUSH;
X	exit(1);
X    }
X    /*NOTREACHED*/
X}
X
X/* safe version of free */
X
Xsafefree(where)
Xchar *where;
X{
X#ifdef DEBUGGING
X    if (debug & 128)
X	fprintf(stderr,"0x%x: (%05d) free\n",where,an++);
X#endif
X    if (where) {
X	free(where);
X    }
X}
X
X#ifdef NOTDEF
X/* safe version of string copy */
X
Xchar *
Xsafecpy(to,from,len)
Xchar *to;
Xregister char *from;
Xregister int len;
X{
X    register char *dest = to;
X
X    if (from != Nullch) 
X	for (len--; len && (*dest++ = *from++); len--) ;
X    *dest = '\0';
X    return to;
X}
X#endif /*NOTDEF*/
X
X#ifdef undef
X/* safe version of string concatenate, with \n deletion and space padding */
X
Xchar *
Xsafecat(to,from,len)
Xchar *to;
Xregister char *from;
Xregister int len;
X{
X    register char *dest = to;
X
X    len--;				/* leave room for null */
X    if (*dest) {
X	while (len && *dest++) len--;
X	if (len) {
X	    len--;
X	    *(dest-1) = ' ';
X	}
X    }
X    if (from != Nullch)
X	while (len && (*dest++ = *from++)) len--;
X    if (len)
X	dest--;
X    if (*(dest-1) == '\n')
X	dest--;
X    *dest = '\0';
X    return to;
X}
X#endif
X
X/* copy a string up to some (non-backslashed) delimiter, if any */
X
Xchar *
Xcpytill(to,from,delim)
Xregister char *to, *from;
Xregister int delim;
X{
X    for (; *from; from++,to++) {
X	if (*from == '\\') {
X	    if (from[1] == delim)
X		from++;
X	    else if (from[1] == '\\')
X		*to++ = *from++;
X	}
X	else if (*from == delim)
X	    break;
X	*to = *from;
X    }
X    *to = '\0';
X    return from;
X}
X
X/* return ptr to little string in big string, NULL if not found */
X/* This routine was donated by Corey Satten. */
X
Xchar *
Xinstr(big, little)
Xregister char *big;
Xregister char *little;
X{
X    register char *s, *x;
X    register int first = *little++;
X
X    if (!first)
X	return big;
X    while (*big) {
X	if (*big++ != first)
X	    continue;
X	for (x=big,s=little; *s; /**/ ) {
X	    if (!*x)
X		return Nullch;
X	    if (*s++ != *x++) {
X		s--;
X		break;
X	    }
X	}
X	if (!*s)
X	    return big-1;
X    }
X    return Nullch;
X}
X
X#ifdef NOTDEF
Xvoid
Xbmcompile(str)
XSTR *str;
X{
X    register char *s;
X    register char *table;
X    register int i;
X    register int len = str->str_cur;
X
X    str_grow(str,len+128);
X    s = str->str_ptr;
X    table = s + len;
X    for (i = 1; i < 128; i++) {
X	table[i] = len;
X    }
X    i = 0;
X    while (*s) {
X	if (!isascii(*s))
X	    return;
X	if (table[*s] == len)
X	    table[*s] = i;
X	s++,i++;
X    }
X    str->str_pok |= 2;		/* deep magic */
X}
X#endif /* NOTDEF */
X
Xstatic unsigned char freq[] = {
X	1,	2,	84,	151,	154,	155,	156,	157,
X	165,	246,	250,	3,	158,	7,	18,	29,
X	40,	51,	62,	73,	85,	96,	107,	118,
X	129,	140,	147,	148,	149,	150,	152,	153,
X	255,	182,	224,	205,	174,	176,	180,	217,
X	233,	232,	236,	187,	235,	228,	234,	226,
X	222,	219,	211,	195,	188,	193,	185,	184,
X	191,	183,	201,	229,	181,	220,	194,	162,
X	163,	208,	186,	202,	200,	218,	198,	179,
X	178,	214,	166,	170,	207,	199,	209,	206,
X	204,	160,	212,	216,	215,	192,	175,	173,
X	243,	172,	161,	190,	203,	189,	164,	230,
X	167,	248,	227,	244,	242,	255,	241,	231,
X	240,	253,	169,	210,	245,	237,	249,	247,
X	239,	168,	252,	251,	254,	238,	223,	221,
X	213,	225,	177,	197,	171,	196,	159,	4,
X	5,	6,	8,	9,	10,	11,	12,	13,
X	14,	15,	16,	17,	19,	20,	21,	22,
X	23,	24,	25,	26,	27,	28,	30,	31,
X	32,	33,	34,	35,	36,	37,	38,	39,
X	41,	42,	43,	44,	45,	46,	47,	48,
X	49,	50,	52,	53,	54,	55,	56,	57,
X	58,	59,	60,	61,	63,	64,	65,	66,
X	67,	68,	69,	70,	71,	72,	74,	75,
X	76,	77,	78,	79,	80,	81,	82,	83,
X	86,	87,	88,	89,	90,	91,	92,	93,
X	94,	95,	97,	98,	99,	100,	101,	102,
X	103,	104,	105,	106,	108,	109,	110,	111,
X	112,	113,	114,	115,	116,	117,	119,	120,
X	121,	122,	123,	124,	125,	126,	127,	128,
X	130,	131,	132,	133,	134,	135,	136,	137,
X	138,	139,	141,	142,	143,	144,	145,	146
X};
X
Xvoid
Xfbmcompile(str)
XSTR *str;
X{
X    register char *s;
X    register char *table;
X    register int i;
X    register int len = str->str_cur;
X    int rarest = 0;
X    int frequency = 256;
X
X    str_grow(str,len+128);
X    table = str->str_ptr + len;		/* actually points at final '\0' */
X    s = table - 1;
X    for (i = 1; i < 128; i++) {
X	table[i] = len;
X    }
X    i = 0;
X    while (s >= str->str_ptr) {
X	if (!isascii(*s))
X	    return;
X	if (table[*s] == len)
X	    table[*s] = i;
X	s--,i++;
X    }
X    str->str_pok |= 2;		/* deep magic */
X
X    s = str->str_ptr;		/* deeper magic */
X    for (i = 0; i < len; i++) {
X	if (freq[s[i]] < frequency) {
X	    rarest = i;
X	    frequency = freq[s[i]];
X	}
X    }
X    str->str_rare = s[rarest];
X    str->str_prev = rarest;
X#ifdef DEBUGGING
X    if (debug & 512)
X	fprintf(stderr,"rarest char %c at %d\n",str->str_rare, str->str_prev);
X#endif
X}
X
X#ifdef NOTDEF
Xchar *
Xbminstr(big, biglen, littlestr)
Xregister char *big;
Xint biglen;
XSTR *littlestr;
X{
X    register char *s;
X    register int tmp;
X    register char *little = littlestr->str_ptr;
X    int littlelen = littlestr->str_cur;
X    register char *table = little + littlelen;
X
X    s = big + biglen - littlelen;
X    while (s >= big) {
X	if (tmp = table[*s]) {
X	    s -= tmp;
X	}
X	else {
X	    if (strnEQ(s,little,littlelen))
X		return s;
X	    s--;
X	}
X    }
X    return Nullch;
X}
X#endif /* NOTDEF */
X
Xchar *
Xfbminstr(big, bigend, littlestr)
Xchar *big;
Xregister char *bigend;
XSTR *littlestr;
X{
X    register char *s;
X    register int tmp;
X    register int littlelen;
X    register char *little;
X    register char *table;
X    register char *olds;
X    register char *oldlittle;
X    register int min;
X    char *screaminstr();
X
X    if (littlestr->str_pok != 3)
X	return instr(big,littlestr->str_ptr);
X
X    littlelen = littlestr->str_cur;
X    table = littlestr->str_ptr + littlelen;
X    s = big + --littlelen;
X    oldlittle = little = table - 1;
X    while (s < bigend) {
X      top:
X	if (tmp = table[*s]) {
X	    s += tmp;
X	}
X	else {
X	    tmp = littlelen;	/* less expensive than calling strncmp() */
X	    olds = s;
X	    while (tmp--) {
X		if (*--s == *--little)
X		    continue;
X		s = olds + 1;	/* here we pay the price for failure */
X		little = oldlittle;
X		if (s < bigend)	/* fake up continue to outer loop */
X		    goto top;
X		return Nullch;
X	    }
X	    return s;
X	}
X    }
X    return Nullch;
X}
X
Xchar *
Xscreaminstr(bigstr, littlestr)
XSTR *bigstr;
XSTR *littlestr;
X{
X    register char *s, *x;
X    register char *big = bigstr->str_ptr;
X    register int pos;
X    register int previous;
X    register int first;
X    register char *little;
X
X    if ((pos = screamfirst[littlestr->str_rare]) < 0) 
X	return Nullch;
X    little = littlestr->str_ptr;
X    first = *little++;
X    previous = littlestr->str_prev;
X    big -= previous;
X    while (pos < previous) {
X	if (!(pos += screamnext[pos]))
X	    return Nullch;
X    }
X    do {
X	if (big[pos] != first)
X	    continue;
X	for (x=big+pos+1,s=little; *s; /**/ ) {
X	    if (!*x)
X		return Nullch;
X	    if (*s++ != *x++) {
X		s--;
X		break;
X	    }
X	}
X	if (!*s)
X	    return big+pos;
X    } while (pos += screamnext[pos]);
X    return Nullch;
X}
X
X/* copy a string to a safe spot */
X
Xchar *
Xsavestr(str)
Xchar *str;
X{
X    register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1));
X
X    (void)strcpy(newaddr,str);
X    return newaddr;
X}
X
X/* grow a static string to at least a certain length */
X
Xvoid
Xgrowstr(strptr,curlen,newlen)
Xchar **strptr;
Xint *curlen;
Xint newlen;
X{
X    if (newlen > *curlen) {		/* need more room? */
X	if (*curlen)
X	    *strptr = saferealloc(*strptr,(MEM_SIZE)newlen);
X	else
X	    *strptr = safemalloc((MEM_SIZE)newlen);
X	*curlen = newlen;
X    }
X}
X
Xextern int errno;
X
X/*VARARGS1*/
Xmess(pat,a1,a2,a3,a4)
Xchar *pat;
X{
X    char *s;
X
X    s = tokenbuf;
X    sprintf(s,pat,a1,a2,a3,a4);
X    s += strlen(s);
X    if (s[-1] != '\n') {
X	if (line) {
X	    sprintf(s," at %s line %ld",
X	      in_eval?filename:origfilename, (long)line);
X	    s += strlen(s);
X	}
X	if (last_in_stab &&
X	    last_in_stab->stab_io &&
X	    last_in_stab->stab_io->lines ) {
X	    sprintf(s,", <%s> line %ld",
X	      last_in_stab == argvstab ? "" : last_in_stab->stab_name,
X	      (long)last_in_stab->stab_io->lines);
X	    s += strlen(s);
X	}
X	strcpy(s,".\n");
X    }
X}
X
X/*VARARGS1*/
Xfatal(pat,a1,a2,a3,a4)
Xchar *pat;
X{
X    extern FILE *e_fp;
X    extern char *e_tmpname;
X
X    mess(pat,a1,a2,a3,a4);
X    if (in_eval) {
X	str_set(stabent("@",TRUE)->stab_val,tokenbuf);
X	longjmp(eval_env,1);
X    }
X    fputs(tokenbuf,stderr);
X    fflush(stderr);
X    if (e_fp)
X	UNLINK(e_tmpname);
X    statusvalue >>= 8;
X    exit(errno?errno:(statusvalue?statusvalue:255));
X}
X
X/*VARARGS1*/
Xwarn(pat,a1,a2,a3,a4)
Xchar *pat;
X{
X    mess(pat,a1,a2,a3,a4);
X    fputs(tokenbuf,stderr);
X    fflush(stderr);
X}
X
Xstatic bool firstsetenv = TRUE;
Xextern char **environ;
X
Xvoid
Xsetenv(nam,val)
Xchar *nam, *val;
X{
X    register int i=envix(nam);		/* where does it go? */
X
X    if (!environ[i]) {			/* does not exist yet */
X	if (firstsetenv) {		/* need we copy environment? */
X	    int j;
X#ifndef lint
X	    char **tmpenv = (char**)	/* point our wand at memory */
X		safemalloc((i+2) * sizeof(char*));
X#else
X	    char **tmpenv = Null(char **);
X#endif /* lint */
X    
X	    firstsetenv = FALSE;
X	    for (j=0; j<i; j++)		/* copy environment */
X		tmpenv[j] = environ[j];
X	    environ = tmpenv;		/* tell exec where it is now */
X	}
X#ifndef lint
X	else
X	    environ = (char**) saferealloc((char*) environ,
X		(i+2) * sizeof(char*));
X					/* just expand it a bit */
X#endif /* lint */
X	environ[i+1] = Nullch;	/* make sure it's null terminated */
X    }
X    environ[i] = safemalloc((MEM_SIZE)(strlen(nam) + strlen(val) + 2));
X					/* this may or may not be in */
X					/* the old environ structure */
X    sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
X}
X
Xint
Xenvix(nam)
Xchar *nam;
X{
X    register int i, len = strlen(nam);
X
X    for (i = 0; environ[i]; i++) {
X	if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
X	    break;			/* strnEQ must come first to avoid */
X    }					/* potential SEGV's */
X    return i;
X}
X
X#ifdef EUNICE
Xunlnk(f)	/* unlink all versions of a file */
Xchar *f;
X{
X    int i;
X
X    for (i = 0; unlink(f) >= 0; i++) ;
X    return i ? 0 : -1;
X}
X#endif
X
X#ifndef BCOPY
X#ifndef MEMCPY
Xchar *
Xbcopy(from,to,len)
Xregister char *from;
Xregister char *to;
Xregister int len;
X{
X    char *retval = to;
X
X    while (len--)
X	*to++ = *from++;
X    return retval;
X}
X
Xchar *
Xbzero(loc,len)
Xregister char *loc;
Xregister int len;
X{
X    char *retval = loc;
X
X    while (len--)
X	*loc++ = 0;
X    return retval;
X}
X#endif
X#endif
!STUFFY!FUNK!
echo Extracting eg/scan/scan_suid
sed >eg/scan/scan_suid <<'!STUFFY!FUNK!' -e 's/X//'
X#!/usr/bin/perl -P
X
X# $Header: scan_suid,v 2.0 88/06/05 00:17:54 root Exp $
X
X# Look for new setuid root files.
X
Xchdir '/usr/adm/private/memories' || die "Can't cd.";
X
X($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
X   $blksize,$blocks) = stat('oldsuid');
Xif ($nlink) {
X    $lasttime = $mtime;
X    $tmp = $ctime - $atime;
X    if ($tmp <= 0 || $tmp >= 10) {
X	print "WARNING: somebody has read oldsuid!\n";
X    }
X    $tmp = $ctime - $mtime;
X    if ($tmp <= 0 || $tmp >= 10) {
X	print "WARNING: somebody has modified oldsuid!!!\n";
X    }
X} else {
X    $lasttime = time - 60 * 60 * 24;	# one day ago
X}
X$thistime = time;
X
X#if defined(mc300) || defined(mc500) || defined(mc700)
Xopen(Find, 'find / -perm -04000 -print |') ||
X	die "scan_find: can't run find";
X#else
Xopen(Find, 'find / \( -fstype nfs -prune \) -o -perm -04000 -ls |') ||
X	die "scan_find: can't run find";
X#endif
X
Xopen(suid, '>newsuid.tmp');
X
Xwhile (<Find>) {
X
X#if defined(mc300) || defined(mc500) || defined(mc700)
X    $x = `/bin/ls -il $_`;
X    $_ = $x;
X    s/^ *//;
X    ($inode,$perm,$links,$owner,$group,$size,$month,$day,$time,$name)
X      = split;
X#else
X    s/^ *//;
X    ($inode,$blocks,$perm,$links,$owner,$group,$size,$month,$day,$time,$name)
X      = split;
X#endif
X
X    if ($perm =~ /[sS]/ && $owner eq 'root') {
X	($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
X	   $blksize,$blocks) = stat($name);
X	$foo = sprintf("%10s%3s %-8s %-8s%9s %3s %2s %s %s\n",
X		$perm,$links,$owner,$group,$size,$month,$day,$name,$inode);
X	print suid $foo;
X	if ($ctime > $lasttime) {
X	    if ($ctime > $thistime) {
X		print "Future file: $foo";
X	    }
X	    else {
X		$ct .= $foo;
X	    }
X	}
X    }
X}
Xclose(suid);
X
Xprint `sort +7 -8 newsuid.tmp >newsuid 2>&1`;
X$foo = `/bin/diff oldsuid newsuid 2>&1`;
Xprint "Differences in suid info:\n",$foo if $foo;
Xprint `mv oldsuid oldoldsuid 2>&1; mv newsuid oldsuid 2>&1`;
Xprint `touch oldsuid 2>&1;sleep 2 2>&1;chmod o+w oldsuid 2>&1`;
Xprint `rm -f newsuid.tmp 2>&1`;
X
X@ct = split(/\n/,$ct);
X$ct = '';
X$* = 1;
Xwhile ($#ct >= 0) {
X    $tmp = shift(@ct);
X    unless ($foo =~ "^>.*$tmp\n") { $ct .= "$tmp\n"; }
X}
X
Xprint "Inode changed since last time:\n",$ct if $ct;
X
!STUFFY!FUNK!
echo ""
echo "End of kit 8 (of 15)"
cat /dev/null >kit8isdone
run=''
config=''
for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; 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

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.