/* $Header: cmd.c,v 3.0.1.9 90/10/15 15:32:39 lwall Locked $ * * Copyright (c) 1989, Larry Wall * * You may distribute under the terms of the GNU General Public License * as specified in the README file that comes with the perl 3.0 kit. * * $Log: cmd.c,v $ * Revision 3.0.1.9 90/10/15 15:32:39 lwall * patch29: non-existent array values no longer cause core dumps * patch29: scripts now run at almost full speed under the debugger * patch29: @ENV = () now works * patch29: added caller * * Revision 3.0.1.8 90/08/09 02:28:49 lwall * patch19: did preliminary work toward debugging packages and evals * patch19: conditionals now always supply a scalar context to expression * patch19: switch optimizer was confused by negative fractional values * * Revision 3.0.1.7 90/03/27 15:32:37 lwall * patch16: non-terminal blocks should never have arrays requested of them * * Revision 3.0.1.6 90/03/12 16:21:09 lwall * patch13: fixed some backwards VOLATILE declarations * patch13: while (s/x//) {} still caused some anomolies * patch13: greater-than test of numeric switch structures did less-than action * * Revision 3.0.1.5 90/02/28 16:38:31 lwall * patch9: volatilized some more variables for super-optimizing compilers * patch9: nested foreach loops didn't reset inner loop on next to outer loop * patch9: returned values were read from obsolete stack * patch9: added sanity check on longjmp() return value * patch9: substitutions that almost always succeed can corrupt label stack * patch9: subs which return by both mechanisms can clobber local return data * * Revision 3.0.1.4 89/12/21 19:17:41 lwall * patch7: arranged for certain registers to be restored after longjmp() * patch7: made nested or recursive foreach work right * * Revision 3.0.1.3 89/11/17 15:04:36 lwall * patch5: nested foreach on same array didn't work * * Revision 3.0.1.2 89/11/11 04:08:56 lwall * patch2: non-BSD machines required two ^D's for <> * patch2: grow_dlevel() not inside #ifdef DEBUGGING * * Revision 3.0.1.1 89/10/26 23:04:21 lwall * patch1: heuristically disabled optimization could cause core dump * * Revision 3.0 89/10/18 15:09:02 lwall * 3.0 baseline * */ #include "EXTERN.h" #include "perl.h" #ifdef I_VARARGS # include #endif static STR str_chop; void grow_dlevel(); /* do longjmps() clobber register variables? */ #if defined(cray) || defined(__STDC__) #define JMPCLOBBER #endif /* This is the main command loop. We try to spend as much time in this loop * as possible, so lots of optimizations do their activities in here. This * means things get a little sloppy. */ int cmd_exec(cmdparm,gimme,sp) CMD *VOLATILE cmdparm; VOLATILE int gimme; VOLATILE int sp; { register CMD *cmd = cmdparm; SPAT *VOLATILE oldspat; VOLATILE int firstsave = savestack->ary_fill; VOLATILE int oldsave; VOLATILE int aryoptsave; #ifdef DEBUGGING VOLATILE int olddlevel; VOLATILE int entdlevel; #endif register STR *retstr = &str_undef; register char *tmps; register int cmdflags; register int match; register char *go_to = goto_targ; register int newsp = -2; register STR **st = stack->ary_array; FILE *VOLATILE fp; ARRAY *VOLATILE ar; lastsize = 0; #ifdef DEBUGGING entdlevel = dlevel; #endif tail_recursion_entry: #ifdef DEBUGGING dlevel = entdlevel; #endif #ifdef TAINT tainted = 0; /* Each statement is presumed innocent */ #endif if (cmd == Nullcmd) { if (gimme == G_ARRAY && newsp > -2) return newsp; else { st[++sp] = retstr; return sp; } } cmdflags = cmd->c_flags; /* hopefully load register */ if (go_to) { if (cmd->c_label && strEQ(go_to,cmd->c_label)) goto_targ = go_to = Nullch; /* here at last */ else { switch (cmd->c_type) { case C_IF: oldspat = curspat; oldsave = savestack->ary_fill; #ifdef DEBUGGING olddlevel = dlevel; #endif retstr = &str_yes; newsp = -2; if (cmd->ucmd.ccmd.cc_true) { #ifdef DEBUGGING if (debug) { debname[dlevel] = 't'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); } #endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } if (!goto_targ) go_to = Nullch; curspat = oldspat; if (savestack->ary_fill > oldsave) restorelist(oldsave); #ifdef DEBUGGING dlevel = olddlevel; #endif cmd = cmd->ucmd.ccmd.cc_alt; goto tail_recursion_entry; case C_ELSE: oldspat = curspat; oldsave = savestack->ary_fill; #ifdef DEBUGGING olddlevel = dlevel; #endif retstr = &str_undef; newsp = -2; if (cmd->ucmd.ccmd.cc_true) { #ifdef DEBUGGING if (debug) { debname[dlevel] = 'e'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); } #endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } if (!goto_targ) go_to = Nullch; curspat = oldspat; if (savestack->ary_fill > oldsave) restorelist(oldsave); #ifdef DEBUGGING dlevel = olddlevel; #endif break; case C_BLOCK: case C_WHILE: if (!(cmdflags & CF_ONCE)) { cmdflags |= CF_ONCE; if (++loop_ptr >= loop_max) { loop_max += 128; Renew(loop_stack, loop_max, struct loop); } loop_stack[loop_ptr].loop_label = cmd->c_label; loop_stack[loop_ptr].loop_sp = sp; #ifdef DEBUGGING if (debug & 4) { deb("(Pushing label #%d %s)\n", loop_ptr, cmd->c_label ? cmd->c_label : ""); } #endif } #ifdef JMPCLOBBER cmdparm = cmd; #endif if (match = setjmp(loop_stack[loop_ptr].loop_env)) { st = stack->ary_array; /* possibly reallocated */ #ifdef JMPCLOBBER cmd = cmdparm; cmdflags = cmd->c_flags|CF_ONCE; #endif if (savestack->ary_fill > oldsave) restorelist(oldsave); switch (match) { default: fatal("longjmp returned bad value (%d)",match); case O_LAST: /* not done unless go_to found */ go_to = Nullch; if (lastretstr) { retstr = lastretstr; newsp = -2; } else { newsp = sp + lastsize; retstr = st[newsp]; } #ifdef DEBUGGING olddlevel = dlevel; #endif curspat = oldspat; goto next_cmd; case O_NEXT: /* not done unless go_to found */ go_to = Nullch; #ifdef JMPCLOBBER newsp = -2; retstr = &str_undef; #endif goto next_iter; case O_REDO: /* not done unless go_to found */ go_to = Nullch; #ifdef JMPCLOBBER newsp = -2; retstr = &str_undef; #endif goto doit; } } oldspat = curspat; oldsave = savestack->ary_fill; #ifdef DEBUGGING olddlevel = dlevel; #endif if (cmd->ucmd.ccmd.cc_true) { #ifdef DEBUGGING if (debug) { debname[dlevel] = 't'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); } #endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } if (!goto_targ) { go_to = Nullch; goto next_iter; } #ifdef DEBUGGING dlevel = olddlevel; #endif if (cmd->ucmd.ccmd.cc_alt) { #ifdef DEBUGGING if (debug) { debname[dlevel] = 'a'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); } #endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_alt,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } if (goto_targ) break; go_to = Nullch; goto finish_while; } cmd = cmd->c_next; if (cmd && cmd->c_head == cmd) /* reached end of while loop */ return sp; /* targ isn't in this block */ if (cmdflags & CF_ONCE) { #ifdef DEBUGGING if (debug & 4) { tmps = loop_stack[loop_ptr].loop_label; deb("(Popping label #%d %s)\n",loop_ptr, tmps ? tmps : "" ); } #endif loop_ptr--; } goto tail_recursion_entry; } } until_loop: /* Set line number so run-time errors can be located */ curcmd = cmd; #ifdef DEBUGGING if (debug) { if (debug & 2) { deb("%s (%lx) r%lx t%lx a%lx n%lx cs%lx\n", cmdname[cmd->c_type],cmd,cmd->c_expr, cmd->ucmd.ccmd.cc_true,cmd->ucmd.ccmd.cc_alt,cmd->c_next, curspat); } debname[dlevel] = cmdname[cmd->c_type][0]; debdelim[dlevel] = '!'; if (++dlevel >= dlmax) grow_dlevel(); } #endif /* Here is some common optimization */ if (cmdflags & CF_COND) { switch (cmdflags & CF_OPTIMIZE) { case CFT_FALSE: retstr = cmd->c_short; newsp = -2; match = FALSE; if (cmdflags & CF_NESURE) goto maybe; break; case CFT_TRUE: retstr = cmd->c_short; newsp = -2; match = TRUE; if (cmdflags & CF_EQSURE) goto flipmaybe; break; case CFT_REG: retstr = STAB_STR(cmd->c_stab); newsp = -2; match = str_true(retstr); /* => retstr = retstr, c2 should fix */ if (cmdflags & (match ? CF_EQSURE : CF_NESURE)) goto flipmaybe; break; case CFT_ANCHOR: /* /^pat/ optimization */ if (multiline) { if (*cmd->c_short->str_ptr && !(cmdflags & CF_EQSURE)) goto scanner; /* just unanchor it */ else break; /* must evaluate */ } /* FALL THROUGH */ case CFT_STROP: /* string op optimization */ retstr = STAB_STR(cmd->c_stab); newsp = -2; #ifndef I286 if (*cmd->c_short->str_ptr == *str_get(retstr) && bcmp(cmd->c_short->str_ptr, str_get(retstr), cmd->c_slen) == 0 ) { if (cmdflags & CF_EQSURE) { if (sawampersand && (cmdflags & CF_OPTIMIZE) != CFT_STROP) { curspat = Nullspat; if (leftstab) str_nset(stab_val(leftstab),"",0); if (amperstab) str_sset(stab_val(amperstab),cmd->c_short); if (rightstab) str_nset(stab_val(rightstab), retstr->str_ptr + cmd->c_slen, retstr->str_cur - cmd->c_slen); } match = !(cmdflags & CF_FIRSTNEG); retstr = &str_yes; goto flipmaybe; } } else if (cmdflags & CF_NESURE) { match = cmdflags & CF_FIRSTNEG; retstr = &str_no; goto flipmaybe; } #else { char *zap1, *zap2, zap1c, zap2c; int zaplen; zap1 = cmd->c_short->str_ptr; zap2 = str_get(retstr); zap1c = *zap1; zap2c = *zap2; zaplen = cmd->c_slen; if ((zap1c == zap2c) && (bcmp(zap1, zap2, zaplen) == 0)) { if (cmdflags & CF_EQSURE) { if (sawampersand && (cmdflags & CF_OPTIMIZE) != CFT_STROP) { curspat = Nullspat; if (leftstab) str_nset(stab_val(leftstab),"",0); if (amperstab) str_sset(stab_val(amperstab),cmd->c_short); if (rightstab) str_nset(stab_val(rightstab), retstr->str_ptr + cmd->c_slen, retstr->str_cur - cmd->c_slen); } match = !(cmdflags & CF_FIRSTNEG); retstr = &str_yes; goto flipmaybe; } } else if (cmdflags & CF_NESURE) { match = cmdflags & CF_FIRSTNEG; retstr = &str_no; goto flipmaybe; } } #endif break; /* must evaluate */ case CFT_SCAN: /* non-anchored search */ scanner: retstr = STAB_STR(cmd->c_stab); newsp = -2; if (retstr->str_pok & SP_STUDIED) if (screamfirst[cmd->c_short->str_rare] >= 0) tmps = screaminstr(retstr, cmd->c_short); else tmps = Nullch; else { tmps = str_get(retstr); /* make sure it's pok */ #ifndef lint tmps = fbminstr((unsigned char*)tmps, (unsigned char*)tmps + retstr->str_cur, cmd->c_short); #endif } if (tmps) { if (cmdflags & CF_EQSURE) { ++cmd->c_short->str_u.str_useful; if (sawampersand) { curspat = Nullspat; if (leftstab) str_nset(stab_val(leftstab),retstr->str_ptr, tmps - retstr->str_ptr); if (amperstab) str_sset(stab_val(amperstab),cmd->c_short); if (rightstab) str_nset(stab_val(rightstab), tmps + cmd->c_short->str_cur, retstr->str_cur - (tmps - retstr->str_ptr) - cmd->c_short->str_cur); } match = !(cmdflags & CF_FIRSTNEG); retstr = &str_yes; goto flipmaybe; } else hint = tmps; } else { if (cmdflags & CF_NESURE) { ++cmd->c_short->str_u.str_useful; match = cmdflags & CF_FIRSTNEG; retstr = &str_no; goto flipmaybe; } } if (--cmd->c_short->str_u.str_useful < 0) { cmdflags &= ~CF_OPTIMIZE; cmdflags |= CFT_EVAL; /* never try this optimization again */ cmd->c_flags = (cmdflags & ~CF_ONCE); } break; /* must evaluate */ case CFT_NUMOP: /* numeric op optimization */ retstr = STAB_STR(cmd->c_stab); newsp = -2; switch (cmd->c_slen) { case O_EQ: if (dowarn) { if ((!retstr->str_nok && !looks_like_number(retstr))) warn("Possible use of == on string value"); } match = (str_gnum(retstr) == cmd->c_short->str_u.str_nval); break; case O_NE: match = (str_gnum(retstr) != cmd->c_short->str_u.str_nval); break; case O_LT: match = (str_gnum(retstr) < cmd->c_short->str_u.str_nval); break; case O_LE: match = (str_gnum(retstr) <= cmd->c_short->str_u.str_nval); break; case O_GT: match = (str_gnum(retstr) > cmd->c_short->str_u.str_nval); break; case O_GE: match = (str_gnum(retstr) >= cmd->c_short->str_u.str_nval); break; } if (match) { if (cmdflags & CF_EQSURE) { retstr = &str_yes; goto flipmaybe; } } else if (cmdflags & CF_NESURE) { retstr = &str_no; goto flipmaybe; } break; /* must evaluate */ case CFT_INDGETS: /* while (<$foo>) */ last_in_stab = stabent(str_get(STAB_STR(cmd->c_stab)),TRUE); if (!stab_io(last_in_stab)) stab_io(last_in_stab) = stio_new(); goto dogets; case CFT_GETS: /* really a while () */ last_in_stab = cmd->c_stab; dogets: fp = stab_io(last_in_stab)->ifp; retstr = stab_val(defstab); newsp = -2; keepgoing: if (fp && str_gets(retstr, fp, 0)) { if (*retstr->str_ptr == '0' && retstr->str_cur == 1) match = FALSE; else match = TRUE; stab_io(last_in_stab)->lines++; } else if (stab_io(last_in_stab)->flags & IOF_ARGV) { if (!fp) goto doeval; /* first time through */ fp = nextargv(last_in_stab); if (fp) goto keepgoing; (void)do_close(last_in_stab,FALSE); stab_io(last_in_stab)->flags |= IOF_START; retstr = &str_undef; match = FALSE; } else { retstr = &str_undef; match = FALSE; } goto flipmaybe; case CFT_EVAL: break; case CFT_UNFLIP: while (tmps_max > tmps_base) /* clean up after last eval */ str_free(tmps_list[tmps_max--]); newsp = eval(cmd->c_expr,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; match = str_true(retstr); if (cmd->c_expr->arg_type == O_FLIP) /* undid itself? */ cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd); goto maybe; case CFT_CHOP: retstr = stab_val(cmd->c_stab); newsp = -2; match = (retstr->str_cur != 0); tmps = str_get(retstr); tmps += retstr->str_cur - match; str_nset(&str_chop,tmps,match); *tmps = '\0'; retstr->str_nok = 0; retstr->str_cur = tmps - retstr->str_ptr; retstr = &str_chop; goto flipmaybe; case CFT_ARRAY: match = cmd->c_short->str_u.str_useful; /* just to get register */ if (match < 0) { /* first time through here? */ ar = stab_array(cmd->c_expr[1].arg_ptr.arg_stab); aryoptsave = savestack->ary_fill; savesptr(&stab_val(cmd->c_stab)); savelong(&cmd->c_short->str_u.str_useful); } else { ar = stab_xarray(cmd->c_expr[1].arg_ptr.arg_stab); if (cmd->c_type != C_WHILE && savestack->ary_fill > firstsave) restorelist(firstsave); } if (match >= ar->ary_fill) { /* we're in LAST, probably */ retstr = &str_undef; cmd->c_short->str_u.str_useful = -1; /* actually redundant */ match = FALSE; } else { match++; if (!(retstr = ar->ary_array[match])) retstr = afetch(ar,match,TRUE); stab_val(cmd->c_stab) = retstr; cmd->c_short->str_u.str_useful = match; match = TRUE; } newsp = -2; goto maybe; case CFT_D1: break; case CFT_D0: if (DBsingle->str_u.str_nval != 0) break; if (DBsignal->str_u.str_nval != 0) break; if (DBtrace->str_u.str_nval != 0) break; goto next_cmd; } /* we have tried to make this normal case as abnormal as possible */ doeval: if (gimme == G_ARRAY) { lastretstr = Nullstr; lastspbase = sp; lastsize = newsp - sp; } else lastretstr = retstr; while (tmps_max > tmps_base) /* clean up after last eval */ str_free(tmps_list[tmps_max--]); newsp = eval(cmd->c_expr, gimme && (cmdflags & CF_TERM) && cmd->c_type == C_EXPR && !cmd->ucmd.acmd.ac_expr, sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; if (newsp > sp && retstr) match = str_true(retstr); else match = FALSE; goto maybe; /* if flipflop was true, flop it */ flipmaybe: if (match && cmdflags & CF_FLIP) { while (tmps_max > tmps_base) /* clean up after last eval */ str_free(tmps_list[tmps_max--]); if (cmd->c_expr->arg_type == O_FLOP) { /* currently toggled? */ newsp = eval(cmd->c_expr,G_SCALAR,sp);/*let eval undo it*/ cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd); } else { newsp = eval(cmd->c_expr,G_SCALAR,sp);/* let eval do it */ if (cmd->c_expr->arg_type == O_FLOP) /* still toggled? */ cmdflags = copyopt(cmd,cmd->c_expr[4].arg_ptr.arg_cmd); } } else if (cmdflags & CF_FLIP) { if (cmd->c_expr->arg_type == O_FLOP) { /* currently toggled? */ match = TRUE; /* force on */ } } /* at this point, match says whether our expression was true */ maybe: if (cmdflags & CF_INVERT) match = !match; if (!match) goto next_cmd; } #ifdef TAINT tainted = 0; /* modifier doesn't affect regular expression */ #endif /* now to do the actual command, if any */ switch (cmd->c_type) { case C_NULL: fatal("panic: cmd_exec"); case C_EXPR: /* evaluated for side effects */ if (cmd->ucmd.acmd.ac_expr) { /* more to do? */ if (gimme == G_ARRAY) { lastretstr = Nullstr; lastspbase = sp; lastsize = newsp - sp; } else lastretstr = retstr; while (tmps_max > tmps_base) /* clean up after last eval */ str_free(tmps_list[tmps_max--]); newsp = eval(cmd->ucmd.acmd.ac_expr,gimme && (cmdflags&CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } break; case C_NSWITCH: { double value = str_gnum(STAB_STR(cmd->c_stab)); match = (int)value; if (value < 0.0) { if (((double)match) > value) --match; /* was fractional--truncate other way */ } } goto doswitch; case C_CSWITCH: match = *(str_get(STAB_STR(cmd->c_stab))) & 255; doswitch: match -= cmd->ucmd.scmd.sc_offset; if (match < 0) match = 0; else if (match > cmd->ucmd.scmd.sc_max) match = cmd->ucmd.scmd.sc_max; cmd = cmd->ucmd.scmd.sc_next[match]; goto tail_recursion_entry; case C_NEXT: cmd = cmd->ucmd.ccmd.cc_alt; goto tail_recursion_entry; case C_ELSIF: fatal("panic: ELSIF"); case C_IF: oldspat = curspat; oldsave = savestack->ary_fill; #ifdef DEBUGGING olddlevel = dlevel; #endif retstr = &str_yes; newsp = -2; if (cmd->ucmd.ccmd.cc_true) { #ifdef DEBUGGING if (debug) { debname[dlevel] = 't'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); } #endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } curspat = oldspat; if (savestack->ary_fill > oldsave) restorelist(oldsave); #ifdef DEBUGGING dlevel = olddlevel; #endif cmd = cmd->ucmd.ccmd.cc_alt; goto tail_recursion_entry; case C_ELSE: oldspat = curspat; oldsave = savestack->ary_fill; #ifdef DEBUGGING olddlevel = dlevel; #endif retstr = &str_undef; newsp = -2; if (cmd->ucmd.ccmd.cc_true) { #ifdef DEBUGGING if (debug) { debname[dlevel] = 'e'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); } #endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } curspat = oldspat; if (savestack->ary_fill > oldsave) restorelist(oldsave); #ifdef DEBUGGING dlevel = olddlevel; #endif break; case C_BLOCK: case C_WHILE: if (!(cmdflags & CF_ONCE)) { /* first time through here? */ cmdflags |= CF_ONCE; if (++loop_ptr >= loop_max) { loop_max += 128; Renew(loop_stack, loop_max, struct loop); } loop_stack[loop_ptr].loop_label = cmd->c_label; loop_stack[loop_ptr].loop_sp = sp; #ifdef DEBUGGING if (debug & 4) { deb("(Pushing label #%d %s)\n", loop_ptr, cmd->c_label ? cmd->c_label : ""); } #endif } #ifdef JMPCLOBBER cmdparm = cmd; #endif if (match = setjmp(loop_stack[loop_ptr].loop_env)) { st = stack->ary_array; /* possibly reallocated */ #ifdef JMPCLOBBER cmd = cmdparm; cmdflags = cmd->c_flags|CF_ONCE; go_to = goto_targ; #endif if (savestack->ary_fill > oldsave) restorelist(oldsave); switch (match) { default: fatal("longjmp returned bad value (%d)",match); case O_LAST: if (lastretstr) { retstr = lastretstr; newsp = -2; } else { newsp = sp + lastsize; retstr = st[newsp]; } curspat = oldspat; goto next_cmd; case O_NEXT: #ifdef JMPCLOBBER newsp = -2; retstr = &str_undef; #endif goto next_iter; case O_REDO: #ifdef DEBUGGING dlevel = olddlevel; #endif #ifdef JMPCLOBBER newsp = -2; retstr = &str_undef; #endif goto doit; } } oldspat = curspat; oldsave = savestack->ary_fill; #ifdef DEBUGGING olddlevel = dlevel; #endif doit: if (cmd->ucmd.ccmd.cc_true) { #ifdef DEBUGGING if (debug) { debname[dlevel] = 't'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); } #endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } /* actually, this spot is rarely reached anymore since the above * cmd_exec() returns through longjmp(). Hooray for structure. */ next_iter: #ifdef DEBUGGING dlevel = olddlevel; #endif if (cmd->ucmd.ccmd.cc_alt) { #ifdef DEBUGGING if (debug) { debname[dlevel] = 'a'; debdelim[dlevel] = '_'; if (++dlevel >= dlmax) grow_dlevel(); } #endif newsp = cmd_exec(cmd->ucmd.ccmd.cc_alt,gimme && (cmdflags & CF_TERM),sp); st = stack->ary_array; /* possibly reallocated */ retstr = st[newsp]; } finish_while: curspat = oldspat; if (savestack->ary_fill > oldsave) { if (cmdflags & CF_TERM) { for (match = sp + 1; match <= newsp; match++) st[match] = str_static(st[match]); retstr = st[newsp]; } restorelist(oldsave); } #ifdef DEBUGGING dlevel = olddlevel - 1; #endif if (cmd->c_type != C_BLOCK) goto until_loop; /* go back and evaluate conditional again */ } if (cmdflags & CF_LOOP) { cmdflags |= CF_COND; /* now test the condition */ #ifdef DEBUGGING dlevel = entdlevel; #endif goto until_loop; } next_cmd: if (cmdflags & CF_ONCE) { #ifdef DEBUGGING if (debug & 4) { tmps = loop_stack[loop_ptr].loop_label; deb("(Popping label #%d %s)\n",loop_ptr, tmps ? tmps : ""); } #endif loop_ptr--; if ((cmdflags & CF_OPTIMIZE) == CFT_ARRAY && savestack->ary_fill > aryoptsave) restorelist(aryoptsave); } cmd = cmd->c_next; goto tail_recursion_entry; } #ifdef DEBUGGING # ifndef VARARGS /*VARARGS1*/ deb(pat,a1,a2,a3,a4,a5,a6,a7,a8) char *pat; { register int i; fprintf(stderr,"%-4ld",(long)curcmd->c_line); for (i=0; ic_line); for (i=0; ic_flags &= CF_ONCE|CF_COND|CF_LOOP; cmd->c_flags |= which->c_flags; cmd->c_short = which->c_short; cmd->c_slen = which->c_slen; cmd->c_stab = which->c_stab; return cmd->c_flags; } ARRAY * saveary(stab) STAB *stab; { register STR *str; str = Str_new(10,0); str->str_state = SS_SARY; str->str_u.str_stab = stab; if (str->str_ptr) { Safefree(str->str_ptr); str->str_len = 0; } str->str_ptr = (char*)stab_array(stab); (void)apush(savestack,str); /* save array ptr */ stab_xarray(stab) = Null(ARRAY*); return stab_xarray(aadd(stab)); } HASH * savehash(stab) STAB *stab; { register STR *str; str = Str_new(11,0); str->str_state = SS_SHASH; str->str_u.str_stab = stab; if (str->str_ptr) { Safefree(str->str_ptr); str->str_len = 0; } str->str_ptr = (char*)stab_hash(stab); (void)apush(savestack,str); /* save hash ptr */ stab_xhash(stab) = Null(HASH*); return stab_xhash(hadd(stab)); } void saveitem(item) register STR *item; { register STR *str; (void)apush(savestack,item); /* remember the pointer */ str = Str_new(12,0); str_sset(str,item); (void)apush(savestack,str); /* remember the value */ } void saveint(intp) int *intp; { register STR *str; str = Str_new(13,0); str->str_state = SS_SINT; str->str_u.str_useful = (long)*intp; /* remember value */ if (str->str_ptr) { Safefree(str->str_ptr); str->str_len = 0; } str->str_ptr = (char*)intp; /* remember pointer */ (void)apush(savestack,str); } void savelong(longp) long *longp; { register STR *str; str = Str_new(14,0); str->str_state = SS_SLONG; str->str_u.str_useful = *longp; /* remember value */ if (str->str_ptr) { Safefree(str->str_ptr); str->str_len = 0; } str->str_ptr = (char*)longp; /* remember pointer */ (void)apush(savestack,str); } void savesptr(sptr) STR **sptr; { register STR *str; str = Str_new(15,0); str->str_state = SS_SSTRP; str->str_magic = *sptr; /* remember value */ if (str->str_ptr) { Safefree(str->str_ptr); str->str_len = 0; } str->str_ptr = (char*)sptr; /* remember pointer */ (void)apush(savestack,str); } void savenostab(stab) STAB *stab; { register STR *str; str = Str_new(16,0); str->str_state = SS_SNSTAB; str->str_magic = (STR*)stab; /* remember which stab to free */ (void)apush(savestack,str); } void savehptr(hptr) HASH **hptr; { register STR *str; str = Str_new(17,0); str->str_state = SS_SHPTR; str->str_u.str_hash = *hptr; /* remember value */ if (str->str_ptr) { Safefree(str->str_ptr); str->str_len = 0; } str->str_ptr = (char*)hptr; /* remember pointer */ (void)apush(savestack,str); } void savelist(sarg,maxsarg) register STR **sarg; int maxsarg; { register STR *str; register int i; for (i = 1; i <= maxsarg; i++) { (void)apush(savestack,sarg[i]); /* remember the pointer */ str = Str_new(18,0); str_sset(str,sarg[i]); (void)apush(savestack,str); /* remember the value */ sarg[i]->str_u.str_useful = -1; } } void restorelist(base) int base; { register STR *str; register STR *value; register STAB *stab; if (base < -1) fatal("panic: corrupt saved stack index"); while (savestack->ary_fill > base) { value = apop(savestack); switch (value->str_state) { case SS_NORM: /* normal string */ case SS_INCR: str = apop(savestack); str_replace(str,value); STABSET(str); break; case SS_SARY: /* array reference */ stab = value->str_u.str_stab; afree(stab_xarray(stab)); stab_xarray(stab) = (ARRAY*)value->str_ptr; value->str_ptr = Nullch; str_free(value); break; case SS_SHASH: /* hash reference */ stab = value->str_u.str_stab; (void)hfree(stab_xhash(stab), FALSE); stab_xhash(stab) = (HASH*)value->str_ptr; value->str_ptr = Nullch; str_free(value); break; case SS_SINT: /* int reference */ *((int*)value->str_ptr) = (int)value->str_u.str_useful; value->str_ptr = Nullch; str_free(value); break; case SS_SLONG: /* long reference */ *((long*)value->str_ptr) = value->str_u.str_useful; value->str_ptr = Nullch; str_free(value); break; case SS_SSTRP: /* STR* reference */ *((STR**)value->str_ptr) = value->str_magic; value->str_magic = Nullstr; value->str_ptr = Nullch; str_free(value); break; case SS_SHPTR: /* HASH* reference */ *((HASH**)value->str_ptr) = value->str_u.str_hash; value->str_ptr = Nullch; str_free(value); break; case SS_SNSTAB: stab = (STAB*)value->str_magic; value->str_magic = Nullstr; (void)stab_clear(stab); str_free(value); break; case SS_SCSV: /* callsave structure */ { CSV *csv = (CSV*) value->str_ptr; curcmd = csv->curcmd; curcsv = csv->curcsv; csv->sub->depth = csv->depth; if (csv->hasargs) { /* put back old @_ */ afree(csv->argarray); stab_xarray(defstab) = csv->savearray; } str_free(value); } break; default: fatal("panic: restorelist inconsistency"); } } } #ifdef DEBUGGING void grow_dlevel() { dlmax += 128; Renew(debname, dlmax, char); Renew(debdelim, dlmax, char); } #endif