[comp.sources.misc] v18i027: perl - The perl programming language, Part09/36

lwall@netlabs.com (Larry Wall) (04/16/91)

Submitted-by: Larry Wall <lwall@netlabs.com>
Posting-number: Volume 18, Issue 27
Archive-name: perl/part09

[There are 36 kits for perl version 4.0.]

#! /bin/sh

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

echo "This is perl 4.0 kit 9 (of 36).  If kit 9 is complete, the line"
echo '"'"End of kit 9 (of 36)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir x2p 2>/dev/null
echo Extracting x2p/walk.c
sed >x2p/walk.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: walk.c,v 4.0 91/03/20 01:58:36 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:	walk.c,v $
X * Revision 4.0  91/03/20  01:58:36  lwall
X * 4.0 baseline.
X * 
X */
X
X#include "handy.h"
X#include "EXTERN.h"
X#include "util.h"
X#include "a2p.h"
X
Xbool exitval = FALSE;
Xbool realexit = FALSE;
Xbool saw_getline = FALSE;
Xbool subretnum = FALSE;
Xbool saw_FNR = FALSE;
Xbool saw_argv0 = FALSE;
Xint maxtmp = 0;
Xchar *lparen;
Xchar *rparen;
XSTR *subs;
XSTR *curargs = Nullstr;
X
XSTR *
Xwalk(useval,level,node,numericptr,minprec)
Xint useval;
Xint level;
Xregister int node;
Xint *numericptr;
Xint minprec;			/* minimum precedence without parens */
X{
X    register int len;
X    register STR *str;
X    register int type;
X    register int i;
X    register STR *tmpstr;
X    STR *tmp2str;
X    STR *tmp3str;
X    char *t;
X    char *d, *s;
X    int numarg;
X    int numeric = FALSE;
X    STR *fstr;
X    int prec = P_MAX;		/* assume no parens needed */
X    char *index();
X
X    if (!node) {
X	*numericptr = 0;
X	return str_make("");
X    }
X    type = ops[node].ival;
X    len = type >> 8;
X    type &= 255;
X    switch (type) {
X    case OPROG:
X	opens = str_new(0);
X	subs = str_new(0);
X	str = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	if (do_split && need_entire && !absmaxfld)
X	    split_to_array = TRUE;
X	if (do_split && split_to_array)
X	    set_array_base = TRUE;
X	if (set_array_base) {
X	    str_cat(str,"$[ = 1;\t\t\t# set array base to 1\n");
X	}
X	if (fswitch && !const_FS)
X	    const_FS = fswitch;
X	if (saw_FS > 1 || saw_RS)
X	    const_FS = 0;
X	if (saw_ORS && need_entire)
X	    do_chop = TRUE;
X	if (fswitch) {
X	    str_cat(str,"$FS = '");
X	    if (index("*+?.[]()|^$\\",fswitch))
X		str_cat(str,"\\");
X	    sprintf(tokenbuf,"%c",fswitch);
X	    str_cat(str,tokenbuf);
X	    str_cat(str,"';\t\t# field separator from -F switch\n");
X	}
X	else if (saw_FS && !const_FS) {
X	    str_cat(str,"$FS = ' ';\t\t# set field separator\n");
X	}
X	if (saw_OFS) {
X	    str_cat(str,"$, = ' ';\t\t# set output field separator\n");
X	}
X	if (saw_ORS) {
X	    str_cat(str,"$\\ = \"\\n\";\t\t# set output record separator\n");
X	}
X	if (saw_argv0) {
X	    str_cat(str,"$ARGV0 = $0;\t\t# remember what we ran as\n");
X	}
X	if (str->str_cur > 20)
X	    str_cat(str,"\n");
X	if (ops[node+2].ival) {
X	    str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
X	    str_free(fstr);
X	    str_cat(str,"\n\n");
X	}
X	fstr = walk(0,level+1,ops[node+3].ival,&numarg,P_MIN);
X	if (*fstr->str_ptr) {
X	    if (saw_line_op)
X		str_cat(str,"line: ");
X	    str_cat(str,"while (<>) {\n");
X	    tab(str,++level);
X	    if (saw_FS && !const_FS)
X		do_chop = TRUE;
X	    if (do_chop) {
X		str_cat(str,"chop;\t# strip record separator\n");
X		tab(str,level);
X	    }
X	    arymax = 0;
X	    if (namelist) {
X		while (isalpha(*namelist)) {
X		    for (d = tokenbuf,s=namelist;
X		      isalpha(*s) || isdigit(*s) || *s == '_';
X		      *d++ = *s++) ;
X		    *d = '\0';
X		    while (*s && !isalpha(*s)) s++;
X		    namelist = s;
X		    nameary[++arymax] = savestr(tokenbuf);
X		}
X	    }
X	    if (maxfld < arymax)
X		maxfld = arymax;
X	    if (do_split)
X		emit_split(str,level);
X	    str_scat(str,fstr);
X	    str_free(fstr);
X	    fixtab(str,--level);
X	    str_cat(str,"}\n");
X	    if (saw_FNR)
X		str_cat(str,"continue {\n    $FNRbase = $. if eof;\n}\n");
X	}
X	else
X	    str_cat(str,"while (<>) { }		# (no line actions)\n");
X	if (ops[node+4].ival) {
X	    realexit = TRUE;
X	    str_cat(str,"\n");
X	    tab(str,level);
X	    str_scat(str,fstr=walk(0,level,ops[node+4].ival,&numarg,P_MIN));
X	    str_free(fstr);
X	    str_cat(str,"\n");
X	}
X	if (exitval)
X	    str_cat(str,"exit $ExitValue;\n");
X	if (subs->str_ptr) {
X	    str_cat(str,"\n");
X	    str_scat(str,subs);
X	}
X	if (saw_getline) {
X	    for (len = 0; len < 4; len++) {
X		if (saw_getline & (1 << len)) {
X		    sprintf(tokenbuf,"\nsub Getline%d {\n",len);
X		    str_cat(str, tokenbuf);
X		    if (len & 2) {
X			if (do_fancy_opens)
X			    str_cat(str,"    &Pick('',@_);\n");
X			else
X			    str_cat(str,"    ($fh) = @_;\n");
X		    }
X		    else {
X			if (saw_FNR)
X			    str_cat(str,"    $FNRbase = $. if eof;\n");
X		    }
X		    if (len & 1)
X			str_cat(str,"    local($_);\n");
X		    if (len & 2)
X			str_cat(str,
X			  "    if ($getline_ok = (($_ = <$fh>) ne ''))");
X		    else
X			str_cat(str,
X			  "    if ($getline_ok = (($_ = <>) ne ''))");
X		    str_cat(str, " {\n");
X		    level += 2;
X		    tab(str,level);
X		    i = 0;
X		    if (do_chop) {
X			i++;
X			str_cat(str,"chop;\t# strip record separator\n");
X			tab(str,level);
X		    }
X		    if (do_split && !(len & 1)) {
X			i++;
X			emit_split(str,level);
X		    }
X		    if (!i)
X			str_cat(str,";\n");
X		    fixtab(str,--level);
X		    str_cat(str,"}\n    $_;\n}\n");
X		    --level;
X		}
X	    }
X	}
X	if (do_fancy_opens) {
X	    str_cat(str,"\n\
Xsub Pick {\n\
X    local($mode,$name,$pipe) = @_;\n\
X    $fh = $opened{$name};\n\
X    if (!$fh) {\n\
X	$fh = $opened{$name} = 'fh_' . ($nextfh++ + 0);\n\
X	open($fh,$mode.$name.$pipe);\n\
X    }\n\
X}\n\
X");
X	}
X	break;
X    case OHUNKS:
X	str = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
X	str_free(fstr);
X	if (len == 3) {
X	    str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg,P_MIN));
X	    str_free(fstr);
X	}
X	else {
X	}
X	break;
X    case ORANGE:
X	prec = P_DOTDOT;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec+1);
X	str_cat(str," .. ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	break;
X    case OPAT:
X	goto def;
X    case OREGEX:
X	str = str_new(0);
X	str_set(str,"/");
X	tmpstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	/* translate \nnn to [\nnn] */
X	for (s = tmpstr->str_ptr, d = tokenbuf; *s; s++, d++) {
X	    if (*s == '\\' && isdigit(s[1]) && isdigit(s[2]) && isdigit(s[3])){
X		*d++ = '[';
X		*d++ = *s++;
X		*d++ = *s++;
X		*d++ = *s++;
X		*d++ = *s;
X		*d = ']';
X	    }
X	    else
X		*d = *s;
X	}
X	*d = '\0';
X	for (d=tokenbuf; *d; d++)
X	    *d += 128;
X	str_cat(str,tokenbuf);
X	str_free(tmpstr);
X	str_cat(str,"/");
X	break;
X    case OHUNK:
X	if (len == 1) {
X	    str = str_new(0);
X	    str = walk(0,level,oper1(OPRINT,0),&numarg,P_MIN);
X	    str_cat(str," if ");
X	    str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN));
X	    str_free(fstr);
X	    str_cat(str,";");
X	}
X	else {
X	    tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	    if (*tmpstr->str_ptr) {
X		str = str_new(0);
X		str_set(str,"if (");
X		str_scat(str,tmpstr);
X		str_cat(str,") {\n");
X		tab(str,++level);
X		str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
X		str_free(fstr);
X		fixtab(str,--level);
X		str_cat(str,"}\n");
X		tab(str,level);
X	    }
X	    else {
X		str = walk(0,level,ops[node+2].ival,&numarg,P_MIN);
X	    }
X	}
X	break;
X    case OPPAREN:
X	str = str_new(0);
X	str_set(str,"(");
X	str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_cat(str,")");
X	break;
X    case OPANDAND:
X	prec = P_ANDAND;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	str_cat(str," && ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
X	str_free(fstr);
X	break;
X    case OPOROR:
X	prec = P_OROR;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	str_cat(str," || ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
X	str_free(fstr);
X	break;
X    case OPNOT:
X	prec = P_UNARY;
X	str = str_new(0);
X	str_set(str,"!");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec));
X	str_free(fstr);
X	break;
X    case OCOND:
X	prec = P_COND;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	str_cat(str," ? ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	str_cat(str," : ");
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
X	str_free(fstr);
X	break;
X    case OCPAREN:
X	str = str_new(0);
X	str_set(str,"(");
X	str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	numeric |= numarg;
X	str_cat(str,")");
X	break;
X    case OCANDAND:
X	prec = P_ANDAND;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	numeric = 1;
X	str_cat(str," && ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
X	str_free(fstr);
X	break;
X    case OCOROR:
X	prec = P_OROR;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	numeric = 1;
X	str_cat(str," || ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
X	str_free(fstr);
X	break;
X    case OCNOT:
X	prec = P_UNARY;
X	str = str_new(0);
X	str_set(str,"!");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case ORELOP:
X	prec = P_REL;
X	str = walk(1,level,ops[node+2].ival,&numarg,prec+1);
X	numeric |= numarg;
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	tmp2str = walk(1,level,ops[node+3].ival,&numarg,prec+1);
X	numeric |= numarg;
X	if (!numeric ||
X	 (!numarg && (*tmp2str->str_ptr == '"' || *tmp2str->str_ptr == '\''))) {
X	    t = tmpstr->str_ptr;
X	    if (strEQ(t,"=="))
X		str_set(tmpstr,"eq");
X	    else if (strEQ(t,"!="))
X		str_set(tmpstr,"ne");
X	    else if (strEQ(t,"<"))
X		str_set(tmpstr,"lt");
X	    else if (strEQ(t,"<="))
X		str_set(tmpstr,"le");
X	    else if (strEQ(t,">"))
X		str_set(tmpstr,"gt");
X	    else if (strEQ(t,">="))
X		str_set(tmpstr,"ge");
X	    if (!index(tmpstr->str_ptr,'\'') && !index(tmpstr->str_ptr,'"') &&
X	      !index(tmp2str->str_ptr,'\'') && !index(tmp2str->str_ptr,'"') )
X		numeric |= 2;
X	}
X	if (numeric & 2) {
X	    if (numeric & 1)		/* numeric is very good guess */
X		str_cat(str," ");
X	    else
X		str_cat(str,"\377");
X	    numeric = 1;
X	}
X	else
X	    str_cat(str," ");
X	str_scat(str,tmpstr);
X	str_free(tmpstr);
X	str_cat(str," ");
X	str_scat(str,tmp2str);
X	str_free(tmp2str);
X	numeric = 1;
X	break;
X    case ORPAREN:
X	str = str_new(0);
X	str_set(str,"(");
X	str_scat(str,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	numeric |= numarg;
X	str_cat(str,")");
X	break;
X    case OMATCHOP:
X	prec = P_MATCH;
X	str = walk(1,level,ops[node+2].ival,&numarg,prec+1);
X	str_cat(str," ");
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	if (strEQ(tmpstr->str_ptr,"~"))
X	    str_cat(str,"=~");
X	else {
X	    str_scat(str,tmpstr);
X	    str_free(tmpstr);
X	}
X	str_cat(str," ");
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OMPAREN:
X	str = str_new(0);
X	str_set(str,"(");
X	str_scat(str,
X	  fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	numeric |= numarg;
X	str_cat(str,")");
X	break;
X    case OCONCAT:
X	prec = P_ADD;
X	type = ops[ops[node+1].ival].ival & 255;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec+(type != OCONCAT));
X	str_cat(str," . ");
X	type = ops[ops[node+2].ival].ival & 255;
X	str_scat(str,
X	  fstr=walk(1,level,ops[node+2].ival,&numarg,prec+(type != OCONCAT)));
X	str_free(fstr);
X	break;
X    case OASSIGN:
X	prec = P_ASSIGN;
X	str = walk(0,level,ops[node+2].ival,&numarg,prec+1);
X	str_cat(str," ");
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	str_scat(str,tmpstr);
X	if (str_len(tmpstr) > 1)
X	    numeric = 1;
X	str_free(tmpstr);
X	str_cat(str," ");
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec));
X	str_free(fstr);
X	numeric |= numarg;
X	break;
X    case OADD:
X	prec = P_ADD;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	str_cat(str," + ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OSUBTRACT:
X	prec = P_ADD;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	str_cat(str," - ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OMULT:
X	prec = P_MUL;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	str_cat(str," * ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case ODIV:
X	prec = P_MUL;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	str_cat(str," / ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OPOW:
X	prec = P_POW;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec+1);
X	str_cat(str," ** ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OMOD:
X	prec = P_MUL;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	str_cat(str," % ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,prec+1));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OPOSTINCR:
X	prec = P_AUTO;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec+1);
X	str_cat(str,"++");
X	numeric = 1;
X	break;
X    case OPOSTDECR:
X	prec = P_AUTO;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec+1);
X	str_cat(str,"--");
X	numeric = 1;
X	break;
X    case OPREINCR:
X	prec = P_AUTO;
X	str = str_new(0);
X	str_set(str,"++");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec+1));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OPREDECR:
X	prec = P_AUTO;
X	str = str_new(0);
X	str_set(str,"--");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec+1));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OUMINUS:
X	prec = P_UNARY;
X	str = str_new(0);
X	str_set(str,"-");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,prec));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OUPLUS:
X	numeric = 1;
X	goto def;
X    case OPAREN:
X	str = str_new(0);
X	str_set(str,"(");
X	str_scat(str,
X	  fstr=walk(useval != 0,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_cat(str,")");
X	numeric |= numarg;
X	break;
X    case OGETLINE:
X	str = str_new(0);
X	if (useval)
X	    str_cat(str,"(");
X	if (len > 0) {
X	    str_cat(str,"$");
X	    str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	    if (!*fstr->str_ptr) {
X		str_cat(str,"_");
X		len = 2;		/* a legal fiction */
X	    }
X	    str_free(fstr);
X	}
X	else
X	    str_cat(str,"$_");
X	if (len > 1) {
X	    tmpstr=walk(1,level,ops[node+3].ival,&numarg,P_MIN);
X	    fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN);
X	    if (!do_fancy_opens) {
X		t = tmpstr->str_ptr;
X		if (*t == '"' || *t == '\'')
X		    t = cpytill(tokenbuf,t+1,*t);
X		else
X		    fatal("Internal error: OGETLINE %s", t);
X		d = savestr(t);
X		s = savestr(tokenbuf);
X		for (t = tokenbuf; *t; t++) {
X		    *t &= 127;
X		    if (!isalpha(*t) && !isdigit(*t))
X			*t = '_';
X		}
X		if (!index(tokenbuf,'_'))
X		    strcpy(t,"_fh");
X		tmp3str = hfetch(symtab,tokenbuf);
X		if (!tmp3str) {
X		    do_opens = TRUE;
X		    str_cat(opens,"open(");
X		    str_cat(opens,tokenbuf);
X		    str_cat(opens,", ");
X		    d[1] = '\0';
X		    str_cat(opens,d);
X		    str_cat(opens,tmpstr->str_ptr+1);
X		    opens->str_cur--;
X		    if (*fstr->str_ptr == '|')
X			str_cat(opens,"|");
X		    str_cat(opens,d);
X		    if (*fstr->str_ptr == '|')
X			str_cat(opens,") || die 'Cannot pipe from \"");
X		    else
X			str_cat(opens,") || die 'Cannot open file \"");
X		    if (*d == '"')
X			str_cat(opens,"'.\"");
X		    str_cat(opens,s);
X		    if (*d == '"')
X			str_cat(opens,"\".'");
X		    str_cat(opens,"\".';\n");
X		    hstore(symtab,tokenbuf,str_make("x"));
X		}
X		safefree(s);
X		safefree(d);
X		str_set(tmpstr,"'");
X		str_cat(tmpstr,tokenbuf);
X		str_cat(tmpstr,"'");
X	    }
X	    if (*fstr->str_ptr == '|')
X		str_cat(tmpstr,", '|'");
X	    str_free(fstr);
X	}
X	else
X	    tmpstr = str_make("");
X	sprintf(tokenbuf," = &Getline%d(%s)",len,tmpstr->str_ptr);
X	str_cat(str,tokenbuf); 
X	str_free(tmpstr);
X	if (useval)
X	    str_cat(str,",$getline_ok)");
X	saw_getline |= 1 << len;
X	break;
X    case OSPRINTF:
X	str = str_new(0);
X	str_set(str,"sprintf(");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_cat(str,")");
X	break;
X    case OSUBSTR:
X	str = str_new(0);
X	str_set(str,"substr(");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_COMMA+1));
X	str_free(fstr);
X	str_cat(str,", ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_COMMA+1));
X	str_free(fstr);
X	str_cat(str,", ");
X	if (len == 3) {
X	    str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,P_COMMA+1));
X	    str_free(fstr);
X	}
X	else
X	    str_cat(str,"999999");
X	str_cat(str,")");
X	break;
X    case OSTRING:
X	str = str_new(0);
X	str_set(str,ops[node+1].cval);
X	break;
X    case OSPLIT:
X	str = str_new(0);
X	numeric = 1;
X	tmpstr = walk(1,level,ops[node+2].ival,&numarg,P_MIN);
X	if (useval)
X	    str_set(str,"(@");
X	else
X	    str_set(str,"@");
X	str_scat(str,tmpstr);
X	str_cat(str," = split(");
X	if (len == 3) {
X	    fstr = walk(1,level,ops[node+3].ival,&numarg,P_COMMA+1);
X	    if (str_len(fstr) == 3 && *fstr->str_ptr == '\'') {
X		i = fstr->str_ptr[1] & 127;
X		if (index("*+?.[]()|^$\\",i))
X		    sprintf(tokenbuf,"/\\%c/",i);
X		else if (i == ' ')
X		    sprintf(tokenbuf,"' '");
X		else
X		    sprintf(tokenbuf,"/%c/",i);
X		str_cat(str,tokenbuf);
X	    }
X	    else
X		str_scat(str,fstr);
X	    str_free(fstr);
X	}
X	else if (const_FS) {
X	    sprintf(tokenbuf,"/[%c\\n]/",const_FS);
X	    str_cat(str,tokenbuf);
X	}
X	else if (saw_FS)
X	    str_cat(str,"$FS");
X	else
X	    str_cat(str,"' '");
X	str_cat(str,", ");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_COMMA+1));
X	str_free(fstr);
X	str_cat(str,", 9999)");
X	if (useval) {
X	    str_cat(str,")");
X	}
X	str_free(tmpstr);
X	break;
X    case OINDEX:
X	str = str_new(0);
X	str_set(str,"index(");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_COMMA+1));
X	str_free(fstr);
X	str_cat(str,", ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_COMMA+1));
X	str_free(fstr);
X	str_cat(str,")");
X	numeric = 1;
X	break;
X    case OMATCH:
X	str = str_new(0);
X	prec = P_ANDAND;
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MATCH+1));
X	str_free(fstr);
X	str_cat(str," =~ ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MATCH+1));
X	str_free(fstr);
X	str_cat(str," && ($RLENGTH = length($&), $RSTART = length($`)+1)");
X	numeric = 1;
X	break;
X    case OUSERDEF:
X	str = str_new(0);
X	subretnum = FALSE;
X	fstr=walk(1,level-1,ops[node+2].ival,&numarg,P_MIN);
X	curargs = str_new(0);
X	str_sset(curargs,fstr);
X	str_cat(curargs,",");
X	tmp2str=walk(1,level,ops[node+5].ival,&numarg,P_MIN);
X	str_free(curargs);
X	curargs = Nullstr;
X	level--;
X	subretnum |= numarg;
X	s = Nullch;
X	t = tmp2str->str_ptr;
X	while (t = instr(t,"return "))
X	    s = t++;
X	if (s) {
X	    i = 0;
X	    for (t = s+7; *t; t++) {
X		if (*t == ';' || *t == '}')
X		    i++;
X	    }
X	    if (i == 1) {
X		strcpy(s,s+7);
X		tmp2str->str_cur -= 7;
X	    }
X	}
X	str_set(str,"\n");
X	tab(str,level);
X	str_cat(str,"sub ");
X	str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	str_cat(str," {\n");
X	tab(str,++level);
X	if (fstr->str_cur) {
X	    str_cat(str,"local(");
X	    str_scat(str,fstr);
X	    str_cat(str,") = @_;");
X	}
X	str_free(fstr);
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,P_MIN));
X	str_free(fstr);
X	fixtab(str,level);
X	str_scat(str,fstr=walk(1,level,ops[node+4].ival,&numarg,P_MIN));
X	str_free(fstr);
X	fixtab(str,level);
X	str_scat(str,tmp2str);
X	str_free(tmp2str);
X	fixtab(str,--level);
X	str_cat(str,"}\n");
X	tab(str,level);
X	str_scat(subs,str);
X	str_set(str,"");
X	str_cat(tmpstr,"(");
X	tmp2str = str_new(0);
X	if (subretnum)
X	    str_set(tmp2str,"1");
X	hstore(symtab,tmpstr->str_ptr,tmp2str);
X	str_free(tmpstr);
X	level++;
X	break;
X    case ORETURN:
X	str = str_new(0);
X	if (len > 0) {
X	    str_cat(str,"return ");
X	    str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_UNI+1));
X	    str_free(fstr);
X	    if (numarg)
X		subretnum = TRUE;
X	}
X	else
X	    str_cat(str,"return");
X	break;
X    case OUSERFUN:
X	str = str_new(0);
X	str_set(str,"&");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_cat(str,"(");
X	tmpstr = hfetch(symtab,str->str_ptr+3);
X	if (tmpstr && tmpstr->str_ptr)
X	    numeric |= atoi(tmpstr->str_ptr);
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_cat(str,")");
X	break;
X    case OGSUB:
X    case OSUB:
X	if (type == OGSUB)
X	    s = "g";
X	else
X	    s = "";
X	str = str_new(0);
X	tmpstr = str_new(0);
X	i = 0;
X	if (len == 3) {
X	    tmpstr = walk(1,level,ops[node+3].ival,&numarg,P_MATCH+1);
X	    if (strNE(tmpstr->str_ptr,"$_")) {
X		str_cat(tmpstr, " =~ s");
X		i++;
X	    }
X	    else
X		str_set(tmpstr, "s");
X	}
X	else
X	    str_set(tmpstr, "s");
X	type = ops[ops[node+2].ival].ival;
X	len = type >> 8;
X	type &= 255;
X	tmp3str = str_new(0);
X	if (type == OSTR) {
X	    tmp2str=walk(1,level,ops[ops[node+2].ival+1].ival,&numarg,P_MIN);
X	    for (t = tmp2str->str_ptr, d=tokenbuf; *t; d++,t++) {
X		if (*t == '&')
X		    *d++ = '$' + 128;
X		else if (*t == '$')
X		    *d++ = '\\' + 128;
X		*d = *t + 128;
X	    }
X	    *d = '\0';
X	    str_set(tmp2str,tokenbuf);
X	}
X	else {
X	    tmp2str=walk(1,level,ops[node+2].ival,&numarg,P_MIN);
X	    str_set(tmp3str,"($s_ = '\"'.(");
X	    str_scat(tmp3str,tmp2str);
X	    str_cat(tmp3str,").'\"') =~ s/&/\\$&/g, ");
X	    str_set(tmp2str,"eval $s_");
X	    s = (*s == 'g' ? "ge" : "e");
X	    i++;
X	}
X	type = ops[ops[node+1].ival].ival;
X	len = type >> 8;
X	type &= 255;
X	fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN);
X	if (type == OREGEX) {
X	    if (useval && i)
X		str_cat(str,"(");
X	    str_scat(str,tmp3str);
X	    str_scat(str,tmpstr);
X	    str_scat(str,fstr);
X	    str_scat(str,tmp2str);
X	    str_cat(str,"/");
X	    str_cat(str,s);
X	}
X	else if ((type == OFLD && !split_to_array) || (type == OVAR && len == 1)) {
X	    if (useval && i)
X		str_cat(str,"(");
X	    str_scat(str,tmp3str);
X	    str_scat(str,tmpstr);
X	    str_cat(str,"/");
X	    str_scat(str,fstr);
X	    str_cat(str,"/");
X	    str_scat(str,tmp2str);
X	    str_cat(str,"/");
X	    str_cat(str,s);
X	}
X	else {
X	    i++;
X	    if (useval)
X		str_cat(str,"(");
X	    str_cat(str,"$s = ");
X	    str_scat(str,fstr);
X	    str_cat(str,", ");
X	    str_scat(str,tmp3str);
X	    str_scat(str,tmpstr);
X	    str_cat(str,"/$s/");
X	    str_scat(str,tmp2str);
X	    str_cat(str,"/");
X	    str_cat(str,s);
X	}
X	if (useval && i)
X	    str_cat(str,")");
X	str_free(fstr);
X	str_free(tmpstr);
X	str_free(tmp2str);
X	str_free(tmp3str);
X	numeric = 1;
X	break;
X    case ONUM:
X	str = walk(1,level,ops[node+1].ival,&numarg,P_MIN);
X	numeric = 1;
X	break;
X    case OSTR:
X	tmpstr = walk(1,level,ops[node+1].ival,&numarg,P_MIN);
X	s = "'";
X	for (t = tmpstr->str_ptr, d=tokenbuf; *t; d++,t++) {
X	    if (*t == '\'')
X		s = "\"";
X	    else if (*t == '\\') {
X		s = "\"";
X		*d++ = *t++ + 128;
X		switch (*t) {
X		case '\\': case '"': case 'n': case 't': case '$':
X		    break;
X		default:	/* hide this from perl */
X		    *d++ = '\\' + 128;
X		}
X	    }
X	    *d = *t + 128;
X	}
X	*d = '\0';
X	str = str_new(0);
X	str_set(str,s);
X	str_cat(str,tokenbuf);
X	str_free(tmpstr);
X	str_cat(str,s);
X	break;
X    case ODEFINED:
X	prec = P_UNI;
X	str = str_new(0);
X	str_set(str,"defined $");
X	goto addvar;
X    case ODELETE:
X	str = str_new(0);
X	str_set(str,"delete $");
X	goto addvar;
X    case OSTAR:
X	str = str_new(0);
X	str_set(str,"*");
X	goto addvar;
X    case OVAR:
X	str = str_new(0);
X	str_set(str,"$");
X      addvar:
X	str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	if (len == 1) {
X	    tmp2str = hfetch(symtab,tmpstr->str_ptr);
X	    if (tmp2str && atoi(tmp2str->str_ptr))
X		numeric = 2;
X	    if (strEQ(str->str_ptr,"$FNR")) {
X		numeric = 1;
X		saw_FNR++;
X		str_set(str,"($.-$FNRbase)");
X	    }
X	    else if (strEQ(str->str_ptr,"$NR")) {
X		numeric = 1;
X		str_set(str,"$.");
X	    }
X	    else if (strEQ(str->str_ptr,"$NF")) {
X		numeric = 1;
X		str_set(str,"$#Fld");
X	    }
X	    else if (strEQ(str->str_ptr,"$0"))
X		str_set(str,"$_");
X	    else if (strEQ(str->str_ptr,"$ARGC"))
X		str_set(str,"($#ARGV+1)");
X	}
X	else {
X#ifdef NOTDEF
X	    if (curargs) {
X		sprintf(tokenbuf,"$%s,",tmpstr->str_ptr);
X	???	if (instr(curargs->str_ptr,tokenbuf))
X		    str_cat(str,"\377");	/* can't translate yet */
X	    }
X#endif
X	    str_cat(tmpstr,"[]");
X	    tmp2str = hfetch(symtab,tmpstr->str_ptr);
X	    if (tmp2str && atoi(tmp2str->str_ptr))
X		str_cat(str,"[");
X	    else
X		str_cat(str,"{");
X	    str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN));
X	    str_free(fstr);
X	    if (strEQ(str->str_ptr,"$ARGV[0")) {
X		str_set(str,"$ARGV0");
X		saw_argv0++;
X	    }
X	    else {
X		if (tmp2str && atoi(tmp2str->str_ptr))
X		    strcpy(tokenbuf,"]");
X		else
X		    strcpy(tokenbuf,"}");
X		*tokenbuf += 128;
X		str_cat(str,tokenbuf);
X	    }
X	}
X	str_free(tmpstr);
X	break;
X    case OFLD:
X	str = str_new(0);
X	if (split_to_array) {
X	    str_set(str,"$Fld");
X	    str_cat(str,"[");
X	    str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	    str_free(fstr);
X	    str_cat(str,"]");
X	}
X	else {
X	    i = atoi(walk(1,level,ops[node+1].ival,&numarg,P_MIN)->str_ptr);
X	    if (i <= arymax)
X		sprintf(tokenbuf,"$%s",nameary[i]);
X	    else
X		sprintf(tokenbuf,"$Fld%d",i);
X	    str_set(str,tokenbuf);
X	}
X	break;
X    case OVFLD:
X	str = str_new(0);
X	str_set(str,"$Fld[");
X	i = ops[node+1].ival;
X	if ((ops[i].ival & 255) == OPAREN)
X	    i = ops[i+1].ival;
X	tmpstr=walk(1,level,i,&numarg,P_MIN);
X	str_scat(str,tmpstr);
X	str_free(tmpstr);
X	str_cat(str,"]");
X	break;
X    case OJUNK:
X	goto def;
X    case OSNEWLINE:
X	str = str_new(2);
X	str_set(str,";\n");
X	tab(str,level);
X	break;
X    case ONEWLINE:
X	str = str_new(1);
X	str_set(str,"\n");
X	tab(str,level);
X	break;
X    case OSCOMMENT:
X	str = str_new(0);
X	str_set(str,";");
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	for (s = tmpstr->str_ptr; *s && *s != '\n'; s++)
X	    *s += 128;
X	str_scat(str,tmpstr);
X	str_free(tmpstr);
X	tab(str,level);
X	break;
X    case OCOMMENT:
X	str = str_new(0);
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	for (s = tmpstr->str_ptr; *s && *s != '\n'; s++)
X	    *s += 128;
X	str_scat(str,tmpstr);
X	str_free(tmpstr);
X	tab(str,level);
X	break;
X    case OCOMMA:
X	prec = P_COMMA;
X	str = walk(1,level,ops[node+1].ival,&numarg,prec);
X	str_cat(str,", ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,prec+1));
X	str_free(fstr);
X	break;
X    case OSEMICOLON:
X	str = str_new(1);
X	str_set(str,";\n");
X	tab(str,level);
X	break;
X    case OSTATES:
X	str = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
X	str_free(fstr);
X	break;
X    case OSTATE:
X	str = str_new(0);
X	if (len >= 1) {
X	    str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN));
X	    str_free(fstr);
X	    if (len >= 2) {
X		tmpstr = walk(0,level,ops[node+2].ival,&numarg,P_MIN);
X		if (*tmpstr->str_ptr == ';') {
X		    addsemi(str);
X		    str_cat(str,tmpstr->str_ptr+1);
X		}
X		str_free(tmpstr);
X	    }
X	}
X	break;
X    case OCLOSE:
X	str = str_make("close(");
X	tmpstr = walk(1,level,ops[node+1].ival,&numarg,P_MIN);
X	if (!do_fancy_opens) {
X	    t = tmpstr->str_ptr;
X	    if (*t == '"' || *t == '\'')
X		t = cpytill(tokenbuf,t+1,*t);
X	    else
X		fatal("Internal error: OCLOSE %s",t);
X	    s = savestr(tokenbuf);
X	    for (t = tokenbuf; *t; t++) {
X		*t &= 127;
X		if (!isalpha(*t) && !isdigit(*t))
X		    *t = '_';
X	    }
X	    if (!index(tokenbuf,'_'))
X		strcpy(t,"_fh");
X	    str_free(tmpstr);
X	    safefree(s);
X	    str_set(str,"close ");
X	    str_cat(str,tokenbuf);
X	}
X	else {
X	    sprintf(tokenbuf,"$fh = delete $opened{%s} && close($fh)",
X	       tmpstr->str_ptr);
X	    str_free(tmpstr);
X	    str_set(str,tokenbuf);
X	}
X	break;
X    case OPRINTF:
X    case OPRINT:
X	lparen = "";	/* set to parens if necessary */
X	rparen = "";
X	str = str_new(0);
X	if (len == 3) {		/* output redirection */
X	    tmpstr = walk(1,level,ops[node+3].ival,&numarg,P_MIN);
X	    tmp2str = walk(1,level,ops[node+2].ival,&numarg,P_MIN);
X	    if (!do_fancy_opens) {
X		t = tmpstr->str_ptr;
X		if (*t == '"' || *t == '\'')
X		    t = cpytill(tokenbuf,t+1,*t);
X		else
X		    fatal("Internal error: OPRINT");
X		d = savestr(t);
X		s = savestr(tokenbuf);
X		for (t = tokenbuf; *t; t++) {
X		    *t &= 127;
X		    if (!isalpha(*t) && !isdigit(*t))
X			*t = '_';
X		}
X		if (!index(tokenbuf,'_'))
X		    strcpy(t,"_fh");
X		tmp3str = hfetch(symtab,tokenbuf);
X		if (!tmp3str) {
X		    str_cat(opens,"open(");
X		    str_cat(opens,tokenbuf);
X		    str_cat(opens,", ");
X		    d[1] = '\0';
X		    str_cat(opens,d);
X		    str_scat(opens,tmp2str);
X		    str_cat(opens,tmpstr->str_ptr+1);
X		    if (*tmp2str->str_ptr == '|')
X			str_cat(opens,") || die 'Cannot pipe to \"");
X		    else
X			str_cat(opens,") || die 'Cannot create file \"");
X		    if (*d == '"')
X			str_cat(opens,"'.\"");
X		    str_cat(opens,s);
X		    if (*d == '"')
X			str_cat(opens,"\".'");
X		    str_cat(opens,"\".';\n");
X		    hstore(symtab,tokenbuf,str_make("x"));
X		}
X		str_free(tmpstr);
X		str_free(tmp2str);
X		safefree(s);
X		safefree(d);
X	    }
X	    else {
X		sprintf(tokenbuf,"&Pick('%s', %s) &&\n",
X		   tmp2str->str_ptr, tmpstr->str_ptr);
X		str_cat(str,tokenbuf);
X		tab(str,level+1);
X		strcpy(tokenbuf,"$fh");
X		str_free(tmpstr);
X		str_free(tmp2str);
X		lparen = "(";
X		rparen = ")";
X	    }
X	}
X	else
X	    strcpy(tokenbuf,"");
X	str_cat(str,lparen);	/* may be null */
X	if (type == OPRINTF)
X	    str_cat(str,"printf");
X	else
X	    str_cat(str,"print");
X	if (len == 3 || do_fancy_opens) {
X	    if (*tokenbuf)
X		str_cat(str," ");
X	    str_cat(str,tokenbuf);
X	}
X	tmpstr = walk(1+(type==OPRINT),level,ops[node+1].ival,&numarg,P_MIN);
X	if (!*tmpstr->str_ptr && lval_field) {
X	    t = saw_OFS ? "$," : "' '";
X	    if (split_to_array) {
X		sprintf(tokenbuf,"join(%s,@Fld)",t);
X		str_cat(tmpstr,tokenbuf);
X	    }
X	    else {
X		for (i = 1; i < maxfld; i++) {
X		    if (i <= arymax)
X			sprintf(tokenbuf,"$%s, ",nameary[i]);
X		    else
X			sprintf(tokenbuf,"$Fld%d, ",i);
X		    str_cat(tmpstr,tokenbuf);
X		}
X		if (maxfld <= arymax)
X		    sprintf(tokenbuf,"$%s",nameary[maxfld]);
X		else
X		    sprintf(tokenbuf,"$Fld%d",maxfld);
X		str_cat(tmpstr,tokenbuf);
X	    }
X	}
X	if (*tmpstr->str_ptr) {
X	    str_cat(str," ");
X	    str_scat(str,tmpstr);
X	}
X	else {
X	    str_cat(str," $_");
X	}
X	str_cat(str,rparen);	/* may be null */
X	str_free(tmpstr);
X	break;
X    case ORAND:
X	str = str_make("rand(1)");
X	break;
X    case OSRAND:
X	str = str_make("srand(");
X	goto maybe0;
X    case OATAN2:
X	str = str_make("atan2(");
X	goto maybe0;
X    case OSIN:
X	str = str_make("sin(");
X	goto maybe0;
X    case OCOS:
X	str = str_make("cos(");
X	goto maybe0;
X    case OSYSTEM:
X	str = str_make("system(");
X	goto maybe0;
X    case OLENGTH:
X	str = str_make("length(");
X	goto maybe0;
X    case OLOG:
X	str = str_make("log(");
X	goto maybe0;
X    case OEXP:
X	str = str_make("exp(");
X	goto maybe0;
X    case OSQRT:
X	str = str_make("sqrt(");
X	goto maybe0;
X    case OINT:
X	str = str_make("int(");
X      maybe0:
X	numeric = 1;
X	if (len > 0)
X	    tmpstr = walk(1,level,ops[node+1].ival,&numarg,P_MIN);
X	else
X	    tmpstr = str_new(0);;
X	if (!tmpstr->str_ptr || !*tmpstr->str_ptr) {
X	    if (lval_field) {
X		t = saw_OFS ? "$," : "' '";
X		if (split_to_array) {
X		    sprintf(tokenbuf,"join(%s,@Fld)",t);
X		    str_cat(tmpstr,tokenbuf);
X		}
X		else {
X		    sprintf(tokenbuf,"join(%s, ",t);
X		    str_cat(tmpstr,tokenbuf);
X		    for (i = 1; i < maxfld; i++) {
X			if (i <= arymax)
X			    sprintf(tokenbuf,"$%s,",nameary[i]);
X			else
X			    sprintf(tokenbuf,"$Fld%d,",i);
X			str_cat(tmpstr,tokenbuf);
X		    }
X		    if (maxfld <= arymax)
X			sprintf(tokenbuf,"$%s)",nameary[maxfld]);
X		    else
X			sprintf(tokenbuf,"$Fld%d)",maxfld);
X		    str_cat(tmpstr,tokenbuf);
X		}
X	    }
X	    else
X		str_cat(tmpstr,"$_");
X	}
X	if (strEQ(tmpstr->str_ptr,"$_")) {
X	    if (type == OLENGTH && !do_chop) {
X		str = str_make("(length(");
X		str_cat(tmpstr,") - 1");
X	    }
X	}
X	str_scat(str,tmpstr);
X	str_free(tmpstr);
X	str_cat(str,")");
X	break;
X    case OBREAK:
X	str = str_new(0);
X	str_set(str,"last");
X	break;
X    case ONEXT:
X	str = str_new(0);
X	str_set(str,"next line");
X	break;
X    case OEXIT:
X	str = str_new(0);
X	if (realexit) {
X	    prec = P_UNI;
X	    str_set(str,"exit");
X	    if (len == 1) {
X		str_cat(str," ");
X		exitval = TRUE;
X		str_scat(str,
X		  fstr=walk(1,level,ops[node+1].ival,&numarg,prec+1));
X		str_free(fstr);
X	    }
X	}
X	else {
X	    if (len == 1) {
X		str_set(str,"$ExitValue = ");
X		exitval = TRUE;
X		str_scat(str,
X		  fstr=walk(1,level,ops[node+1].ival,&numarg,P_ASSIGN));
X		str_free(fstr);
X		str_cat(str,"; ");
X	    }
X	    str_cat(str,"last line");
X	}
X	break;
X    case OCONTINUE:
X	str = str_new(0);
X	str_set(str,"next");
X	break;
X    case OREDIR:
X	goto def;
X    case OIF:
X	str = str_new(0);
X	str_set(str,"if (");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_cat(str,") ");
X	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
X	str_free(fstr);
X	if (len == 3) {
X	    i = ops[node+3].ival;
X	    if (i) {
X		if ((ops[i].ival & 255) == OBLOCK) {
X		    i = ops[i+1].ival;
X		    if (i) {
X			if ((ops[i].ival & 255) != OIF)
X			    i = 0;
X		    }
X		}
X		else
X		    i = 0;
X	    }
X	    if (i) {
X		str_cat(str,"els");
X		str_scat(str,fstr=walk(0,level,i,&numarg,P_MIN));
X		str_free(fstr);
X	    }
X	    else {
X		str_cat(str,"else ");
X		str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg,P_MIN));
X		str_free(fstr);
X	    }
X	}
X	break;
X    case OWHILE:
X	str = str_new(0);
X	str_set(str,"while (");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_cat(str,") ");
X	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
X	str_free(fstr);
X	break;
X    case OFOR:
X	str = str_new(0);
X	str_set(str,"for (");
X	str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	i = numarg;
X	if (i) {
X	    t = s = tmpstr->str_ptr;
X	    while (isalpha(*t) || isdigit(*t) || *t == '$' || *t == '_')
X		t++;
X	    i = t - s;
X	    if (i < 2)
X		i = 0;
X	}
X	str_cat(str,"; ");
X	fstr=walk(1,level,ops[node+2].ival,&numarg,P_MIN);
X	if (i && (t = index(fstr->str_ptr,0377))) {
X	    if (strnEQ(fstr->str_ptr,s,i))
X		*t = ' ';
X	}
X	str_scat(str,fstr);
X	str_free(fstr);
X	str_free(tmpstr);
X	str_cat(str,"; ");
X	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_cat(str,") ");
X	str_scat(str,fstr=walk(0,level,ops[node+4].ival,&numarg,P_MIN));
X	str_free(fstr);
X	break;
X    case OFORIN:
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	d = index(tmpstr->str_ptr,'$');
X	if (!d)
X	    fatal("Illegal for loop: %s",tmpstr->str_ptr);
X	s = index(d,'{');
X	if (!s)
X	    s = index(d,'[');
X	if (!s)
X	    fatal("Illegal for loop: %s",d);
X	*s++ = '\0';
X	for (t = s; i = *t; t++) {
X	    i &= 127;
X	    if (i == '}' || i == ']')
X		break;
X	}
X	if (*t)
X	    *t = '\0';
X	str = str_new(0);
X	str_set(str,d+1);
X	str_cat(str,"[]");
X	tmp2str = hfetch(symtab,str->str_ptr);
X	if (tmp2str && atoi(tmp2str->str_ptr)) {
X	    sprintf(tokenbuf,
X	      "foreach %s ($[ .. $#%s) ",
X	      s,
X	      d+1);
X	}
X	else {
X	    sprintf(tokenbuf,
X	      "foreach %s (keys %%%s) ",
X	      s,
X	      d+1);
X	}
X	str_set(str,tokenbuf);
X	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
X	str_free(fstr);
X	str_free(tmpstr);
X	break;
X    case OBLOCK:
X	str = str_new(0);
X	str_set(str,"{");
X	if (len >= 2 && ops[node+2].ival) {
X	    str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg,P_MIN));
X	    str_free(fstr);
X	}
X	fixtab(str,++level);
X	str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg,P_MIN));
X	str_free(fstr);
X	addsemi(str);
X	fixtab(str,--level);
X	str_cat(str,"}\n");
X	tab(str,level);
X	if (len >= 3) {
X	    str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg,P_MIN));
X	    str_free(fstr);
X	}
X	break;
X    default:
X      def:
X	if (len) {
X	    if (len > 5)
X		fatal("Garbage length in walk");
X	    str = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	    for (i = 2; i<= len; i++) {
X		str_scat(str,fstr=walk(0,level,ops[node+i].ival,&numarg,P_MIN));
X		str_free(fstr);
X	    }
X	}
X	else {
X	    str = Nullstr;
X	}
X	break;
X    }
X    if (!str)
X	str = str_new(0);
X
X    if (useval && prec < minprec) {		/* need parens? */
X	fstr = str_new(str->str_cur+2);
X	str_nset(fstr,"(",1);
X	str_scat(fstr,str);
X	str_ncat(fstr,")",1);
X	str_free(str);
X	str = fstr;
X    }
X
X    *numericptr = numeric;
X#ifdef DEBUGGING
X    if (debug & 4) {
X	printf("%3d %5d %15s %d %4d ",level,node,opname[type],len,str->str_cur);
X	for (t = str->str_ptr; *t && t - str->str_ptr < 40; t++)
X	    if (*t == '\n')
X		printf("\\n");
X	    else if (*t == '\t')
X		printf("\\t");
X	    else
X		putchar(*t);
X	putchar('\n');
X    }
X#endif
X    return str;
X}
X
Xtab(str,lvl)
Xregister STR *str;
Xregister int lvl;
X{
X    while (lvl > 1) {
X	str_cat(str,"\t");
X	lvl -= 2;
X    }
X    if (lvl)
X	str_cat(str,"    ");
X}
X
Xfixtab(str,lvl)
Xregister STR *str;
Xregister int lvl;
X{
X    register char *s;
X
X    /* strip trailing white space */
X
X    s = str->str_ptr+str->str_cur - 1;
X    while (s >= str->str_ptr && (*s == ' ' || *s == '\t' || *s == '\n'))
X	s--;
X    s[1] = '\0';
X    str->str_cur = s + 1 - str->str_ptr;
X    if (s >= str->str_ptr && *s != '\n')
X	str_cat(str,"\n");
X
X    tab(str,lvl);
X}
X
Xaddsemi(str)
Xregister STR *str;
X{
X    register char *s;
X
X    s = str->str_ptr+str->str_cur - 1;
X    while (s >= str->str_ptr && (*s == ' ' || *s == '\t' || *s == '\n'))
X	s--;
X    if (s >= str->str_ptr && *s != ';' && *s != '}')
X	str_cat(str,";");
X}
X
Xemit_split(str,level)
Xregister STR *str;
Xint level;
X{
X    register int i;
X
X    if (split_to_array)
X	str_cat(str,"@Fld");
X    else {
X	str_cat(str,"(");
X	for (i = 1; i < maxfld; i++) {
X	    if (i <= arymax)
X		sprintf(tokenbuf,"$%s,",nameary[i]);
X	    else
X		sprintf(tokenbuf,"$Fld%d,",i);
X	    str_cat(str,tokenbuf);
X	}
X	if (maxfld <= arymax)
X	    sprintf(tokenbuf,"$%s)",nameary[maxfld]);
X	else
X	    sprintf(tokenbuf,"$Fld%d)",maxfld);
X	str_cat(str,tokenbuf);
X    }
X    if (const_FS) {
X	sprintf(tokenbuf," = split(/[%c\\n]/, $_, 9999);\n",const_FS);
X	str_cat(str,tokenbuf);
X    }
X    else if (saw_FS)
X	str_cat(str," = split($FS, $_, 9999);\n");
X    else
X	str_cat(str," = split(' ', $_, 9999);\n");
X    tab(str,level);
X}
X
Xprewalk(numit,level,node,numericptr)
Xint numit;
Xint level;
Xregister int node;
Xint *numericptr;
X{
X    register int len;
X    register int type;
X    register int i;
X    char *t;
X    char *d, *s;
X    int numarg;
X    int numeric = FALSE;
X    STR *tmpstr;
X    STR *tmp2str;
X
X    if (!node) {
X	*numericptr = 0;
X	return 0;
X    }
X    type = ops[node].ival;
X    len = type >> 8;
X    type &= 255;
X    switch (type) {
X    case OPROG:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	if (ops[node+2].ival) {
X	    prewalk(0,level,ops[node+2].ival,&numarg);
X	}
X	++level;
X	prewalk(0,level,ops[node+3].ival,&numarg);
X	--level;
X	if (ops[node+3].ival) {
X	    prewalk(0,level,ops[node+4].ival,&numarg);
X	}
X	break;
X    case OHUNKS:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	if (len == 3) {
X	    prewalk(0,level,ops[node+3].ival,&numarg);
X	}
X	break;
X    case ORANGE:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	prewalk(1,level,ops[node+2].ival,&numarg);
X	break;
X    case OPAT:
X	goto def;
X    case OREGEX:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	break;
X    case OHUNK:
X	if (len == 1) {
X	    prewalk(0,level,ops[node+1].ival,&numarg);
X	}
X	else {
X	    i = prewalk(0,level,ops[node+1].ival,&numarg);
X	    if (i) {
X		++level;
X		prewalk(0,level,ops[node+2].ival,&numarg);
X		--level;
X	    }
X	    else {
X		prewalk(0,level,ops[node+2].ival,&numarg);
X	    }
X	}
X	break;
X    case OPPAREN:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	break;
X    case OPANDAND:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	break;
X    case OPOROR:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	break;
X    case OPNOT:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	break;
X    case OCPAREN:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	numeric |= numarg;
X	break;
X    case OCANDAND:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	break;
X    case OCOROR:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	break;
X    case OCNOT:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case ORELOP:
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	numeric |= numarg;
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+3].ival,&numarg);
X	numeric |= numarg;
X	numeric = 1;
X	break;
X    case ORPAREN:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	numeric |= numarg;
X	break;
X    case OMATCHOP:
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+3].ival,&numarg);
X	numeric = 1;
X	break;
X    case OMPAREN:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	numeric |= numarg;
X	break;
X    case OCONCAT:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	break;
X    case OASSIGN:
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+3].ival,&numarg);
X	if (numarg || strlen(ops[ops[node+1].ival+1].cval) > 1) {
X	    numericize(ops[node+2].ival);
X	    if (!numarg)
X		numericize(ops[node+3].ival);
X	}
X	numeric |= numarg;
X	break;
X    case OADD:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	prewalk(1,level,ops[node+2].ival,&numarg);
X	numeric = 1;
X	break;
X    case OSUBTRACT:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	prewalk(1,level,ops[node+2].ival,&numarg);
X	numeric = 1;
X	break;
X    case OMULT:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	prewalk(1,level,ops[node+2].ival,&numarg);
X	numeric = 1;
X	break;
X    case ODIV:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	prewalk(1,level,ops[node+2].ival,&numarg);
X	numeric = 1;
X	break;
X    case OPOW:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	prewalk(1,level,ops[node+2].ival,&numarg);
X	numeric = 1;
X	break;
X    case OMOD:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	prewalk(1,level,ops[node+2].ival,&numarg);
X	numeric = 1;
X	break;
X    case OPOSTINCR:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case OPOSTDECR:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case OPREINCR:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case OPREDECR:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case OUMINUS:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case OUPLUS:
X	prewalk(1,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case OPAREN:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	numeric |= numarg;
X	break;
X    case OGETLINE:
X	break;
X    case OSPRINTF:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	break;
X    case OSUBSTR:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(1,level,ops[node+2].ival,&numarg);
X	if (len == 3) {
X	    prewalk(1,level,ops[node+3].ival,&numarg);
X	}
X	break;
X    case OSTRING:
X	break;
X    case OSPLIT:
X	numeric = 1;
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	if (len == 3)
X	    prewalk(0,level,ops[node+3].ival,&numarg);
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	break;
X    case OINDEX:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	numeric = 1;
X	break;
X    case OMATCH:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	numeric = 1;
X	break;
X    case OUSERDEF:
X	subretnum = FALSE;
X	--level;
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg,P_MIN);
X	++level;
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	prewalk(0,level,ops[node+4].ival,&numarg);
X	prewalk(0,level,ops[node+5].ival,&numarg);
X	--level;
X	str_cat(tmpstr,"(");
X	tmp2str = str_new(0);
X	if (subretnum || numarg)
X	    str_set(tmp2str,"1");
X	hstore(symtab,tmpstr->str_ptr,tmp2str);
X	str_free(tmpstr);
X	level++;
X	break;
X    case ORETURN:
X	if (len > 0) {
X	    prewalk(0,level,ops[node+1].ival,&numarg);
X	    if (numarg)
X		subretnum = TRUE;
X	}
X	break;
X    case OUSERFUN:
X	tmp2str = str_new(0);
X	str_scat(tmp2str,tmpstr=walk(1,level,ops[node+1].ival,&numarg,P_MIN));
X	fixrargs(tmpstr->str_ptr,ops[node+2].ival,0);
X	str_free(tmpstr);
X	str_cat(tmp2str,"(");
X	tmpstr = hfetch(symtab,tmp2str->str_ptr);
X	if (tmpstr && tmpstr->str_ptr)
X	    numeric |= atoi(tmpstr->str_ptr);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	str_free(tmp2str);
X	break;
X    case OGSUB:
X    case OSUB:
X	if (len >= 3)
X	    prewalk(0,level,ops[node+3].ival,&numarg);
X	prewalk(0,level,ops[ops[node+2].ival+1].ival,&numarg);
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case ONUM:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case OSTR:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	break;
X    case ODEFINED:
X    case ODELETE:
X    case OSTAR:
X    case OVAR:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	if (len == 1) {
X	    if (numit)
X		numericize(node);
X	}
X	else {
X	    prewalk(0,level,ops[node+2].ival,&numarg);
X	}
X	break;
X    case OFLD:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	break;
X    case OVFLD:
X	i = ops[node+1].ival;
X	prewalk(0,level,i,&numarg);
X	break;
X    case OJUNK:
X	goto def;
X    case OSNEWLINE:
X	break;
X    case ONEWLINE:
X	break;
X    case OSCOMMENT:
X	break;
X    case OCOMMENT:
X	break;
X    case OCOMMA:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	prewalk(0,level,ops[node+3].ival,&numarg);
X	break;
X    case OSEMICOLON:
X	break;
X    case OSTATES:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	break;
X    case OSTATE:
X	if (len >= 1) {
X	    prewalk(0,level,ops[node+1].ival,&numarg);
X	    if (len >= 2) {
X		prewalk(0,level,ops[node+2].ival,&numarg);
X	    }
X	}
X	break;
X    case OCLOSE:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	break;
X    case OPRINTF:
X    case OPRINT:
X	if (len == 3) {		/* output redirection */
X	    prewalk(0,level,ops[node+3].ival,&numarg);
X	    prewalk(0,level,ops[node+2].ival,&numarg);
X	}
X	prewalk(0+(type==OPRINT),level,ops[node+1].ival,&numarg);
X	break;
X    case ORAND:
X	break;
X    case OSRAND:
X	goto maybe0;
X    case OATAN2:
X	goto maybe0;
X    case OSIN:
X	goto maybe0;
X    case OCOS:
X	goto maybe0;
X    case OSYSTEM:
X	goto maybe0;
X    case OLENGTH:
X	goto maybe0;
X    case OLOG:
X	goto maybe0;
X    case OEXP:
X	goto maybe0;
X    case OSQRT:
X	goto maybe0;
X    case OINT:
X      maybe0:
X	numeric = 1;
X	if (len > 0)
X	    prewalk(type != OLENGTH && type != OSYSTEM,
X	      level,ops[node+1].ival,&numarg);
X	break;
X    case OBREAK:
X	break;
X    case ONEXT:
X	break;
X    case OEXIT:
X	if (len == 1) {
X	    prewalk(1,level,ops[node+1].ival,&numarg);
X	}
X	break;
X    case OCONTINUE:
X	break;
X    case OREDIR:
X	goto def;
X    case OIF:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	if (len == 3) {
X	    prewalk(0,level,ops[node+3].ival,&numarg);
X	}
X	break;
X    case OWHILE:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	break;
X    case OFOR:
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	prewalk(0,level,ops[node+3].ival,&numarg);
X	prewalk(0,level,ops[node+4].ival,&numarg);
X	break;
X    case OFORIN:
X	prewalk(0,level,ops[node+2].ival,&numarg);
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	break;
X    case OBLOCK:
X	if (len == 2) {
X	    prewalk(0,level,ops[node+2].ival,&numarg);
X	}
X	++level;
X	prewalk(0,level,ops[node+1].ival,&numarg);
X	--level;
X	break;
X    default:
X      def:
X	if (len) {
X	    if (len > 5)
X		fatal("Garbage length in prewalk");
X	    prewalk(0,level,ops[node+1].ival,&numarg);
X	    for (i = 2; i<= len; i++) {
X		prewalk(0,level,ops[node+i].ival,&numarg);
X	    }
X	}
X	break;
X    }
X    *numericptr = numeric;
X    return 1;
X}
X
Xnumericize(node)
Xregister int node;
X{
X    register int len;
X    register int type;
X    register int i;
X    STR *tmpstr;
X    STR *tmp2str;
X    int numarg;
X
X    type = ops[node].ival;
X    len = type >> 8;
X    type &= 255;
X    if (type == OVAR && len == 1) {
X	tmpstr=walk(0,0,ops[node+1].ival,&numarg,P_MIN);
X	tmp2str = str_make("1");
X	hstore(symtab,tmpstr->str_ptr,tmp2str);
X    }
X}
!STUFFY!FUNK!
echo " "
echo "End of kit 9 (of 36)"
cat /dev/null >kit9isdone
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 24 25 26 27 28 29 30 31 32 33 34 35 36; 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."
	for combo in *:AA; do
	    if test -f "$combo"; then
		realfile=`basename $combo :AA`
		cat $realfile:[A-Z][A-Z] >$realfile
		rm -rf $realfile:[A-Z][A-Z]
	    fi
	done
	rm -rf kit*isdone
	chmod 755 Configure
	;;
    *)  echo "You have run$run."
	echo "You still need to run$todo."
	;;
esac
: Someone might mail this, so...
exit

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.