summaryrefslogtreecommitdiff
path: root/cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd.c')
-rw-r--r--cmd.c453
1 files changed, 453 insertions, 0 deletions
diff --git a/cmd.c b/cmd.c
new file mode 100644
index 0000000000..ba57a2a3fc
--- /dev/null
+++ b/cmd.c
@@ -0,0 +1,453 @@
+/* $Header: cmd.c,v 1.0 87/12/18 13:04:51 root Exp $
+ *
+ * $Log: cmd.c,v $
+ * Revision 1.0 87/12/18 13:04:51 root
+ * Initial revision
+ *
+ */
+
+#include "handy.h"
+#include "EXTERN.h"
+#include "search.h"
+#include "util.h"
+#include "perl.h"
+
+static STR str_chop;
+
+/* 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.
+ */
+
+STR *
+cmd_exec(cmd)
+register CMD *cmd;
+{
+ SPAT *oldspat;
+#ifdef DEBUGGING
+ int olddlevel;
+ int entdlevel;
+#endif
+ register STR *retstr;
+ register char *tmps;
+ register int cmdflags;
+ register bool match;
+ register char *go_to = goto_targ;
+ ARG *arg;
+ FILE *fp;
+
+ retstr = &str_no;
+#ifdef DEBUGGING
+ entdlevel = dlevel;
+#endif
+tail_recursion_entry:
+#ifdef DEBUGGING
+ dlevel = entdlevel;
+#endif
+ if (cmd == Nullcmd)
+ return retstr;
+ 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;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ retstr = &str_yes;
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ debname[dlevel] = 't';
+ debdelim[dlevel++] = '_';
+#endif
+ retstr = cmd_exec(cmd->ucmd.ccmd.cc_true);
+ }
+ if (!goto_targ) {
+ go_to = Nullch;
+ } else {
+ retstr = &str_no;
+ if (cmd->ucmd.ccmd.cc_alt) {
+#ifdef DEBUGGING
+ debname[dlevel] = 'e';
+ debdelim[dlevel++] = '_';
+#endif
+ retstr = cmd_exec(cmd->ucmd.ccmd.cc_alt);
+ }
+ }
+ if (!goto_targ)
+ go_to = Nullch;
+ curspat = oldspat;
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+ break;
+ case C_BLOCK:
+ case C_WHILE:
+ if (!(cmdflags & CF_ONCE)) {
+ cmdflags |= CF_ONCE;
+ loop_ptr++;
+ loop_stack[loop_ptr].loop_label = cmd->c_label;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Pushing label #%d %s)\n",
+ loop_ptr,cmd->c_label);
+ }
+#endif
+ }
+ switch (setjmp(loop_stack[loop_ptr].loop_env)) {
+ case O_LAST: /* not done unless go_to found */
+ go_to = Nullch;
+ retstr = &str_no;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ curspat = oldspat;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Popping label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ loop_ptr--;
+ cmd = cmd->c_next;
+ goto tail_recursion_entry;
+ case O_NEXT: /* not done unless go_to found */
+ go_to = Nullch;
+ goto next_iter;
+ case O_REDO: /* not done unless go_to found */
+ go_to = Nullch;
+ goto doit;
+ }
+ oldspat = curspat;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ debname[dlevel] = 't';
+ debdelim[dlevel++] = '_';
+#endif
+ cmd_exec(cmd->ucmd.ccmd.cc_true);
+ }
+ if (!goto_targ) {
+ go_to = Nullch;
+ goto next_iter;
+ }
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+ if (cmd->ucmd.ccmd.cc_alt) {
+#ifdef DEBUGGING
+ debname[dlevel] = 'a';
+ debdelim[dlevel++] = '_';
+#endif
+ cmd_exec(cmd->ucmd.ccmd.cc_alt);
+ }
+ 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 retstr; /* targ isn't in this block */
+ goto tail_recursion_entry;
+ }
+ }
+
+until_loop:
+
+#ifdef DEBUGGING
+ 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++] = '!';
+#endif
+ while (tmps_max >= 0) /* clean up after last eval */
+ str_free(tmps_list[tmps_max--]);
+
+ /* Here is some common optimization */
+
+ if (cmdflags & CF_COND) {
+ switch (cmdflags & CF_OPTIMIZE) {
+
+ case CFT_FALSE:
+ retstr = cmd->c_first;
+ match = FALSE;
+ if (cmdflags & CF_NESURE)
+ goto maybe;
+ break;
+ case CFT_TRUE:
+ retstr = cmd->c_first;
+ match = TRUE;
+ if (cmdflags & CF_EQSURE)
+ goto flipmaybe;
+ break;
+
+ case CFT_REG:
+ retstr = STAB_STR(cmd->c_stab);
+ 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_first->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);
+ if (*cmd->c_first->str_ptr == *str_get(retstr) &&
+ strnEQ(cmd->c_first->str_ptr, str_get(retstr),
+ cmd->c_flen) ) {
+ if (cmdflags & CF_EQSURE) {
+ match = !(cmdflags & CF_FIRSTNEG);
+ retstr = &str_yes;
+ goto flipmaybe;
+ }
+ }
+ else if (cmdflags & CF_NESURE) {
+ match = cmdflags & CF_FIRSTNEG;
+ retstr = &str_no;
+ goto flipmaybe;
+ }
+ break; /* must evaluate */
+
+ case CFT_SCAN: /* non-anchored search */
+ scanner:
+ retstr = STAB_STR(cmd->c_stab);
+ if (instr(str_get(retstr),cmd->c_first->str_ptr)) {
+ if (cmdflags & CF_EQSURE) {
+ match = !(cmdflags & CF_FIRSTNEG);
+ retstr = &str_yes;
+ goto flipmaybe;
+ }
+ }
+ else if (cmdflags & CF_NESURE) {
+ match = cmdflags & CF_FIRSTNEG;
+ retstr = &str_no;
+ goto flipmaybe;
+ }
+ break; /* must evaluate */
+
+ case CFT_GETS: /* really a while (<file>) */
+ last_in_stab = cmd->c_stab;
+ fp = last_in_stab->stab_io->fp;
+ retstr = defstab->stab_val;
+ if (fp && str_gets(retstr, fp)) {
+ last_in_stab->stab_io->lines++;
+ match = TRUE;
+ }
+ else if (last_in_stab->stab_io->flags & IOF_ARGV)
+ goto doeval; /* doesn't necessarily count as EOF yet */
+ else {
+ retstr = &str_no;
+ match = FALSE;
+ }
+ goto flipmaybe;
+ case CFT_EVAL:
+ break;
+ case CFT_UNFLIP:
+ retstr = eval(cmd->c_expr,Null(char***));
+ 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 = cmd->c_stab->stab_val;
+ match = (retstr->str_cur != 0);
+ tmps = str_get(retstr);
+ tmps += retstr->str_cur - match;
+ str_set(&str_chop,tmps);
+ *tmps = '\0';
+ retstr->str_nok = 0;
+ retstr->str_cur = tmps - retstr->str_ptr;
+ retstr = &str_chop;
+ goto flipmaybe;
+ }
+
+ /* we have tried to make this normal case as abnormal as possible */
+
+ doeval:
+ retstr = eval(cmd->c_expr,Null(char***));
+ match = str_true(retstr);
+ goto maybe;
+
+ /* if flipflop was true, flop it */
+
+ flipmaybe:
+ if (match && cmdflags & CF_FLIP) {
+ if (cmd->c_expr->arg_type == O_FLOP) { /* currently toggled? */
+ retstr = eval(cmd->c_expr,Null(char***)); /* let eval undo it */
+ cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd);
+ }
+ else {
+ retstr = eval(cmd->c_expr,Null(char***)); /* 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 && cmd->c_type != C_IF) {
+ cmd = cmd->c_next;
+ goto tail_recursion_entry;
+ }
+ }
+
+ /* now to do the actual command, if any */
+
+ switch (cmd->c_type) {
+ case C_NULL:
+ fatal("panic: cmd_exec\n");
+ case C_EXPR: /* evaluated for side effects */
+ if (cmd->ucmd.acmd.ac_expr) { /* more to do? */
+ retstr = eval(cmd->ucmd.acmd.ac_expr,Null(char***));
+ }
+ break;
+ case C_IF:
+ oldspat = curspat;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ if (match) {
+ retstr = &str_yes;
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ debname[dlevel] = 't';
+ debdelim[dlevel++] = '_';
+#endif
+ retstr = cmd_exec(cmd->ucmd.ccmd.cc_true);
+ }
+ }
+ else {
+ retstr = &str_no;
+ if (cmd->ucmd.ccmd.cc_alt) {
+#ifdef DEBUGGING
+ debname[dlevel] = 'e';
+ debdelim[dlevel++] = '_';
+#endif
+ retstr = cmd_exec(cmd->ucmd.ccmd.cc_alt);
+ }
+ }
+ curspat = oldspat;
+#ifdef DEBUGGING
+ dlevel = olddlevel;
+#endif
+ break;
+ case C_BLOCK:
+ case C_WHILE:
+ if (!(cmdflags & CF_ONCE)) { /* first time through here? */
+ cmdflags |= CF_ONCE;
+ loop_ptr++;
+ loop_stack[loop_ptr].loop_label = cmd->c_label;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Pushing label #%d %s)\n",
+ loop_ptr,cmd->c_label);
+ }
+#endif
+ }
+ switch (setjmp(loop_stack[loop_ptr].loop_env)) {
+ case O_LAST:
+ retstr = &str_no;
+ curspat = oldspat;
+#ifdef DEBUGGING
+ if (debug & 4) {
+ deb("(Popping label #%d %s)\n",loop_ptr,
+ loop_stack[loop_ptr].loop_label);
+ }
+#endif
+ loop_ptr--;
+ cmd = cmd->c_next;
+ goto tail_recursion_entry;
+ case O_NEXT:
+ goto next_iter;
+ case O_REDO:
+ goto doit;
+ }
+ oldspat = curspat;
+#ifdef DEBUGGING
+ olddlevel = dlevel;
+#endif
+ doit:
+ if (cmd->ucmd.ccmd.cc_true) {
+#ifdef DEBUGGING
+ debname[dlevel] = 't';
+ debdelim[dlevel++] = '_';
+#endif
+ cmd_exec(cmd->ucmd.ccmd.cc_true);
+ }
+ /* actually, this spot is never 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
+ debname[dlevel] = 'a';
+ debdelim[dlevel++] = '_';
+#endif
+ cmd_exec(cmd->ucmd.ccmd.cc_alt);
+ }
+ finish_while:
+ curspat = oldspat;
+#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 */
+ goto until_loop;
+ }
+ cmd = cmd->c_next;
+ goto tail_recursion_entry;
+}
+
+#ifdef DEBUGGING
+/*VARARGS1*/
+deb(pat,a1,a2,a3,a4,a5,a6,a7,a8)
+char *pat;
+{
+ register int i;
+
+ for (i=0; i<dlevel; i++)
+ fprintf(stderr,"%c%c ",debname[i],debdelim[i]);
+ fprintf(stderr,pat,a1,a2,a3,a4,a5,a6,a7,a8);
+}
+#endif
+
+copyopt(cmd,which)
+register CMD *cmd;
+register CMD *which;
+{
+ cmd->c_flags &= CF_ONCE|CF_COND|CF_LOOP;
+ cmd->c_flags |= which->c_flags;
+ cmd->c_first = which->c_first;
+ cmd->c_flen = which->c_flen;
+ cmd->c_stab = which->c_stab;
+ return cmd->c_flags;
+}