[comp.sources.unix] v15i096: Perl, release 2, Part07/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 96
Archive-name: perl2/part07

#! /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 7 (of 15).  If kit 7 is complete, the line"
echo '"'"End of kit 7 (of 15)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir t x2p 2>/dev/null
echo Extracting x2p/walk.c
sed >x2p/walk.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: walk.c,v 2.0 88/06/05 00:16:12 root Exp $
X *
X * $Log:	walk.c,v $
X * Revision 2.0  88/06/05  00:16:12  root
X * Baseline version 2.0.
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;
Xint maxtmp = 0;
Xchar *lparen;
Xchar *rparen;
X
XSTR *
Xwalk(useval,level,node,numericptr)
Xint useval;
Xint level;
Xregister int node;
Xint *numericptr;
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    char *t;
X    char *d, *s;
X    int numarg;
X    int numeric = FALSE;
X    STR *fstr;
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	str = walk(0,level,ops[node+1].ival,&numarg);
X	opens = str_new(0);
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 (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));
X	    str_free(fstr);
X	    str_cat(str,"\n\n");
X	}
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=walk(0,level,ops[node+3].ival,&numarg));
X	str_free(fstr);
X	fixtab(str,--level);
X	str_cat(str,"}\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));
X	    str_free(fstr);
X	    str_cat(str,"\n");
X	}
X	if (exitval)
X	    str_cat(str,"exit ExitValue;\n");
X	if (saw_getline) {
X	    str_cat(str,"\nsub Getline {\n    $_ = <>;\n");
X	    tab(str,++level);
X	    if (do_chop) {
X		str_cat(str,"chop;\t# strip record separator\n");
X		tab(str,level);
X	    }
X	    if (do_split)
X		emit_split(str,level);
X	    fixtab(str,--level);
X	    str_cat(str,"}\n");
X	}
X	if (do_fancy_opens) {
X	    str_cat(str,"\n\
Xsub Pick {\n\
X    ($name) = @_;\n\
X    $fh = $opened{$name};\n\
X    if (!$fh) {\n\
X	$nextfh == 0 && open(fh_0,$name);\n\
X	$nextfh == 1 && open(fh_1,$name);\n\
X	$nextfh == 2 && open(fh_2,$name);\n\
X	$nextfh == 3 && open(fh_3,$name);\n\
X	$nextfh == 4 && open(fh_4,$name);\n\
X	$nextfh == 5 && open(fh_5,$name);\n\
X	$nextfh == 6 && open(fh_6,$name);\n\
X	$nextfh == 7 && open(fh_7,$name);\n\
X	$nextfh == 8 && open(fh_8,$name);\n\
X	$nextfh == 9 && open(fh_9,$name);\n\
X	$fh = $opened{$name} = 'fh_' . $nextfh++;\n\
X    }\n\
X    select($fh);\n\
X}\n\
X");
X	}
X	break;
X    case OHUNKS:
X	str = walk(0,level,ops[node+1].ival,&numarg);
X	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	if (len == 3) {
X	    str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
X	    str_free(fstr);
X	}
X	else {
X	}
X	break;
X    case ORANGE:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str," .. ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
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);
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);
X	    str_cat(str," if ");
X	    str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg));
X	    str_free(fstr);
X	    str_cat(str,";");
X	}
X	else {
X	    tmpstr = walk(0,level,ops[node+1].ival,&numarg);
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));
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);
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));
X	str_free(fstr);
X	str_cat(str,")");
X	break;
X    case OPANDAND:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str," && ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	break;
X    case OPOROR:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str," || ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	break;
X    case OPNOT:
X	str = str_new(0);
X	str_set(str,"!");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
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));
X	str_free(fstr);
X	numeric |= numarg;
X	str_cat(str,")");
X	break;
X    case OCANDAND:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	str_cat(str," && ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	break;
X    case OCOROR:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	str_cat(str," || ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	break;
X    case OCNOT:
X	str = str_new(0);
X	str_set(str,"!");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case ORELOP:
X	str = walk(1,level,ops[node+2].ival,&numarg);
X	numeric |= numarg;
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg);
X	tmp2str = walk(1,level,ops[node+3].ival,&numarg);
X	numeric |= numarg;
X	if (!numeric) {
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));
X	str_free(fstr);
X	numeric |= numarg;
X	str_cat(str,")");
X	break;
X    case OMATCHOP:
X	str = walk(1,level,ops[node+2].ival,&numarg);
X	str_cat(str," ");
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg);
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));
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,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg));
X	str_free(fstr);
X	numeric |= numarg;
X	str_cat(str,")");
X	break;
X    case OCONCAT:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str," . ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	break;
X    case OASSIGN:
X	str = walk(0,level,ops[node+2].ival,&numarg);
X	str_cat(str," ");
X	tmpstr = walk(0,level,ops[node+1].ival,&numarg);
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));
X	str_free(fstr);
X	numeric |= numarg;
X	break;
X    case OADD:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str," + ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OSUB:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str," - ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OMULT:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str," * ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case ODIV:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str," / ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OMOD:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str," % ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OPOSTINCR:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str,"++");
X	numeric = 1;
X	break;
X    case OPOSTDECR:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str,"--");
X	numeric = 1;
X	break;
X    case OPREINCR:
X	str = str_new(0);
X	str_set(str,"++");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OPREDECR:
X	str = str_new(0);
X	str_set(str,"--");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X	str_free(fstr);
X	numeric = 1;
X	break;
X    case OUMINUS:
X	str = str_new(0);
X	str_set(str,"-");
X	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
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,fstr=walk(useval != 0,level,ops[node+1].ival,&numarg));
X	str_free(fstr);
X	str_cat(str,")");
X	numeric |= numarg;
X	break;
X    case OGETLINE:
X	str = str_new(0);
X	str_set(str,"do Getline()");
X	saw_getline = TRUE;
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));
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));
X	str_free(fstr);
X	str_cat(str,", ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
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));
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);
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);
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
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));
X	str_free(fstr);
X	str_cat(str,")");
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));
X	str_free(fstr);
X	str_cat(str,", ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	str_cat(str,")");
X	numeric = 1;
X	break;
X    case ONUM:
X	str = walk(1,level,ops[node+1].ival,&numarg);
X	numeric = 1;
X	break;
X    case OSTR:
X	tmpstr = walk(1,level,ops[node+1].ival,&numarg);
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':
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 OVAR:
X	str = str_new(0);
X	str_set(str,"$");
X	str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg));
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,"$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	}
X	else {
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));
X	    str_free(fstr);
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	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));
X	    str_free(fstr);
X	    str_cat(str,"]");
X	}
X	else {
X	    i = atoi(walk(1,level,ops[node+1].ival,&numarg)->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);
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);
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);
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	str = walk(1,level,ops[node+1].ival,&numarg);
X	str_cat(str,", ");
X	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
X	str_free(fstr);
X	break;
X    case OSEMICOLON:
X	str = str_new(1);
X	str_set(str,"; ");
X	break;
X    case OSTATES:
X	str = walk(0,level,ops[node+1].ival,&numarg);
X	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
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));
X	    str_free(fstr);
X	    if (len >= 2) {
X		tmpstr = walk(0,level,ops[node+2].ival,&numarg);
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 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);
X	    tmp2str = walk(1,level,ops[node+2].ival,&numarg);
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		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		str_free(tmpstr);
X		str_free(tmp2str);
X		safefree(s);
X		safefree(d);
X	    }
X	    else {
X		sprintf(tokenbuf,"do Pick('%s' . (%s)) &&\n",
X		   tmp2str->str_ptr, tmpstr->str_ptr);
X		str_cat(str,tokenbuf);
X		tab(str,level+1);
X		*tokenbuf = '\0';
X		str_free(tmpstr);
X		str_free(tmp2str);
X		lparen = "(";
X		rparen = ")";
X	    }
X	}
X	else
X	    strcpy(tokenbuf,"stdout");
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);
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 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);
X	else
X	    tmpstr = str_new(0);;
X	if (!*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	    str_set(str,"exit");
X	    if (len == 1) {
X		str_cat(str," ");
X		exitval = TRUE;
X		str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X		str_free(fstr);
X	    }
X	}
X	else {
X	    if (len == 1) {
X		str_set(str,"ExitValue = ");
X		exitval = TRUE;
X		str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
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));
X	str_free(fstr);
X	str_cat(str,") ");
X	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
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));
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));
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));
X	str_free(fstr);
X	str_cat(str,") ");
X	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
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));
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);
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));
X	str_free(fstr);
X	str_cat(str,") ");
X	str_scat(str,fstr=walk(0,level,ops[node+4].ival,&numarg));
X	str_free(fstr);
X	break;
X    case OFORIN:
X	tmpstr=walk(0,level,ops[node+2].ival,&numarg);
X	str = str_new(0);
X	str_sset(str,tmpstr);
X	str_cat(str,"[]");
X	tmp2str = hfetch(symtab,str->str_ptr);
X	if (tmp2str && atoi(tmp2str->str_ptr)) {
X	    fstr=walk(1,level,ops[node+1].ival,&numarg);
X	    sprintf(tokenbuf,
X	      "foreach $%s (@%s) ",
X	      fstr->str_ptr,
X	      tmpstr->str_ptr);
X	    str_set(str,tokenbuf);
X	    str_free(fstr);
X	    str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
X	    str_free(fstr);
X	}
X	else {
X	    str_set(str,"while (($");
X	    str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
X	    str_free(fstr);
X	    str_cat(str,",$junkval) = each(");
X	    str_scat(str,tmpstr);
X	    str_cat(str,")) ");
X	    str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
X	    str_free(fstr);
X	}
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));
X	    str_free(fstr);
X	}
X	fixtab(str,++level);
X	str_scat(str,fstr=walk(0,level,ops[node+1].ival,&numarg));
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));
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);
X	    for (i = 2; i<= len; i++) {
X		str_scat(str,fstr=walk(0,level,ops[node+i].ival,&numarg));
X		str_free(fstr);
X	    }
X	}
X	else {
X	    str = Nullstr;
X	}
X	break;
X    }
X    if (!str)
X	str = str_new(0);
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'))
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]/);\n",const_FS);
X	str_cat(str,tokenbuf);
X    }
X    else if (saw_FS)
X	str_cat(str," = split($FS);\n");
X    else
X	str_cat(str," = split(' ');\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
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 OSUB:
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 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 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 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	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 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 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,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	prewalk(0,level,ops[node+3].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);
X	tmp2str = str_make("1");
X	hstore(symtab,tmpstr->str_ptr,tmp2str);
X    }
X}
!STUFFY!FUNK!
echo Extracting str.c
sed >str.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: str.c,v 2.0 88/06/05 00:11:07 root Exp $
X *
X * $Log:	str.c,v $
X * Revision 2.0  88/06/05  00:11:07  root
X * Baseline version 2.0.
X * 
X */
X
X#include "EXTERN.h"
X#include "perl.h"
X
Xstr_reset(s)
Xregister char *s;
X{
X    register STAB *stab;
X    register STR *str;
X    register int i;
X    register int max;
X    register SPAT *spat;
X
X    if (!*s) {		/* reset ?? searches */
X	for (spat = spat_root; spat != Nullspat; spat = spat->spat_next) {
X	    spat->spat_flags &= ~SPAT_USED;
X	}
X	return;
X    }
X
X    /* reset variables */
X
X    while (*s) {
X	i = *s;
X	if (s[1] == '-') {
X	    s += 2;
X	}
X	max = *s++;
X	for ( ; i <= max; i++) {
X	    for (stab = stab_index[i]; stab; stab = stab->stab_next) {
X		str = stab->stab_val;
X		str->str_cur = 0;
X		str->str_nok = 0;
X		if (str->str_ptr != Nullch)
X		    str->str_ptr[0] = '\0';
X		if (stab->stab_array) {
X		    aclear(stab->stab_array);
X		}
X		if (stab->stab_hash) {
X		    hclear(stab->stab_hash);
X		}
X	    }
X	}
X    }
X}
X
Xstr_numset(str,num)
Xregister STR *str;
Xdouble num;
X{
X    str->str_nval = num;
X    str->str_pok = 0;		/* invalidate pointer */
X    str->str_nok = 1;		/* validate number */
X}
X
Xextern int errno;
X
Xchar *
Xstr_2ptr(str)
Xregister STR *str;
X{
X    register char *s;
X    int olderrno;
X
X    if (!str)
X	return "";
X    GROWSTR(&(str->str_ptr), &(str->str_len), 24);
X    s = str->str_ptr;
X    if (str->str_nok) {
X	olderrno = errno;	/* some Xenix systems wipe out errno here */
X#if defined(scs) && defined(ns32000)
X	gcvt(str->str_nval,20,s);
X#else
X#ifdef apollo
X	if (str->str_nval == 0.0)
X	    strcpy(s,"0");
X	else
X#endif /*apollo*/
X	sprintf(s,"%.20g",str->str_nval);
X#endif /*scs*/
X	errno = olderrno;
X	while (*s) s++;
X    }
X    else if (dowarn)
X	warn("Use of uninitialized variable");
X    *s = '\0';
X    str->str_cur = s - str->str_ptr;
X    str->str_pok = 1;
X#ifdef DEBUGGING
X    if (debug & 32)
X	fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
X#endif
X    return str->str_ptr;
X}
X
Xdouble
Xstr_2num(str)
Xregister STR *str;
X{
X    if (!str)
X	return 0.0;
X    if (str->str_len && str->str_pok)
X	str->str_nval = atof(str->str_ptr);
X    else {
X	if (dowarn)
X	    fprintf(stderr,"Use of uninitialized variable in %s line %ld.\n",
X		filename,(long)line);
X	str->str_nval = 0.0;
X    }
X    str->str_nok = 1;
X#ifdef DEBUGGING
X    if (debug & 32)
X	fprintf(stderr,"0x%lx num(%g)\n",str,str->str_nval);
X#endif
X    return str->str_nval;
X}
X
Xstr_sset(dstr,sstr)
XSTR *dstr;
Xregister STR *sstr;
X{
X    if (!sstr)
X	str_nset(dstr,No,0);
X    else if (sstr->str_nok)
X	str_numset(dstr,sstr->str_nval);
X    else if (sstr->str_pok)
X	str_nset(dstr,sstr->str_ptr,sstr->str_cur);
X    else
X	str_nset(dstr,"",0);
X}
X
Xstr_nset(str,ptr,len)
Xregister STR *str;
Xregister char *ptr;
Xregister int len;
X{
X    GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
X    bcopy(ptr,str->str_ptr,len);
X    str->str_cur = len;
X    *(str->str_ptr+str->str_cur) = '\0';
X    str->str_nok = 0;		/* invalidate number */
X    str->str_pok = 1;		/* validate pointer */
X}
X
Xstr_set(str,ptr)
Xregister STR *str;
Xregister char *ptr;
X{
X    register int len;
X
X    if (!ptr)
X	ptr = "";
X    len = strlen(ptr);
X    GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
X    bcopy(ptr,str->str_ptr,len+1);
X    str->str_cur = len;
X    str->str_nok = 0;		/* invalidate number */
X    str->str_pok = 1;		/* validate pointer */
X}
X
Xstr_chop(str,ptr)	/* like set but assuming ptr is in str */
Xregister STR *str;
Xregister char *ptr;
X{
X    if (!(str->str_pok))
X	str_2ptr(str);
X    str->str_cur -= (ptr - str->str_ptr);
X    bcopy(ptr,str->str_ptr, str->str_cur + 1);
X    str->str_nok = 0;		/* invalidate number */
X    str->str_pok = 1;		/* validate pointer */
X}
X
Xstr_ncat(str,ptr,len)
Xregister STR *str;
Xregister char *ptr;
Xregister int len;
X{
X    if (!(str->str_pok))
X	str_2ptr(str);
X    GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
X    bcopy(ptr,str->str_ptr+str->str_cur,len);
X    str->str_cur += len;
X    *(str->str_ptr+str->str_cur) = '\0';
X    str->str_nok = 0;		/* invalidate number */
X    str->str_pok = 1;		/* validate pointer */
X}
X
Xstr_scat(dstr,sstr)
XSTR *dstr;
Xregister STR *sstr;
X{
X    if (!sstr)
X	return;
X    if (!(sstr->str_pok))
X	str_2ptr(sstr);
X    if (sstr)
X	str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
X}
X
Xstr_cat(str,ptr)
Xregister STR *str;
Xregister char *ptr;
X{
X    register int len;
X
X    if (!ptr)
X	return;
X    if (!(str->str_pok))
X	str_2ptr(str);
X    len = strlen(ptr);
X    GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
X    bcopy(ptr,str->str_ptr+str->str_cur,len+1);
X    str->str_cur += len;
X    str->str_nok = 0;		/* invalidate number */
X    str->str_pok = 1;		/* validate pointer */
X}
X
Xchar *
Xstr_append_till(str,from,delim,keeplist)
Xregister STR *str;
Xregister char *from;
Xregister int delim;
Xchar *keeplist;
X{
X    register char *to;
X    register int len;
X
X    if (!from)
X	return Nullch;
X    len = strlen(from);
X    GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + len + 1);
X    str->str_nok = 0;		/* invalidate number */
X    str->str_pok = 1;		/* validate pointer */
X    to = str->str_ptr+str->str_cur;
X    for (; *from; from++,to++) {
X	if (*from == '\\' && from[1] && delim != '\\') {
X	    if (!keeplist) {
X		if (from[1] == delim || from[1] == '\\')
X		    from++;
X		else
X		    *to++ = *from++;
X	    }
X	    else if (index(keeplist,from[1]))
X		*to++ = *from++;
X	    else
X		from++;
X	}
X	else if (*from == delim)
X	    break;
X	*to = *from;
X    }
X    *to = '\0';
X    str->str_cur = to - str->str_ptr;
X    return from;
X}
X
XSTR *
Xstr_new(len)
Xint len;
X{
X    register STR *str;
X    
X    if (freestrroot) {
X	str = freestrroot;
X	freestrroot = str->str_link.str_next;
X	str->str_link.str_magic = Nullstab;
X    }
X    else {
X	str = (STR *) safemalloc(sizeof(STR));
X	bzero((char*)str,sizeof(STR));
X    }
X    if (len)
X	GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
X    return str;
X}
X
Xvoid
Xstr_grow(str,len)
Xregister STR *str;
Xint len;
X{
X    if (len && str)
X	GROWSTR(&(str->str_ptr), &(str->str_len), len + 1);
X}
X
X/* make str point to what nstr did */
X
Xvoid
Xstr_replace(str,nstr)
Xregister STR *str;
Xregister STR *nstr;
X{
X    safefree(str->str_ptr);
X    str->str_ptr = nstr->str_ptr;
X    str->str_len = nstr->str_len;
X    str->str_cur = nstr->str_cur;
X    str->str_pok = nstr->str_pok;
X    if (str->str_nok = nstr->str_nok)
X	str->str_nval = nstr->str_nval;
X    safefree((char*)nstr);
X}
X
Xvoid
Xstr_free(str)
Xregister STR *str;
X{
X    if (!str)
X	return;
X    if (str->str_len)
X	str->str_ptr[0] = '\0';
X    str->str_cur = 0;
X    str->str_nok = 0;
X    str->str_pok = 0;
X    str->str_link.str_next = freestrroot;
X    freestrroot = str;
X}
X
Xstr_len(str)
Xregister STR *str;
X{
X    if (!str)
X	return 0;
X    if (!(str->str_pok))
X	str_2ptr(str);
X    if (str->str_len)
X	return str->str_cur;
X    else
X	return 0;
X}
X
Xchar *
Xstr_gets(str,fp)
Xregister STR *str;
Xregister FILE *fp;
X{
X#ifdef STDSTDIO		/* Here is some breathtakingly efficient cheating */
X
X    register char *bp;		/* we're going to steal some values */
X    register int cnt;		/*  from the stdio struct and put EVERYTHING */
X    register STDCHAR *ptr;	/*   in the innermost loop into registers */
X    register char newline = record_separator;/* (assuming >= 6 registers) */
X    int i;
X    int bpx;
X    int obpx;
X    register int get_paragraph;
X    register char *oldbp;
X
X    if (get_paragraph = !newline) {	/* yes, that's an assignment */
X	newline = '\n';
X	oldbp = Nullch;			/* remember last \n position (none) */
X    }
X    cnt = fp->_cnt;			/* get count into register */
X    str->str_nok = 0;			/* invalidate number */
X    str->str_pok = 1;			/* validate pointer */
X    if (str->str_len <= cnt)		/* make sure we have the room */
X	GROWSTR(&(str->str_ptr), &(str->str_len), cnt+1);
X    bp = str->str_ptr;			/* move these two too to registers */
X    ptr = fp->_ptr;
X    for (;;) {
X      screamer:
X	while (--cnt >= 0) {			/* this */	/* eat */
X	    if ((*bp++ = *ptr++) == newline)	/* really */	/* dust */
X		goto thats_all_folks;		/* screams */	/* sed :-) */ 
X	}
X	
X	fp->_cnt = cnt;			/* deregisterize cnt and ptr */
X	fp->_ptr = ptr;
X	i = _filbuf(fp);		/* get more characters */
X	cnt = fp->_cnt;
X	ptr = fp->_ptr;			/* reregisterize cnt and ptr */
X
X	bpx = bp - str->str_ptr;	/* prepare for possible relocation */
X	if (get_paragraph && oldbp)
X	    obpx = oldbp - str->str_ptr;
X	GROWSTR(&(str->str_ptr), &(str->str_len), bpx + cnt + 2);
X	bp = str->str_ptr + bpx;	/* reconstitute our pointer */
X	if (get_paragraph && oldbp)
X	    oldbp = str->str_ptr + obpx;
X
X	if (i == newline) {		/* all done for now? */
X	    *bp++ = i;
X	    goto thats_all_folks;
X	}
X	else if (i == EOF)		/* all done for ever? */
X	    goto thats_really_all_folks;
X	*bp++ = i;			/* now go back to screaming loop */
X    }
X
Xthats_all_folks:
X    if (get_paragraph && bp - 1 != oldbp) {
X	oldbp = bp;	/* remember where this newline was */
X	goto screamer;	/* and go back to the fray */
X    }
Xthats_really_all_folks:
X    fp->_cnt = cnt;			/* put these back or we're in trouble */
X    fp->_ptr = ptr;
X    *bp = '\0';
X    str->str_cur = bp - str->str_ptr;	/* set length */
X
X#else /* !STDSTDIO */	/* The big, slow, and stupid way */
X
X    static char buf[4192];
X
X    if (fgets(buf, sizeof buf, fp) != Nullch)
X	str_set(str, buf);
X    else
X	str_set(str, No);
X
X#endif /* STDSTDIO */
X
X    return str->str_cur ? str->str_ptr : Nullch;
X}
X
X
XSTR *
Xinterp(str,s)
Xregister STR *str;
Xregister char *s;
X{
X    register char *t = s;
X    char *envsave = envname;
X    envname = Nullch;
X
X    str_set(str,"");
X    while (*s) {
X	if (*s == '\\' && s[1] == '\\') {
X	    str_ncat(str, t, s++ - t);
X	    t = s++;
X	}
X	else if (*s == '\\' && s[1] == '$') {
X	    str_ncat(str, t, s++ - t);
X	    t = s++;
X	}
X	else if (*s == '$' && s[1] && s[1] != '|') {
X	    str_ncat(str,t,s-t);
X	    s = scanreg(s,tokenbuf);
X	    str_cat(str,reg_get(tokenbuf));
X	    t = s;
X	}
X	else
X	    s++;
X    }
X    envname = envsave;
X    str_ncat(str,t,s-t);
X    return str;
X}
X
Xvoid
Xstr_inc(str)
Xregister STR *str;
X{
X    register char *d;
X
X    if (!str)
X	return;
X    if (str->str_nok) {
X	str->str_nval += 1.0;
X	str->str_pok = 0;
X	return;
X    }
X    if (!str->str_pok || !*str->str_ptr) {
X	str->str_nval = 1.0;
X	str->str_nok = 1;
X	return;
X    }
X    d = str->str_ptr;
X    while (isalpha(*d)) d++;
X    while (isdigit(*d)) d++;
X    if (*d) {
X        str_numset(str,atof(str->str_ptr) + 1.0);  /* punt */
X	return;
X    }
X    d--;
X    while (d >= str->str_ptr) {
X	if (isdigit(*d)) {
X	    if (++*d <= '9')
X		return;
X	    *(d--) = '0';
X	}
X	else {
X	    ++*d;
X	    if (isalpha(*d))
X		return;
X	    *(d--) -= 'z' - 'a' + 1;
X	}
X    }
X    /* oh,oh, the number grew */
X    GROWSTR(&(str->str_ptr), &(str->str_len), str->str_cur + 2);
X    str->str_cur++;
X    for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
X	*d = d[-1];
X    if (isdigit(d[1]))
X	*d = '1';
X    else
X	*d = d[1];
X}
X
Xvoid
Xstr_dec(str)
Xregister STR *str;
X{
X    if (!str)
X	return;
X    if (str->str_nok) {
X	str->str_nval -= 1.0;
X	str->str_pok = 0;
X	return;
X    }
X    if (!str->str_pok) {
X	str->str_nval = -1.0;
X	str->str_nok = 1;
X	return;
X    }
X    str_numset(str,atof(str->str_ptr) - 1.0);
X}
X
X/* make a string that will exist for the duration of the expression eval */
X
XSTR *
Xstr_static(oldstr)
XSTR *oldstr;
X{
X    register STR *str = str_new(0);
X    static long tmps_size = -1;
X
X    str_sset(str,oldstr);
X    if (++tmps_max > tmps_size) {
X	tmps_size = tmps_max;
X	if (!(tmps_size & 127)) {
X	    if (tmps_size)
X		tmps_list = (STR**)saferealloc((char*)tmps_list,
X		    (MEM_SIZE)((tmps_size + 128) * sizeof(STR*)) );
X	    else
X		tmps_list = (STR**)safemalloc(128 * sizeof(char*));
X	}
X    }
X    tmps_list[tmps_max] = str;
X    return str;
X}
X
XSTR *
Xstr_make(s)
Xchar *s;
X{
X    register STR *str = str_new(0);
X
X    str_set(str,s);
X    return str;
X}
X
XSTR *
Xstr_nmake(n)
Xdouble n;
X{
X    register STR *str = str_new(0);
X
X    str_numset(str,n);
X    return str;
X}
!STUFFY!FUNK!
echo Extracting t/op.split
sed >t/op.split <<'!STUFFY!FUNK!' -e 's/X//'
X#!./perl
X
X# $Header: op.split,v 2.0 88/06/05 00:14:37 root Exp $
X
Xprint "1..7\n";
X
X$FS = ':';
X
X$_ = 'a:b:c';
X
X($a,$b,$c) = split($FS,$_);
X
Xif (join(';',$a,$b,$c) eq 'a;b;c') {print "ok 1\n";} else {print "not ok 1\n";}
X
X@ary = split(/:b:/);
Xif (join("$_",@ary) eq 'aa:b:cc') {print "ok 2\n";} else {print "not ok 2\n";}
X
X$_ = "abc\n";
X@ary = split(//);
Xif (join(".",@ary) eq "a.b.c.\n") {print "ok 3\n";} else {print "not ok 3\n";}
X
X$_ = "a:b:c::::";
X@ary = split(/:/);
Xif (join(".",@ary) eq "a.b.c") {print "ok 4\n";} else {print "not ok 4\n";}
X
X$_ = join(':',split(' ',"    a b\tc \t d "));
Xif ($_ eq 'a:b:c:d') {print "ok 5\n";} else {print "not ok 5 #$_#\n";}
X
X$_ = join(':',split(/ */,"foo  bar bie\tdoll"));
Xif ($_ eq "f:o:o:b:a:r:b:i:e:\t:d:o:l:l")
X	{print "ok 6\n";} else {print "not ok 6\n";}
X
X$_ = join(':', 'foo', split(/ /,'a b  c'), 'bar');
Xif ($_ eq "foo:a:b::c:bar") {print "ok 7\n";} else {print "not ok 7 $_\n";}
X
!STUFFY!FUNK!
echo ""
echo "End of kit 7 (of 15)"
cat /dev/null >kit7isdone
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.