/* This file is included by eval.c.  It's separate from eval.c to keep
 * kit sizes from getting too big.
 */

/* $Header: evalargs.xc,v 3.0.1.9 91/01/11 18:00:18 lwall Locked $
 *
 * $Log:	evalargs.xc,v $
 * Revision 3.0.1.9  91/01/11  18:00:18  lwall
 * patch42: <> input to individual array elements was suboptimal
 * 
 * Revision 3.0.1.8  90/11/10  01:35:49  lwall
 * patch38: array slurps are now faster and take less memory
 * 
 * Revision 3.0.1.7  90/10/15  16:48:11  lwall
 * patch29: non-existent array values no longer cause core dumps
 * patch29: added caller
 * 
 * Revision 3.0.1.6  90/08/09  03:37:15  lwall
 * patch19: passing *name to subroutine now forces filehandle and array creation
 * patch19: `command` in array context now returns array of lines
 * patch19: <handle> input is a little more efficient
 * 
 * Revision 3.0.1.5  90/03/27  15:54:42  lwall
 * patch16: MSDOS support
 * 
 * Revision 3.0.1.4  90/02/28  17:38:37  lwall
 * patch9: $#foo -= 2 didn't work
 * 
 * Revision 3.0.1.3  89/11/17  15:25:07  lwall
 * patch5: constant numeric subscripts disappeared in ?:
 * 
 * Revision 3.0.1.2  89/11/11  04:33:05  lwall
 * patch2: Configure now locates csh
 * 
 * Revision 3.0.1.1  89/10/26  23:12:55  lwall
 * patch1: glob didn't free a temporary string
 * 
 * Revision 3.0  89/10/18  15:17:16  lwall
 * 3.0 baseline
 * 
 */

    for (anum = 1; anum <= maxarg; anum++) {
	argflags = arg[anum].arg_flags;
	argtype = arg[anum].arg_type;
	argptr = arg[anum].arg_ptr;
      re_eval:
	switch (argtype) {
	default:
	    st[++sp] = &str_undef;
#ifdef DEBUGGING
	    tmps = "NULL";
#endif
	    break;
	case A_EXPR:
#ifdef DEBUGGING
	    if (debug & 8) {
		tmps = "EXPR";
		deb("%d.EXPR =>\n",anum);
	    }
#endif
	    sp = eval(argptr.arg_arg,
		(argflags & AF_ARYOK) ? G_ARRAY : G_SCALAR, sp);
	    if (sp + (maxarg - anum) > stack->ary_max)
		astore(stack, sp + (maxarg - anum), Nullstr);
	    st = stack->ary_array;	/* possibly reallocated */
	    break;
	case A_CMD:
#ifdef DEBUGGING
	    if (debug & 8) {
		tmps = "CMD";
		deb("%d.CMD (%lx) =>\n",anum,argptr.arg_cmd);
	    }
#endif
	    sp = cmd_exec(argptr.arg_cmd, gimme, sp);
	    if (sp + (maxarg - anum) > stack->ary_max)
		astore(stack, sp + (maxarg - anum), Nullstr);
	    st = stack->ary_array;	/* possibly reallocated */
	    break;
	case A_LARYSTAB:
	    ++sp;
	    switch (optype) {
		case O_ITEM2: argtype = 2; break;
		case O_ITEM3: argtype = 3; break;
		default:      argtype = anum; break;
	    }
	    str = afetch(stab_array(argptr.arg_stab),
		arg[argtype].arg_len - arybase, TRUE);
#ifdef DEBUGGING
	    if (debug & 8) {
		(void)sprintf(buf,"LARYSTAB $%s[%d]",stab_name(argptr.arg_stab),
		    arg[argtype].arg_len);
		tmps = buf;
	    }
#endif
	    goto do_crement;
	case A_ARYSTAB:
	    switch (optype) {
		case O_ITEM2: argtype = 2; break;
		case O_ITEM3: argtype = 3; break;
		default:      argtype = anum; break;
	    }
	    st[++sp] = afetch(stab_array(argptr.arg_stab),
		arg[argtype].arg_len - arybase, FALSE);
#ifdef DEBUGGING
	    if (debug & 8) {
		(void)sprintf(buf,"ARYSTAB $%s[%d]",stab_name(argptr.arg_stab),
		    arg[argtype].arg_len);
		tmps = buf;
	    }
#endif
	    break;
	case A_STAR:
	    stab = argptr.arg_stab;
	    st[++sp] = (STR*)stab;
	    if (!stab_xarray(stab))
		aadd(stab);
	    if (!stab_xhash(stab))
		hadd(stab);
	    if (!stab_io(stab))
		stab_io(stab) = stio_new();
#ifdef DEBUGGING
	    if (debug & 8) {
		(void)sprintf(buf,"STAR *%s",stab_name(argptr.arg_stab));
		tmps = buf;
	    }
#endif
	    break;
	case A_LSTAR:
	    str = st[++sp] = (STR*)argptr.arg_stab;
#ifdef DEBUGGING
	    if (debug & 8) {
		(void)sprintf(buf,"LSTAR *%s",stab_name(argptr.arg_stab));
		tmps = buf;
	    }
#endif
	    break;
	case A_STAB:
	    st[++sp] = STAB_STR(argptr.arg_stab);
#ifdef DEBUGGING
	    if (debug & 8) {
		(void)sprintf(buf,"STAB $%s",stab_name(argptr.arg_stab));
		tmps = buf;
	    }
#endif
	    break;
	case A_LEXPR:
#ifdef DEBUGGING
	    if (debug & 8) {
		tmps = "LEXPR";
		deb("%d.LEXPR =>\n",anum);
	    }
#endif
	    if (argflags & AF_ARYOK) {
		sp = eval(argptr.arg_arg, G_ARRAY, sp);
		if (sp + (maxarg - anum) > stack->ary_max)
		    astore(stack, sp + (maxarg - anum), Nullstr);
		st = stack->ary_array;	/* possibly reallocated */
	    }
	    else {
		sp = eval(argptr.arg_arg, G_SCALAR, sp);
		st = stack->ary_array;	/* possibly reallocated */
		str = st[sp];
		goto do_crement;
	    }
	    break;
	case A_LVAL:
#ifdef DEBUGGING
	    if (debug & 8) {
		(void)sprintf(buf,"LVAL $%s",stab_name(argptr.arg_stab));
		tmps = buf;
	    }
#endif
	    ++sp;
	    str = STAB_STR(argptr.arg_stab);
	    if (!str)
		fatal("panic: A_LVAL");
	  do_crement:
	    assigning = TRUE;
	    if (argflags & AF_PRE) {
		if (argflags & AF_UP)
		    str_inc(str);
		else
		    str_dec(str);
		STABSET(str);
		st[sp] = str;
		str = arg->arg_ptr.arg_str;
	    }
	    else if (argflags & AF_POST) {
		st[sp] = str_static(str);
		if (argflags & AF_UP)
		    str_inc(str);
		else
		    str_dec(str);
		STABSET(str);
		str = arg->arg_ptr.arg_str;
	    }
	    else
		st[sp] = str;
	    break;
	case A_LARYLEN:
	    ++sp;
	    stab = argptr.arg_stab;
	    str = stab_array(argptr.arg_stab)->ary_magic;
	    if (optype != O_SASSIGN || argflags & (AF_PRE|AF_POST))
		str_numset(str,(double)(stab_array(stab)->ary_fill+arybase));
#ifdef DEBUGGING
	    tmps = "LARYLEN";
#endif
	    if (!str)
		fatal("panic: A_LEXPR");
	    goto do_crement;
	case A_ARYLEN:
	    stab = argptr.arg_stab;
	    st[++sp] = stab_array(stab)->ary_magic;
	    str_numset(st[sp],(double)(stab_array(stab)->ary_fill+arybase));
#ifdef DEBUGGING
	    tmps = "ARYLEN";
#endif
	    break;
	case A_SINGLE:
	    st[++sp] = argptr.arg_str;
#ifdef DEBUGGING
	    tmps = "SINGLE";
#endif
	    break;
	case A_DOUBLE:
	    (void) interp(str,argptr.arg_str,sp);
	    st = stack->ary_array;
	    st[++sp] = str;
#ifdef DEBUGGING
	    tmps = "DOUBLE";
#endif
	    break;
	case A_BACKTICK:
	    tmps = savestr(str_get(interp(str,argptr.arg_str,sp)));
	    st = stack->ary_array;
#ifdef TAINT
	    taintproper("Insecure dependency in ``");
#endif
	    str_set(str,"");
	    tmps2 = tmps;
	    tmps3 = index(tmps, '\n');
	    do {
		if (tmps3)
		    *tmps3 = 0;

		fp = mypopen(tmps2,"r");
		if (fp) {
		    if (gimme == G_SCALAR) {
			while (str_gets(str,fp,str->str_cur) != Nullch)
			    ;
		    }
		    else {
			for (;;) {
			    if (++sp > stack->ary_max) {
				astore(stack, sp, Nullstr);
				st = stack->ary_array;
			    }
			str = st[sp] = Str_new(56,80);
			if (str_gets(str,fp,0) == Nullch) {
				sp--;
				break;
			    }
			    if (str->str_len - str->str_cur > 20) {
				str->str_len = str->str_cur+1;
				Renew(str->str_ptr, str->str_len, char);
			    }
			    str_2static(str);
			}
		    }
		    statusvalue = mypclose(fp);
		}
		else
		    statusvalue = -1;

		if (tmps3) {
		    *tmps3 = '\n';
		    tmps2 = tmps3 + 1;
		    tmps3 = index(tmps2, '\n');
		}

	    } while (tmps3);

	    Safefree(tmps);
	    if (gimme == G_SCALAR)
		st[++sp] = str;
#ifdef DEBUGGING
	    tmps = "BACK";
#endif
	    break;
	case A_WANTARRAY:
	    {
		if (curcsv->wantarray == G_ARRAY)
		    st[++sp] = &str_yes;
		else
		    st[++sp] = &str_no;
	    }
#ifdef DEBUGGING
	    tmps = "WANTARRAY";
#endif
	    break;
	case A_INDREAD:
	    last_in_stab = stabent(str_get(STAB_STR(argptr.arg_stab)),TRUE);
	    old_record_separator = record_separator;
	    goto do_read;
	case A_GLOB:
	    argflags |= AF_POST;	/* enable newline chopping */
	    last_in_stab = argptr.arg_stab;
	    old_record_separator = record_separator;
	    record_separator = 0;
	    goto do_read;
	case A_READ:
	    last_in_stab = argptr.arg_stab;
	    old_record_separator = record_separator;
	  do_read:
	    if (anum > 1)		/* assign to scalar */
		gimme = G_SCALAR;	/* force context to scalar */
	    if (gimme == G_ARRAY)
		str = Str_new(57,0);
	    ++sp;
	    fp = Nullfp;
	    if (stab_io(last_in_stab)) {
		fp = stab_io(last_in_stab)->ifp;
		if (!fp) {
		    if (stab_io(last_in_stab)->flags & IOF_ARGV) {
			if (stab_io(last_in_stab)->flags & IOF_START) {
			    stab_io(last_in_stab)->flags &= ~IOF_START;
			    stab_io(last_in_stab)->lines = 0;
			    if (alen(stab_array(last_in_stab)) < 0) {
				tmpstr = str_make("-",1); /* assume stdin */
				(void)apush(stab_array(last_in_stab), tmpstr);
			    }
			}
			fp = nextargv(last_in_stab);
			if (!fp) { /* Note: fp != stab_io(last_in_stab)->ifp */
			    (void)do_close(last_in_stab,FALSE); /* now it does*/
			    stab_io(last_in_stab)->flags |= IOF_START;
			}
		    }
		    else if (argtype == A_GLOB) {
			(void) interp(str,stab_val(last_in_stab),sp);
			st = stack->ary_array;
			tmpstr = Str_new(55,0);

			str_set(tmpstr, "glob ");
			str_scat(tmpstr,str);
			str_cat(tmpstr," |");

			(void)do_open(last_in_stab,tmpstr->str_ptr,
			  tmpstr->str_cur);
			fp = stab_io(last_in_stab)->ifp;
			str_free(tmpstr);
		    }
		}
	    }
	    if (!fp && dowarn)
		warn("Read on closed filehandle <%s>",stab_name(last_in_stab));
	    when = str->str_len;	/* remember if already alloced */
	    if (!when)
		Str_Grow(str,80);	/* try short-buffering it */
	  keepgoing:
	    if (!fp)
		st[sp] = &str_undef;
	    else if (!str_gets(str,fp, optype == O_RCAT ? str->str_cur : 0)) {
		clearerr(fp);
		if (stab_io(last_in_stab)->flags & IOF_ARGV) {
		    fp = nextargv(last_in_stab);
		    if (fp)
			goto keepgoing;
		    (void)do_close(last_in_stab,FALSE);
		    stab_io(last_in_stab)->flags |= IOF_START;
		}
		else if (argflags & AF_POST) {
		    (void)do_close(last_in_stab,FALSE);
		}
		st[sp] = &str_undef;
		record_separator = old_record_separator;
		if (gimme == G_ARRAY) {
		    --sp;
		    str_2static(str);
		    goto array_return;
		}
		break;
	    }
	    else {
		stab_io(last_in_stab)->lines++;
		st[sp] = str;
#ifdef TAINT
		str->str_tainted = 1; /* Anything from the outside world...*/
#endif
		if (argflags & AF_POST) {
		    if (str->str_cur > 0)
			str->str_cur--;
		    if (str->str_ptr[str->str_cur] == record_separator)
			str->str_ptr[str->str_cur] = '\0';
		    else
			str->str_cur++;
		    for (tmps = str->str_ptr; *tmps; tmps++)
			if (!isalpha(*tmps) && !isdigit(*tmps) &&
			    index("$&*(){}[]'\";\\|?<>~`",*tmps))
				break;
		    if (*tmps && stat(str->str_ptr,&statbuf) < 0)
			goto keepgoing;		/* unmatched wildcard? */
		}
		if (gimme == G_ARRAY) {
		    if (str->str_len - str->str_cur > 20) {
			str->str_len = str->str_cur+1;
			Renew(str->str_ptr, str->str_len, char);
		    }
		    str_2static(str);
		    if (++sp > stack->ary_max) {
			astore(stack, sp, Nullstr);
			st = stack->ary_array;
		    }
		    str = Str_new(58,80);
		    goto keepgoing;
		}
		else if (!when && str->str_len - str->str_cur > 80) {
		    /* try to reclaim a bit of scalar space on 1st alloc */
		    if (str->str_cur < 60)
			str->str_len = 80;
		    else
			str->str_len = str->str_cur+40;	/* allow some slop */
		    Renew(str->str_ptr, str->str_len, char);
		}
	    }
	    record_separator = old_record_separator;
#ifdef DEBUGGING
	    tmps = "READ";
#endif
	    break;
	}
#ifdef DEBUGGING
	if (debug & 8)
	    deb("%d.%s = '%s'\n",anum,tmps,str_peek(st[sp]));
#endif
	if (anum < 8)
	    arglast[anum] = sp;
    }
