[comp.sources.bugs] perl 2.0 patch #5

lroot@devvax.JPL.NASA.GOV (The Superuser) (07/13/88)

System: perl version 2.0
Patch #: 5
Priority: MEDIUM
Subject: patch2 continued

Description:
	See patch 2.

Fix:	From rn, say "| patch -p -N -d DIR", where DIR is your perl source
	directory.  Outside of rn, say "cd DIR; patch -p -N <thisarticle".
	If you don't have the patch program, apply the following by hand,
	or get patch (version 2.0, latest patchlevel).

	After patching:
		Configure -d
		make depend
		make
		make test
		make install
		cd x2p
		make depend
		make
		make install

	If patch indicates that patchlevel is the wrong version, you may need
	to apply one or more previous patches, or the patch may already
	have been applied.  See the patchlevel.h file to find out what has or
	has not been applied.  In any event, don't continue with the patch.

	If you are missing previous patches they can be obtained from me:

	Larry Wall
	lwall@jpl-devvax.jpl.nasa.gov

	If you send a mail message of the following form it will greatly speed
	processing:

	Subject: Command
	@SH mailpatch PATH perl 2.0 LIST
		   ^ note the c

	where PATH is a return path FROM ME TO YOU either in Internet notation,
	or in bang notation from some well-known host, and LIST is the number
	of one or more patches you need, separated by spaces, commas, and/or
	hyphens.  Saying 35- says everything from 35 to the end.


	You can also get the patches via anonymous FTP from
	jpl-devvax.jpl.nasa.gov (128.149.8.43).

Index: patchlevel.h
Prereq: 4
1c1
< #define PATCHLEVEL 4
---
> #define PATCHLEVEL 5


Index: x2p/s2p
Prereq: 2.0
*** x2p/s2p.old	Mon Jul 11 23:40:01 1988
--- x2p/s2p	Mon Jul 11 23:40:02 1988
***************
*** 1,8 ****
  #!/usr/bin/perl
  
! # $Header: s2p,v 2.0 88/06/05 00:15:55 root Exp $
  #
  # $Log:	s2p,v $
  # Revision 2.0  88/06/05  00:15:55  root
  # Baseline version 2.0.
  # 
--- 1,11 ----
  #!/usr/bin/perl
  
! # $Header: s2p,v 2.0.1.1 88/07/11 23:26:23 root Exp $
  #
  # $Log:	s2p,v $
+ # Revision 2.0.1.1  88/07/11  23:26:23  root
+ # patch2: s2p didn't put a proper prologue on output script
+ # 
  # Revision 2.0  88/06/05  00:15:55  root
  # Baseline version 2.0.
  # 
***************
*** 243,249 ****
      }
      close head;
  
!     print "#!/bin/perl\n\n";
      open(body,"cc -E /tmp/sperl2$$.c |") ||
  	do Die("Can't reopen temp file");
      while (<body>) {
--- 246,256 ----
      }
      close head;
  
!     print '#!/usr/bin/perl
! eval "exec /usr/bin/perl -S $0 $*"
! 	if $running_under_some_shell;
! 
! ';
      open(body,"cc -E /tmp/sperl2$$.c |") ||
  	do Die("Can't reopen temp file");
      while (<body>) {

Index: x2p/walk.c
Prereq: 2.0
*** x2p/walk.c.old	Mon Jul 11 23:40:08 1988
--- x2p/walk.c	Mon Jul 11 23:40:11 1988
***************
*** 1,6 ****
! /* $Header: walk.c,v 2.0 88/06/05 00:16:12 root Exp $
   *
   * $Log:	walk.c,v $
   * Revision 2.0  88/06/05  00:16:12  root
   * Baseline version 2.0.
   * 
--- 1,13 ----
! /* $Header: walk.c,v 2.0.1.1 88/07/11 23:35:57 root Exp $
   *
   * $Log:	walk.c,v $
+  * Revision 2.0.1.1  88/07/11  23:35:57  root
+  * patch2: changes to support translation of 1985 awk
+  * patch2: handles multiple opens to same file better
+  * patch2: now handles absence of line actions
+  * patch2: now takes advantage of perl's filehandle indirection
+  * patch2: now uses keys() instead of each() to protect against deletes in loop
+  * 
   * Revision 2.0  88/06/05  00:16:12  root
   * Baseline version 2.0.
   * 
***************
*** 14,22 ****
--- 21,34 ----
  bool exitval = FALSE;
  bool realexit = FALSE;
  bool saw_getline = FALSE;
+ bool subretnum = FALSE;
+ bool saw_FNR = FALSE;
+ bool saw_argv0 = FALSE;
  int maxtmp = 0;
  char *lparen;
  char *rparen;
+ STR *subs;
+ STR *curargs = Nullstr;
  
  STR *
  walk(useval,level,node,numericptr)
***************
*** 31,36 ****
--- 43,49 ----
      register int i;
      register STR *tmpstr;
      STR *tmp2str;
+     STR *tmp3str;
      char *t;
      char *d, *s;
      int numarg;
***************
*** 47,54 ****
      type &= 255;
      switch (type) {
      case OPROG:
- 	str = walk(0,level,ops[node+1].ival,&numarg);
  	opens = str_new(0);
  	if (do_split && need_entire && !absmaxfld)
  	    split_to_array = TRUE;
  	if (do_split && split_to_array)
--- 60,68 ----
      type &= 255;
      switch (type) {
      case OPROG:
  	opens = str_new(0);
+ 	subs = str_new(0);
+ 	str = walk(0,level,ops[node+1].ival,&numarg);
  	if (do_split && need_entire && !absmaxfld)
  	    split_to_array = TRUE;
  	if (do_split && split_to_array)
***************
*** 79,84 ****
--- 93,101 ----
  	if (saw_ORS) {
  	    str_cat(str,"$\\ = \"\\n\";\t\t# set output record separator\n");
  	}
+ 	if (saw_argv0) {
+ 	    str_cat(str,"$ARGV0 = $0;\t\t# remember what we ran as\n");
+ 	}
  	if (str->str_cur > 20)
  	    str_cat(str,"\n");
  	if (ops[node+2].ival) {
***************
*** 86,121 ****
  	    str_free(fstr);
  	    str_cat(str,"\n\n");
  	}
! 	if (saw_line_op)
! 	    str_cat(str,"line: ");
! 	str_cat(str,"while (<>) {\n");
! 	tab(str,++level);
! 	if (saw_FS && !const_FS)
! 	    do_chop = TRUE;
! 	if (do_chop) {
! 	    str_cat(str,"chop;\t# strip record separator\n");
! 	    tab(str,level);
! 	}
! 	arymax = 0;
! 	if (namelist) {
! 	    while (isalpha(*namelist)) {
! 		for (d = tokenbuf,s=namelist;
! 		  isalpha(*s) || isdigit(*s) || *s == '_';
! 		  *d++ = *s++) ;
! 		*d = '\0';
! 		while (*s && !isalpha(*s)) s++;
! 		namelist = s;
! 		nameary[++arymax] = savestr(tokenbuf);
  	    }
  	}
! 	if (maxfld < arymax)
! 	    maxfld = arymax;
! 	if (do_split)
! 	    emit_split(str,level);
! 	str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
! 	str_free(fstr);
! 	fixtab(str,--level);
! 	str_cat(str,"}\n");
  	if (ops[node+4].ival) {
  	    realexit = TRUE;
  	    str_cat(str,"\n");
--- 103,145 ----
  	    str_free(fstr);
  	    str_cat(str,"\n\n");
  	}
! 	fstr = walk(0,level+1,ops[node+3].ival,&numarg);
! 	if (*fstr->str_ptr) {
! 	    if (saw_line_op)
! 		str_cat(str,"line: ");
! 	    str_cat(str,"while (<>) {\n");
! 	    tab(str,++level);
! 	    if (saw_FS && !const_FS)
! 		do_chop = TRUE;
! 	    if (do_chop) {
! 		str_cat(str,"chop;\t# strip record separator\n");
! 		tab(str,level);
  	    }
+ 	    arymax = 0;
+ 	    if (namelist) {
+ 		while (isalpha(*namelist)) {
+ 		    for (d = tokenbuf,s=namelist;
+ 		      isalpha(*s) || isdigit(*s) || *s == '_';
+ 		      *d++ = *s++) ;
+ 		    *d = '\0';
+ 		    while (*s && !isalpha(*s)) s++;
+ 		    namelist = s;
+ 		    nameary[++arymax] = savestr(tokenbuf);
+ 		}
+ 	    }
+ 	    if (maxfld < arymax)
+ 		maxfld = arymax;
+ 	    if (do_split)
+ 		emit_split(str,level);
+ 	    str_scat(str,fstr);
+ 	    str_free(fstr);
+ 	    fixtab(str,--level);
+ 	    str_cat(str,"}\n");
+ 	    if (saw_FNR)
+ 		str_cat(str,"continue {\n    $FNRbase = $. if eof;\n}\n");
  	}
! 	else
! 	    str_cat(str,"# (no line actions)\n");
  	if (ops[node+4].ival) {
  	    realexit = TRUE;
  	    str_cat(str,"\n");
***************
*** 126,162 ****
  	}
  	if (exitval)
  	    str_cat(str,"exit ExitValue;\n");
  	if (saw_getline) {
! 	    str_cat(str,"\nsub Getline {\n    $_ = <>;\n");
! 	    tab(str,++level);
! 	    if (do_chop) {
! 		str_cat(str,"chop;\t# strip record separator\n");
! 		tab(str,level);
  	    }
- 	    if (do_split)
- 		emit_split(str,level);
- 	    fixtab(str,--level);
- 	    str_cat(str,"}\n");
  	}
  	if (do_fancy_opens) {
  	    str_cat(str,"\n\
  sub Pick {\n\
!     ($name) = @_;\n\
      $fh = $opened{$name};\n\
      if (!$fh) {\n\
! 	$nextfh == 0 && open(fh_0,$name);\n\
! 	$nextfh == 1 && open(fh_1,$name);\n\
! 	$nextfh == 2 && open(fh_2,$name);\n\
! 	$nextfh == 3 && open(fh_3,$name);\n\
! 	$nextfh == 4 && open(fh_4,$name);\n\
! 	$nextfh == 5 && open(fh_5,$name);\n\
! 	$nextfh == 6 && open(fh_6,$name);\n\
! 	$nextfh == 7 && open(fh_7,$name);\n\
! 	$nextfh == 8 && open(fh_8,$name);\n\
! 	$nextfh == 9 && open(fh_9,$name);\n\
! 	$fh = $opened{$name} = 'fh_' . $nextfh++;\n\
      }\n\
-     select($fh);\n\
  }\n\
  ");
  	}
--- 150,212 ----
  	}
  	if (exitval)
  	    str_cat(str,"exit ExitValue;\n");
+ 	if (subs->str_ptr) {
+ 	    str_cat(str,"\n");
+ 	    str_scat(str,subs);
+ 	}
  	if (saw_getline) {
! 	    for (len = 0; len < 4; len++) {
! 		if (saw_getline & (1 << len)) {
! 		    sprintf(tokenbuf,"\nsub Getline%d {\n",len);
! 		    str_cat(str, tokenbuf);
! 		    if (len & 2) {
! 			if (do_fancy_opens)
! 			    str_cat(str,"    do Pick('',@_);\n");
! 			else
! 			    str_cat(str,"    ($fh) = @_;\n");
! 		    }
! 		    else {
! 			if (saw_FNR)
! 			    str_cat(str,"    $FNRbase = $. if eof;\n");
! 		    }
! 		    if (len & 1)
! 			str_cat(str,"    local($_)\n");
! 		    if (len & 2)
! 			str_cat(str,
! 			  "    if ($getline_ok = (($_ = <$fh>) ne ''))");
! 		    else
! 			str_cat(str,
! 			  "    if ($getline_ok = (($_ = <>) ne ''))");
! 		    str_cat(str, " {\n");
! 		    level += 2;
! 		    tab(str,level);
! 		    i = 0;
! 		    if (do_chop) {
! 			i++;
! 			str_cat(str,"chop;\t# strip record separator\n");
! 			tab(str,level);
! 		    }
! 		    if (do_split && !(len & 1)) {
! 			i++;
! 			emit_split(str,level);
! 		    }
! 		    if (!i)
! 			str_cat(str,";\n");
! 		    fixtab(str,--level);
! 		    str_cat(str,"}\n    $_;\n}\n");
! 		    --level;
! 		}
  	    }
  	}
  	if (do_fancy_opens) {
  	    str_cat(str,"\n\
  sub Pick {\n\
!     local($mode,$name,$pipe) = @_;\n\
      $fh = $opened{$name};\n\
      if (!$fh) {\n\
! 	$fh = $opened{$name} = 'fh_' . ($nextfh++ + 0);\n\
! 	open($fh,$mode.$name.$pipe);\n\
      }\n\
  }\n\
  ");
  	}
***************
*** 345,352 ****
--- 395,407 ----
  	    str_free(tmpstr);
  	}
  	str_cat(str," ");
+ 	type = ops[ops[node+3].ival].ival & 255;
+ 	if (type != OREGEX && type != OVAR)
+ 	    str_cat(str,"(");
  	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg));
  	str_free(fstr);
+ 	if (type != OREGEX && type != OVAR)
+ 	    str_cat(str,")");
  	numeric = 1;
  	break;
      case OMPAREN:
***************
*** 383,389 ****
  	str_free(fstr);
  	numeric = 1;
  	break;
!     case OSUB:
  	str = walk(1,level,ops[node+1].ival,&numarg);
  	str_cat(str," - ");
  	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
--- 438,444 ----
  	str_free(fstr);
  	numeric = 1;
  	break;
!     case OSUBTRACT:
  	str = walk(1,level,ops[node+1].ival,&numarg);
  	str_cat(str," - ");
  	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
***************
*** 404,409 ****
--- 459,471 ----
  	str_free(fstr);
  	numeric = 1;
  	break;
+     case OPOW:
+ 	str = walk(1,level,ops[node+1].ival,&numarg);
+ 	str_cat(str," ** ");
+ 	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
+ 	str_free(fstr);
+ 	numeric = 1;
+ 	break;
      case OMOD:
  	str = walk(1,level,ops[node+1].ival,&numarg);
  	str_cat(str," % ");
***************
*** 455,462 ****
  	break;
      case OGETLINE:
  	str = str_new(0);
! 	str_set(str,"do Getline()");
! 	saw_getline = TRUE;
  	break;
      case OSPRINTF:
  	str = str_new(0);
--- 517,596 ----
  	break;
      case OGETLINE:
  	str = str_new(0);
! 	if (useval)
! 	    str_cat(str,"(");
! 	if (len > 0) {
! 	    str_cat(str,"$");
! 	    str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
! 	    if (!*fstr->str_ptr) {
! 		str_cat(str,"_");
! 		len = 2;		/* a legal fiction */
! 	    }
! 	    str_free(fstr);
! 	}
! 	else
! 	    str_cat(str,"$_");
! 	if (len > 1) {
! 	    tmpstr=walk(1,level,ops[node+3].ival,&numarg);
! 	    fstr=walk(1,level,ops[node+2].ival,&numarg);
! 	    if (!do_fancy_opens) {
! 		t = tmpstr->str_ptr;
! 		if (*t == '"' || *t == '\'')
! 		    t = cpytill(tokenbuf,t+1,*t);
! 		else
! 		    fatal("Internal error: OGETLINE %s", t);
! 		d = savestr(t);
! 		s = savestr(tokenbuf);
! 		for (t = tokenbuf; *t; t++) {
! 		    *t &= 127;
! 		    if (!isalpha(*t) && !isdigit(*t))
! 			*t = '_';
! 		}
! 		if (!index(tokenbuf,'_'))
! 		    strcpy(t,"_fh");
! 		tmp3str = hfetch(symtab,tokenbuf);
! 		if (!tmp3str) {
! 		    do_opens = TRUE;
! 		    str_cat(opens,"open(");
! 		    str_cat(opens,tokenbuf);
! 		    str_cat(opens,", ");
! 		    d[1] = '\0';
! 		    str_cat(opens,d);
! 		    str_cat(opens,tmpstr->str_ptr+1);
! 		    opens->str_cur--;
! 		    if (*fstr->str_ptr == '|')
! 			str_cat(opens,"|");
! 		    str_cat(opens,d);
! 		    if (*fstr->str_ptr == '|')
! 			str_cat(opens,") || die 'Cannot pipe from \"");
! 		    else
! 			str_cat(opens,") || die 'Cannot open file \"");
! 		    if (*d == '"')
! 			str_cat(opens,"'.\"");
! 		    str_cat(opens,s);
! 		    if (*d == '"')
! 			str_cat(opens,"\".'");
! 		    str_cat(opens,"\".';\n");
! 		    hstore(symtab,tokenbuf,str_make("x"));
! 		}
! 		safefree(s);
! 		safefree(d);
! 		str_set(tmpstr,"'");
! 		str_cat(tmpstr,tokenbuf);
! 		str_cat(tmpstr,"'");
! 	    }
! 	    if (*fstr->str_ptr == '|')
! 		str_cat(tmpstr,", '|'");
! 	    str_free(fstr);
! 	}
! 	else
! 	    tmpstr = str_make("");
! 	sprintf(tokenbuf," = do Getline%d(%s)",len,tmpstr->str_ptr);
! 	str_cat(str,tokenbuf); 
! 	str_free(tmpstr);
! 	if (useval)
! 	    str_cat(str,",getline_ok)");
! 	saw_getline |= 1 << len;
  	break;
      case OSPRINTF:
  	str = str_new(0);
***************
*** 538,543 ****
--- 672,862 ----
  	str_cat(str,")");
  	numeric = 1;
  	break;
+     case OMATCH:
+ 	str = str_new(0);
+ 	str_set(str,"(");
+ 	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
+ 	str_free(fstr);
+ 	str_cat(str," =~ ");
+ 	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
+ 	str_free(fstr);
+ 	str_cat(str," && ($RLENGTH = length($&), $RSTART = length($`)+1))");
+ 	numeric = 1;
+ 	break;
+     case OUSERDEF:
+ 	str = str_new(0);
+ 	subretnum = FALSE;
+ 	fstr=walk(1,level-1,ops[node+2].ival,&numarg);
+ 	curargs = str_new(0);
+ 	str_sset(curargs,fstr);
+ 	str_cat(curargs,",");
+ 	tmp2str=walk(1,level,ops[node+5].ival,&numarg);
+ 	str_free(curargs);
+ 	curargs = Nullstr;
+ 	level--;
+ 	subretnum |= numarg;
+ 	s = Nullch;
+ 	t = tmp2str->str_ptr;
+ 	while (t = instr(t,"return "))
+ 	    s = t++;
+ 	if (s) {
+ 	    i = 0;
+ 	    for (t = s+7; *t; t++) {
+ 		if (*t == ';' || *t == '}')
+ 		    i++;
+ 	    }
+ 	    if (i == 1) {
+ 		strcpy(s,s+7);
+ 		tmp2str->str_cur -= 7;
+ 	    }
+ 	}
+ 	str_set(str,"sub ");
+ 	str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg));
+ 	str_cat(str," {\n");
+ 	tab(str,++level);
+ 	str_cat(str,"local(");
+ 	str_scat(str,fstr);
+ 	str_free(fstr);
+ 	str_cat(str,") = @_;");
+ 	str_scat(str,fstr=walk(1,level,ops[node+3].ival,&numarg));
+ 	str_free(fstr);
+ 	fixtab(str,level);
+ 	str_scat(str,fstr=walk(1,level,ops[node+4].ival,&numarg));
+ 	str_free(fstr);
+ 	fixtab(str,level);
+ 	str_scat(str,tmp2str);
+ 	str_free(tmp2str);
+ 	fixtab(str,--level);
+ 	str_cat(str,"}\n");
+ 	tab(str,level);
+ 	str_scat(subs,str);
+ 	str_set(str,"");
+ 	str_cat(tmpstr,"(");
+ 	tmp2str = str_new(0);
+ 	if (subretnum)
+ 	    str_set(tmp2str,"1");
+ 	hstore(symtab,tmpstr->str_ptr,tmp2str);
+ 	str_free(tmpstr);
+ 	level++;
+ 	break;
+     case ORETURN:
+ 	str = str_new(0);
+ 	if (len > 0) {
+ 	    str_cat(str,"return ");
+ 	    str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
+ 	    str_free(fstr);
+ 	    if (numarg)
+ 		subretnum = TRUE;
+ 	}
+ 	else
+ 	    str_cat(str,"return");
+ 	break;
+     case OUSERFUN:
+ 	str = str_new(0);
+ 	str_set(str,"do ");
+ 	str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
+ 	str_free(fstr);
+ 	str_cat(str,"(");
+ 	tmpstr = hfetch(symtab,str->str_ptr+3);
+ 	if (tmpstr)
+ 	    numeric |= atoi(tmpstr->str_ptr);
+ 	str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
+ 	str_free(fstr);
+ 	str_cat(str,")");
+ 	break;
+     case OGSUB:
+     case OSUB:
+ 	if (type == OGSUB)
+ 	    s = "g";
+ 	else
+ 	    s = "";
+ 	str = str_new(0);
+ 	tmpstr = str_new(0);
+ 	i = 0;
+ 	if (len == 3) {
+ 	    tmpstr = walk(1,level,ops[node+3].ival,&numarg);
+ 	    if (strNE(tmpstr->str_ptr,"$_")) {
+ 		str_cat(tmpstr, " =~ s");
+ 		i++;
+ 	    }
+ 	    else
+ 		str_set(tmpstr, "s");
+ 	}
+ 	else
+ 	    str_set(tmpstr, "s");
+ 	type = ops[ops[node+2].ival].ival;
+ 	len = type >> 8;
+ 	type &= 255;
+ 	tmp3str = str_new(0);
+ 	if (type == OSTR) {
+ 	    tmp2str=walk(1,level,ops[ops[node+2].ival+1].ival,&numarg);
+ 	    for (t = tmp2str->str_ptr, d=tokenbuf; *t; d++,t++) {
+ 		if (*t == '&')
+ 		    *d++ = '$' + 128;
+ 		else if (*t == '$')
+ 		    *d++ = '\\' + 128;
+ 		*d = *t + 128;
+ 	    }
+ 	    *d = '\0';
+ 	    str_set(tmp2str,tokenbuf);
+ 	}
+ 	else {
+ 	    tmp2str=walk(1,level,ops[node+2].ival,&numarg);
+ 	    str_set(tmp3str,"($s_ = '\"'.(");
+ 	    str_scat(tmp3str,tmp2str);
+ 	    str_cat(tmp3str,").'\"') =~ s/&/\$&/g, ");
+ 	    str_set(tmp2str,"eval $s_");
+ 	    s = (*s == 'g' ? "ge" : "e");
+ 	    i++;
+ 	}
+ 	type = ops[ops[node+1].ival].ival;
+ 	len = type >> 8;
+ 	type &= 255;
+ 	fstr=walk(1,level,ops[node+1].ival,&numarg);
+ 	if (type == OREGEX) {
+ 	    if (useval && i)
+ 		str_cat(str,"(");
+ 	    str_scat(str,tmp3str);
+ 	    str_scat(str,tmpstr);
+ 	    str_scat(str,fstr);
+ 	    str_scat(str,tmp2str);
+ 	    str_cat(str,"/");
+ 	    str_cat(str,s);
+ 	}
+ 	else if ((type == OFLD && !split_to_array) || (type == OVAR && len == 1)) {
+ 	    if (useval && i)
+ 		str_cat(str,"(");
+ 	    str_scat(str,tmp3str);
+ 	    str_scat(str,tmpstr);
+ 	    str_cat(str,"/");
+ 	    str_scat(str,fstr);
+ 	    str_cat(str,"/");
+ 	    str_scat(str,tmp2str);
+ 	    str_cat(str,"/");
+ 	    str_cat(str,s);
+ 	}
+ 	else {
+ 	    i++;
+ 	    if (useval)
+ 		str_cat(str,"(");
+ 	    str_cat(str,"$s = ");
+ 	    str_scat(str,fstr);
+ 	    str_cat(str,", ");
+ 	    str_scat(str,tmp3str);
+ 	    str_scat(str,tmpstr);
+ 	    str_cat(str,"/$s/");
+ 	    str_scat(str,tmp2str);
+ 	    str_cat(str,"/");
+ 	    str_cat(str,s);
+ 	}
+ 	if (useval && i)
+ 	    str_cat(str,")");
+ 	str_free(fstr);
+ 	str_free(tmpstr);
+ 	str_free(tmp2str);
+ 	str_free(tmp3str);
+ 	numeric = 1;
+ 	break;
      case ONUM:
  	str = walk(1,level,ops[node+1].ival,&numarg);
  	numeric = 1;
***************
*** 567,582 ****
  	str_free(tmpstr);
  	str_cat(str,s);
  	break;
      case OVAR:
  	str = str_new(0);
  	str_set(str,"$");
  	str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg));
  	if (len == 1) {
  	    tmp2str = hfetch(symtab,tmpstr->str_ptr);
  	    if (tmp2str && atoi(tmp2str->str_ptr))
  		numeric = 2;
! 	    if (strEQ(str->str_ptr,"$NR")) {
  		numeric = 1;
  		str_set(str,"$.");
  	    }
  	    else if (strEQ(str->str_ptr,"$NF")) {
--- 886,911 ----
  	str_free(tmpstr);
  	str_cat(str,s);
  	break;
+     case ODELETE:
+ 	str = str_new(0);
+ 	str_set(str,"delete $");
+ 	goto addvar;
      case OVAR:
  	str = str_new(0);
  	str_set(str,"$");
+       addvar:
  	str_scat(str,tmpstr=walk(1,level,ops[node+1].ival,&numarg));
  	if (len == 1) {
  	    tmp2str = hfetch(symtab,tmpstr->str_ptr);
  	    if (tmp2str && atoi(tmp2str->str_ptr))
  		numeric = 2;
! 	    if (strEQ(str->str_ptr,"$FNR")) {
  		numeric = 1;
+ 		saw_FNR++;
+ 		str_set(str,"($.-$FNRbase)");
+ 	    }
+ 	    else if (strEQ(str->str_ptr,"$NR")) {
+ 		numeric = 1;
  		str_set(str,"$.");
  	    }
  	    else if (strEQ(str->str_ptr,"$NF")) {
***************
*** 585,592 ****
--- 914,928 ----
  	    }
  	    else if (strEQ(str->str_ptr,"$0"))
  		str_set(str,"$_");
+ 	    else if (strEQ(str->str_ptr,"$ARGC"))
+ 		str_set(str,"($#ARGV+1)");
  	}
  	else {
+ 	    if (curargs) {
+ 		sprintf(tokenbuf,"$%s,",tmpstr->str_ptr);
+ 		if (instr(curargs->str_ptr,tokenbuf))
+ 		    str_cat(str,"\377");	/* can't translate yet */
+ 	    }
  	    str_cat(tmpstr,"[]");
  	    tmp2str = hfetch(symtab,tmpstr->str_ptr);
  	    if (tmp2str && atoi(tmp2str->str_ptr))
***************
*** 595,606 ****
  		str_cat(str,"{");
  	    str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
  	    str_free(fstr);
! 	    if (tmp2str && atoi(tmp2str->str_ptr))
! 		strcpy(tokenbuf,"]");
! 	    else
! 		strcpy(tokenbuf,"}");
! 	    *tokenbuf += 128;
! 	    str_cat(str,tokenbuf);
  	}
  	str_free(tmpstr);
  	break;
--- 931,948 ----
  		str_cat(str,"{");
  	    str_scat(str,fstr=walk(1,level,ops[node+2].ival,&numarg));
  	    str_free(fstr);
! 	    if (strEQ(str->str_ptr,"$ARGV[0")) {
! 		str_set(str,"$ARGV0");
! 		saw_argv0++;
! 	    }
! 	    else {
! 		if (tmp2str && atoi(tmp2str->str_ptr))
! 		    strcpy(tokenbuf,"]");
! 		else
! 		    strcpy(tokenbuf,"}");
! 		*tokenbuf += 128;
! 		str_cat(str,tokenbuf);
! 	    }
  	}
  	str_free(tmpstr);
  	break;
***************
*** 694,699 ****
--- 1036,1070 ----
  	    }
  	}
  	break;
+     case OCLOSE:
+ 	str = str_make("close(");
+ 	tmpstr = walk(1,level,ops[node+1].ival,&numarg);
+ 	if (!do_fancy_opens) {
+ 	    t = tmpstr->str_ptr;
+ 	    if (*t == '"' || *t == '\'')
+ 		t = cpytill(tokenbuf,t+1,*t);
+ 	    else
+ 		fatal("Internal error: OCLOSE %s",t);
+ 	    s = savestr(tokenbuf);
+ 	    for (t = tokenbuf; *t; t++) {
+ 		*t &= 127;
+ 		if (!isalpha(*t) && !isdigit(*t))
+ 		    *t = '_';
+ 	    }
+ 	    if (!index(tokenbuf,'_'))
+ 		strcpy(t,"_fh");
+ 	    str_free(tmpstr);
+ 	    safefree(s);
+ 	    str_set(str,"close ");
+ 	    str_cat(str,tokenbuf);
+ 	}
+ 	else {
+ 	    sprintf(tokenbuf,"$fh = delete $opened{%s} && close $fh",
+ 	       tmpstr->str_ptr);
+ 	    str_free(tmpstr);
+ 	    str_set(str,tokenbuf);
+ 	}
+ 	break;
      case OPRINTF:
      case OPRINT:
  	lparen = "";	/* set to parens if necessary */
***************
*** 717,739 ****
  		}
  		if (!index(tokenbuf,'_'))
  		    strcpy(t,"_fh");
! 		str_cat(opens,"open(");
! 		str_cat(opens,tokenbuf);
! 		str_cat(opens,", ");
! 		d[1] = '\0';
! 		str_cat(opens,d);
! 		str_scat(opens,tmp2str);
! 		str_cat(opens,tmpstr->str_ptr+1);
! 		if (*tmp2str->str_ptr == '|')
! 		    str_cat(opens,") || die 'Cannot pipe to \"");
! 		else
! 		    str_cat(opens,") || die 'Cannot create file \"");
! 		if (*d == '"')
! 		    str_cat(opens,"'.\"");
! 		str_cat(opens,s);
! 		if (*d == '"')
! 		    str_cat(opens,"\".'");
! 		str_cat(opens,"\".';\n");
  		str_free(tmpstr);
  		str_free(tmp2str);
  		safefree(s);
--- 1088,1114 ----
  		}
  		if (!index(tokenbuf,'_'))
  		    strcpy(t,"_fh");
! 		tmp3str = hfetch(symtab,tokenbuf);
! 		if (!tmp3str) {
! 		    str_cat(opens,"open(");
! 		    str_cat(opens,tokenbuf);
! 		    str_cat(opens,", ");
! 		    d[1] = '\0';
! 		    str_cat(opens,d);
! 		    str_scat(opens,tmp2str);
! 		    str_cat(opens,tmpstr->str_ptr+1);
! 		    if (*tmp2str->str_ptr == '|')
! 			str_cat(opens,") || die 'Cannot pipe to \"");
! 		    else
! 			str_cat(opens,") || die 'Cannot create file \"");
! 		    if (*d == '"')
! 			str_cat(opens,"'.\"");
! 		    str_cat(opens,s);
! 		    if (*d == '"')
! 			str_cat(opens,"\".'");
! 		    str_cat(opens,"\".';\n");
! 		    hstore(symtab,tokenbuf,str_make("x"));
! 		}
  		str_free(tmpstr);
  		str_free(tmp2str);
  		safefree(s);
***************
*** 740,750 ****
  		safefree(d);
  	    }
  	    else {
! 		sprintf(tokenbuf,"do Pick('%s' . (%s)) &&\n",
  		   tmp2str->str_ptr, tmpstr->str_ptr);
  		str_cat(str,tokenbuf);
  		tab(str,level+1);
! 		*tokenbuf = '\0';
  		str_free(tmpstr);
  		str_free(tmp2str);
  		lparen = "(";
--- 1115,1125 ----
  		safefree(d);
  	    }
  	    else {
! 		sprintf(tokenbuf,"do Pick('%s', %s) &&\n",
  		   tmp2str->str_ptr, tmpstr->str_ptr);
  		str_cat(str,tokenbuf);
  		tab(str,level+1);
! 		strcpy(tokenbuf,"$fh");
  		str_free(tmpstr);
  		str_free(tmp2str);
  		lparen = "(";
***************
*** 795,800 ****
--- 1170,1193 ----
  	str_cat(str,rparen);	/* may be null */
  	str_free(tmpstr);
  	break;
+     case ORAND:
+ 	str = str_make("rand(1)");
+ 	break;
+     case OSRAND:
+ 	str = str_make("srand(");
+ 	goto maybe0;
+     case OATAN2:
+ 	str = str_make("atan2(");
+ 	goto maybe0;
+     case OSIN:
+ 	str = str_make("sin(");
+ 	goto maybe0;
+     case OCOS:
+ 	str = str_make("cos(");
+ 	goto maybe0;
+     case OSYSTEM:
+ 	str = str_make("system(");
+ 	goto maybe0;
      case OLENGTH:
  	str = str_make("length(");
  	goto maybe0;
***************
*** 960,991 ****
  	str_free(fstr);
  	break;
      case OFORIN:
! 	tmpstr=walk(0,level,ops[node+2].ival,&numarg);
  	str = str_new(0);
! 	str_sset(str,tmpstr);
  	str_cat(str,"[]");
  	tmp2str = hfetch(symtab,str->str_ptr);
  	if (tmp2str && atoi(tmp2str->str_ptr)) {
- 	    fstr=walk(1,level,ops[node+1].ival,&numarg);
  	    sprintf(tokenbuf,
! 	      "foreach $%s (@%s) ",
! 	      fstr->str_ptr,
! 	      tmpstr->str_ptr);
! 	    str_set(str,tokenbuf);
! 	    str_free(fstr);
! 	    str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
! 	    str_free(fstr);
  	}
  	else {
! 	    str_set(str,"while (($");
! 	    str_scat(str,fstr=walk(1,level,ops[node+1].ival,&numarg));
! 	    str_free(fstr);
! 	    str_cat(str,",$junkval) = each(");
! 	    str_scat(str,tmpstr);
! 	    str_cat(str,")) ");
! 	    str_scat(str,fstr=walk(0,level,ops[node+3].ival,&numarg));
! 	    str_free(fstr);
  	}
  	str_free(tmpstr);
  	break;
      case OBLOCK:
--- 1353,1389 ----
  	str_free(fstr);
  	break;
      case OFORIN:
! 	tmpstr = walk(0,level,ops[node+1].ival,&numarg);
! 	s = index(tmpstr->str_ptr,'{');
! 	if (!s)
! 	    s = index(tmpstr->str_ptr,'[');
! 	if (!s)
! 	    fatal("Illegal for loop: %s",tmpstr->str_ptr);
! 	*s++ = '\0';
! 	t = index(s,'}' + 128);
! 	if (!t)
! 	    t = index(s,']' + 128);
! 	if (t)
! 	    *t = '\0';
  	str = str_new(0);
! 	str_set(str,tmpstr->str_ptr+1);
  	str_cat(str,"[]");
  	tmp2str = hfetch(symtab,str->str_ptr);
  	if (tmp2str && atoi(tmp2str->str_ptr)) {
  	    sprintf(tokenbuf,
! 	      "foreach %s (@%s) ",
! 	      s,
! 	      tmpstr->str_ptr+1);
  	}
  	else {
! 	    sprintf(tokenbuf,
! 	      "foreach %s (keys(%s)) ",
! 	      s,
! 	      tmpstr->str_ptr+1);
  	}
+ 	str_set(str,tokenbuf);
+ 	str_scat(str,fstr=walk(0,level,ops[node+2].ival,&numarg));
+ 	str_free(fstr);
  	str_free(tmpstr);
  	break;
      case OBLOCK:
***************
*** 1132,1137 ****
--- 1530,1537 ----
      char *d, *s;
      int numarg;
      int numeric = FALSE;
+     STR *tmpstr;
+     STR *tmp2str;
  
      if (!node) {
  	*numericptr = 0;
***************
*** 1259,1265 ****
  	prewalk(1,level,ops[node+2].ival,&numarg);
  	numeric = 1;
  	break;
!     case OSUB:
  	prewalk(1,level,ops[node+1].ival,&numarg);
  	prewalk(1,level,ops[node+2].ival,&numarg);
  	numeric = 1;
--- 1659,1665 ----
  	prewalk(1,level,ops[node+2].ival,&numarg);
  	numeric = 1;
  	break;
!     case OSUBTRACT:
  	prewalk(1,level,ops[node+1].ival,&numarg);
  	prewalk(1,level,ops[node+2].ival,&numarg);
  	numeric = 1;
***************
*** 1274,1279 ****
--- 1674,1684 ----
  	prewalk(1,level,ops[node+2].ival,&numarg);
  	numeric = 1;
  	break;
+     case OPOW:
+ 	prewalk(1,level,ops[node+1].ival,&numarg);
+ 	prewalk(1,level,ops[node+2].ival,&numarg);
+ 	numeric = 1;
+ 	break;
      case OMOD:
  	prewalk(1,level,ops[node+1].ival,&numarg);
  	prewalk(1,level,ops[node+2].ival,&numarg);
***************
*** 1333,1338 ****
--- 1738,1791 ----
  	prewalk(0,level,ops[node+2].ival,&numarg);
  	numeric = 1;
  	break;
+     case OMATCH:
+ 	prewalk(0,level,ops[node+1].ival,&numarg);
+ 	prewalk(0,level,ops[node+2].ival,&numarg);
+ 	numeric = 1;
+ 	break;
+     case OUSERDEF:
+ 	subretnum = FALSE;
+ 	--level;
+ 	tmpstr = walk(0,level,ops[node+1].ival,&numarg);
+ 	++level;
+ 	prewalk(0,level,ops[node+2].ival,&numarg);
+ 	prewalk(0,level,ops[node+4].ival,&numarg);
+ 	prewalk(0,level,ops[node+5].ival,&numarg);
+ 	--level;
+ 	str_cat(tmpstr,"(");
+ 	tmp2str = str_new(0);
+ 	if (subretnum || numarg)
+ 	    str_set(tmp2str,"1");
+ 	hstore(symtab,tmpstr->str_ptr,tmp2str);
+ 	str_free(tmpstr);
+ 	level++;
+ 	break;
+     case ORETURN:
+ 	if (len > 0) {
+ 	    prewalk(0,level,ops[node+1].ival,&numarg);
+ 	    if (numarg)
+ 		subretnum = TRUE;
+ 	}
+ 	break;
+     case OUSERFUN:
+ 	tmp2str = str_new(0);
+ 	str_scat(tmp2str,tmpstr=walk(1,level,ops[node+1].ival,&numarg));
+ 	str_free(tmpstr);
+ 	str_cat(tmp2str,"(");
+ 	tmpstr = hfetch(symtab,tmp2str->str_ptr);
+ 	if (tmpstr)
+ 	    numeric |= atoi(tmpstr->str_ptr);
+ 	prewalk(0,level,ops[node+2].ival,&numarg);
+ 	str_free(tmp2str);
+ 	break;
+     case OGSUB:
+     case OSUB:
+ 	if (len >= 3)
+ 	    prewalk(0,level,ops[node+3].ival,&numarg);
+ 	prewalk(0,level,ops[ops[node+2].ival+1].ival,&numarg);
+ 	prewalk(0,level,ops[node+1].ival,&numarg);
+ 	numeric = 1;
+ 	break;
      case ONUM:
  	prewalk(0,level,ops[node+1].ival,&numarg);
  	numeric = 1;
***************
*** 1340,1345 ****
--- 1793,1799 ----
      case OSTR:
  	prewalk(0,level,ops[node+1].ival,&numarg);
  	break;
+     case ODELETE:
      case OVAR:
  	prewalk(0,level,ops[node+1].ival,&numarg);
  	if (len == 1) {
***************
*** 1385,1390 ****
--- 1839,1847 ----
  	    }
  	}
  	break;
+     case OCLOSE:
+ 	prewalk(0,level,ops[node+1].ival,&numarg);
+ 	break;
      case OPRINTF:
      case OPRINT:
  	if (len == 3) {		/* output redirection */
***************
*** 1393,1398 ****
--- 1850,1867 ----
  	}
  	prewalk(0+(type==OPRINT),level,ops[node+1].ival,&numarg);
  	break;
+     case ORAND:
+ 	break;
+     case OSRAND:
+ 	goto maybe0;
+     case OATAN2:
+ 	goto maybe0;
+     case OSIN:
+ 	goto maybe0;
+     case OCOS:
+ 	goto maybe0;
+     case OSYSTEM:
+ 	goto maybe0;
      case OLENGTH:
  	goto maybe0;
      case OLOG:
***************
*** 1405,1411 ****
        maybe0:
  	numeric = 1;
  	if (len > 0)
! 	    prewalk(type != OLENGTH,level,ops[node+1].ival,&numarg);
  	break;
      case OBREAK:
  	break;
--- 1874,1881 ----
        maybe0:
  	numeric = 1;
  	if (len > 0)
! 	    prewalk(type != OLENGTH && type != OSYSTEM,
! 	      level,ops[node+1].ival,&numarg);
  	break;
      case OBREAK:
  	break;
***************
*** 1440,1446 ****
      case OFORIN:
  	prewalk(0,level,ops[node+2].ival,&numarg);
  	prewalk(0,level,ops[node+1].ival,&numarg);
- 	prewalk(0,level,ops[node+3].ival,&numarg);
  	break;
      case OBLOCK:
  	if (len == 2) {
--- 1910,1915 ----