home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / program / language / perl / Source / C / Cmd < prev    next >
Encoding:
Text File  |  1990-11-11  |  29.9 KB  |  1,240 lines

  1. /* $Header: cmd.c,v 3.0.1.10 90/10/20 02:01:56 lwall Locked $
  2.  *
  3.  *    Copyright (c) 1989, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of the GNU General Public License
  6.  *    as specified in the README file that comes with the perl 3.0 kit.
  7.  *
  8.  * $Log:    cmd.c,v $
  9.  * Revision 3.0.1.10  90/10/20  02:01:56  lwall
  10.  * patch37: cray has weird restrictions on setjmp locations
  11.  * 
  12.  * Revision 3.0.1.9  90/10/15  15:32:39  lwall
  13.  * patch29: non-existent array values no longer cause core dumps
  14.  * patch29: scripts now run at almost full speed under the debugger
  15.  * patch29: @ENV = () now works
  16.  * patch29: added caller
  17.  * 
  18.  * Revision 3.0.1.8  90/08/09  02:28:49  lwall
  19.  * patch19: did preliminary work toward debugging packages and evals
  20.  * patch19: conditionals now always supply a scalar context to expression
  21.  * patch19: switch optimizer was confused by negative fractional values
  22.  * 
  23.  * Revision 3.0.1.7  90/03/27  15:32:37  lwall
  24.  * patch16: non-terminal blocks should never have arrays requested of them
  25.  * 
  26.  * Revision 3.0.1.6  90/03/12  16:21:09  lwall
  27.  * patch13: fixed some backwards VOLATILE declarations
  28.  * patch13: while (s/x//) {} still caused some anomolies
  29.  * patch13: greater-than test of numeric switch structures did less-than action
  30.  * 
  31.  * Revision 3.0.1.5  90/02/28  16:38:31  lwall
  32.  * patch9: volatilized some more variables for super-optimizing compilers
  33.  * patch9: nested foreach loops didn't reset inner loop on next to outer loop
  34.  * patch9: returned values were read from obsolete stack
  35.  * patch9: added sanity check on longjmp() return value
  36.  * patch9: substitutions that almost always succeed can corrupt label stack
  37.  * patch9: subs which return by both mechanisms can clobber local return data
  38.  * 
  39.  * Revision 3.0.1.4  89/12/21  19:17:41  lwall
  40.  * patch7: arranged for certain registers to be restored after longjmp()
  41.  * patch7: made nested or recursive foreach work right
  42.  * 
  43.  * Revision 3.0.1.3  89/11/17  15:04:36  lwall
  44.  * patch5: nested foreach on same array didn't work
  45.  * 
  46.  * Revision 3.0.1.2  89/11/11  04:08:56  lwall
  47.  * patch2: non-BSD machines required two ^D's for <>
  48.  * patch2: grow_dlevel() not inside #ifdef DEBUGGING
  49.  * 
  50.  * Revision 3.0.1.1  89/10/26  23:04:21  lwall
  51.  * patch1: heuristically disabled optimization could cause core dump
  52.  * 
  53.  * Revision 3.0  89/10/18  15:09:02  lwall
  54.  * 3.0 baseline
  55.  * 
  56.  */
  57.  
  58. #include "EXTERN.h"
  59. #include "perl.h"
  60.  
  61. #ifdef I_VARARGS
  62. #  include <varargs.h>
  63. #endif
  64.  
  65. #ifdef I_STDARG
  66. #  include <stdarg.h>
  67. #endif
  68.  
  69. static STR str_chop_val;
  70.  
  71. /* do longjmps() clobber register variables? */
  72.  
  73. #if defined(cray) || defined(__STDC__)
  74. #define JMPCLOBBER
  75. #endif
  76.  
  77. /* This is the main command loop.  We try to spend as much time in this loop
  78.  * as possible, so lots of optimizations do their activities in here.  This
  79.  * means things get a little sloppy.
  80.  */
  81.  
  82. int
  83. cmd_exec(cmdparm,gimme,sp)
  84. CMD *VOLATILE cmdparm;
  85. VOLATILE int gimme;
  86. VOLATILE int sp;
  87. {
  88.     register CMD *cmd = cmdparm;
  89.     SPAT *VOLATILE oldspat;
  90.     VOLATILE int firstsave = savestack->ary_fill;
  91.     VOLATILE int oldsave;
  92.     VOLATILE int aryoptsave;
  93. #ifdef DEBUGGING
  94.     VOLATILE int olddlevel;
  95.     VOLATILE int entdlevel;
  96. #endif
  97.     register STR *retstr = &str_undef;
  98.     register char *tmps;
  99.     register int cmdflags;
  100.     register int match;
  101.     register char *go_to = goto_targ;
  102.     register int newsp = -2;
  103.     register STR **st = stack->ary_array;
  104.     FILE *VOLATILE fp;
  105.     ARRAY *VOLATILE ar;
  106.  
  107.     lastsize = 0;
  108. #ifdef DEBUGGING
  109.     entdlevel = dlevel;
  110. #endif
  111. tail_recursion_entry:
  112. #ifdef DEBUGGING
  113.     dlevel = entdlevel;
  114. #endif
  115. #ifdef TAINT
  116.     tainted = 0;    /* Each statement is presumed innocent */
  117. #endif
  118.     if (cmd == Nullcmd) {
  119.     if (gimme == G_ARRAY && newsp > -2)
  120.         return newsp;
  121.     else {
  122.         st[++sp] = retstr;
  123.         return sp;
  124.     }
  125.     }
  126.     cmdflags = cmd->c_flags;    /* hopefully load register */
  127.     if (go_to) {
  128.     if (cmd->c_label && strEQ(go_to,cmd->c_label))
  129.         goto_targ = go_to = Nullch;        /* here at last */
  130.     else {
  131.         switch (cmd->c_type) {
  132.         case C_IF:
  133.         oldspat = curspat;
  134.         oldsave = savestack->ary_fill;
  135. #ifdef DEBUGGING
  136.         olddlevel = dlevel;
  137. #endif
  138.         retstr = &str_yes;
  139.         newsp = -2;
  140.         if (cmd->ucmd.ccmd.cc_true) {
  141. #ifdef DEBUGGING
  142.             if (debug) {
  143.             debname[dlevel] = 't';
  144.             debdelim[dlevel] = '_';
  145.             if (++dlevel >= dlmax)
  146.                 grow_dlevel();
  147.             }
  148. #endif
  149.             newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
  150.             st = stack->ary_array;    /* possibly reallocated */
  151.             retstr = st[newsp];
  152.         }
  153.         if (!goto_targ)
  154.             go_to = Nullch;
  155.         curspat = oldspat;
  156.         if (savestack->ary_fill > oldsave)
  157.             restorelist(oldsave);
  158. #ifdef DEBUGGING
  159.         dlevel = olddlevel;
  160. #endif
  161.         cmd = cmd->ucmd.ccmd.cc_alt;
  162.         goto tail_recursion_entry;
  163.         case C_ELSE:
  164.         oldspat = curspat;
  165.         oldsave = savestack->ary_fill;
  166. #ifdef DEBUGGING
  167.         olddlevel = dlevel;
  168. #endif
  169.         retstr = &str_undef;
  170.         newsp = -2;
  171.         if (cmd->ucmd.ccmd.cc_true) {
  172. #ifdef DEBUGGING
  173.             if (debug) {
  174.             debname[dlevel] = 'e';
  175.             debdelim[dlevel] = '_';
  176.             if (++dlevel >= dlmax)
  177.                 grow_dlevel();
  178.             }
  179. #endif
  180.             newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
  181.             st = stack->ary_array;    /* possibly reallocated */
  182.             retstr = st[newsp];
  183.         }
  184.         if (!goto_targ)
  185.             go_to = Nullch;
  186.         curspat = oldspat;
  187.         if (savestack->ary_fill > oldsave)
  188.             restorelist(oldsave);
  189. #ifdef DEBUGGING
  190.         dlevel = olddlevel;
  191. #endif
  192.         break;
  193.         case C_BLOCK:
  194.         case C_WHILE:
  195.         if (!(cmdflags & CF_ONCE)) {
  196.             cmdflags |= CF_ONCE;
  197.             if (++loop_ptr >= loop_max) {
  198.             loop_max += 128;
  199.             Renew(loop_stack, loop_max, struct loop);
  200.             }
  201.             loop_stack[loop_ptr].loop_label = cmd->c_label;
  202.             loop_stack[loop_ptr].loop_sp = sp;
  203. #ifdef DEBUGGING
  204.             if (debug & 4) {
  205.             deb("(Pushing label #%d %s)\n",
  206.               loop_ptr, cmd->c_label ? cmd->c_label : "");
  207.             }
  208. #endif
  209.         }
  210. #ifdef JMPCLOBBER
  211.         cmdparm = cmd;
  212. #endif
  213.         match = setjmp(loop_stack[loop_ptr].loop_env);
  214.         if (match) {
  215.             st = stack->ary_array;    /* possibly reallocated */
  216. #ifdef JMPCLOBBER
  217.             cmd = cmdparm;
  218.             cmdflags = cmd->c_flags|CF_ONCE;
  219. #endif
  220.             if (savestack->ary_fill > oldsave)
  221.             restorelist(oldsave);
  222.             switch (match) {
  223.             default:
  224.             fatal("longjmp returned bad value (%d)",match);
  225.             case O_LAST:    /* not done unless go_to found */
  226.             go_to = Nullch;
  227.             if (lastretstr) {
  228.                 retstr = lastretstr;
  229.                 newsp = -2;
  230.             }
  231.             else {
  232.                 newsp = sp + lastsize;
  233.                 retstr = st[newsp];
  234.             }
  235. #ifdef DEBUGGING
  236.             olddlevel = dlevel;
  237. #endif
  238.             curspat = oldspat;
  239.             goto next_cmd;
  240.             case O_NEXT:    /* not done unless go_to found */
  241.             go_to = Nullch;
  242. #ifdef JMPCLOBBER
  243.             newsp = -2;
  244.             retstr = &str_undef;
  245. #endif
  246.             goto next_iter;
  247.             case O_REDO:    /* not done unless go_to found */
  248.             go_to = Nullch;
  249. #ifdef JMPCLOBBER
  250.             newsp = -2;
  251.             retstr = &str_undef;
  252. #endif
  253.             goto doit;
  254.             }
  255.         }
  256.         oldspat = curspat;
  257.         oldsave = savestack->ary_fill;
  258. #ifdef DEBUGGING
  259.         olddlevel = dlevel;
  260. #endif
  261.         if (cmd->ucmd.ccmd.cc_true) {
  262. #ifdef DEBUGGING
  263.             if (debug) {
  264.             debname[dlevel] = 't';
  265.             debdelim[dlevel] = '_';
  266.             if (++dlevel >= dlmax)
  267.                 grow_dlevel();
  268.             }
  269. #endif
  270.             newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
  271.             st = stack->ary_array;    /* possibly reallocated */
  272.             retstr = st[newsp];
  273.         }
  274.         if (!goto_targ) {
  275.             go_to = Nullch;
  276.             goto next_iter;
  277.         }
  278. #ifdef DEBUGGING
  279.         dlevel = olddlevel;
  280. #endif
  281.         if (cmd->ucmd.ccmd.cc_alt) {
  282. #ifdef DEBUGGING
  283.             if (debug) {
  284.             debname[dlevel] = 'a';
  285.             debdelim[dlevel] = '_';
  286.             if (++dlevel >= dlmax)
  287.                 grow_dlevel();
  288.             }
  289. #endif
  290.             newsp = cmd_exec(cmd->ucmd.ccmd.cc_alt,gimme && (cmdflags & CF_TERM),sp);
  291.             st = stack->ary_array;    /* possibly reallocated */
  292.             retstr = st[newsp];
  293.         }
  294.         if (goto_targ)
  295.             break;
  296.         go_to = Nullch;
  297.         goto finish_while;
  298.         }
  299.         cmd = cmd->c_next;
  300.         if (cmd && cmd->c_head == cmd)
  301.                     /* reached end of while loop */
  302.         return sp;        /* targ isn't in this block */
  303.         if (cmdflags & CF_ONCE) {
  304. #ifdef DEBUGGING
  305.         if (debug & 4) {
  306.             tmps = loop_stack[loop_ptr].loop_label;
  307.             deb("(Popping label #%d %s)\n",loop_ptr,
  308.             tmps ? tmps : "" );
  309.         }
  310. #endif
  311.         loop_ptr--;
  312.         }
  313.         goto tail_recursion_entry;
  314.     }
  315.     }
  316.  
  317. until_loop:
  318.  
  319.     /* Set line number so run-time errors can be located */
  320.  
  321.     curcmd = cmd;
  322.  
  323. #ifdef DEBUGGING
  324.     if (debug) {
  325.     if (debug & 2) {
  326.         deb("%s    (%lx)    r%lx    t%lx    a%lx    n%lx    cs%lx\n",
  327.         cmdname[cmd->c_type],cmd,cmd->c_expr,
  328.         cmd->ucmd.ccmd.cc_true,cmd->ucmd.ccmd.cc_alt,cmd->c_next,
  329.         curspat);
  330.     }
  331.     debname[dlevel] = cmdname[cmd->c_type][0];
  332.     debdelim[dlevel] = '!';
  333.     if (++dlevel >= dlmax)
  334.         grow_dlevel();
  335.     }
  336. #endif
  337.  
  338.     /* Here is some common optimization */
  339.  
  340.     if (cmdflags & CF_COND) {
  341.     switch (cmdflags & CF_OPTIMIZE) {
  342.  
  343.     case CFT_FALSE:
  344.         retstr = cmd->c_short;
  345.         newsp = -2;
  346.         match = FALSE;
  347.         if (cmdflags & CF_NESURE)
  348.         goto maybe;
  349.         break;
  350.     case CFT_TRUE:
  351.         retstr = cmd->c_short;
  352.         newsp = -2;
  353.         match = TRUE;
  354.         if (cmdflags & CF_EQSURE)
  355.         goto flipmaybe;
  356.         break;
  357.  
  358.     case CFT_REG:
  359.         retstr = STAB_STR(cmd->c_stab);
  360.         newsp = -2;
  361.         match = str_true(retstr);    /* => retstr = retstr, c2 should fix */
  362.         if (cmdflags & (match ? CF_EQSURE : CF_NESURE))
  363.         goto flipmaybe;
  364.         break;
  365.  
  366.     case CFT_ANCHOR:    /* /^pat/ optimization */
  367.         if (multiline) {
  368.         if (*cmd->c_short->str_ptr && !(cmdflags & CF_EQSURE))
  369.             goto scanner;    /* just unanchor it */
  370.         else
  371.             break;        /* must evaluate */
  372.         }
  373.         /* FALL THROUGH */
  374.     case CFT_STROP:        /* string op optimization */
  375.         retstr = STAB_STR(cmd->c_stab);
  376.         newsp = -2;
  377. #ifndef I286
  378.         if (*cmd->c_short->str_ptr == *str_get(retstr) &&
  379.             bcmp(cmd->c_short->str_ptr, str_get(retstr),
  380.               cmd->c_slen) == 0 ) {
  381.         if (cmdflags & CF_EQSURE) {
  382.             if (sawampersand && (cmdflags & CF_OPTIMIZE) != CFT_STROP) {
  383.             curspat = Nullspat;
  384.             if (leftstab)
  385.                 str_nset(stab_val(leftstab),"",0);
  386.             if (amperstab)
  387.                 str_sset(stab_val(amperstab),cmd->c_short);
  388.             if (rightstab)
  389.                 str_nset(stab_val(rightstab),
  390.                   retstr->str_ptr + cmd->c_slen,
  391.                   retstr->str_cur - cmd->c_slen);
  392.             }
  393.             match = !(cmdflags & CF_FIRSTNEG);
  394.             retstr = &str_yes;
  395.             goto flipmaybe;
  396.         }
  397.         }
  398.         else if (cmdflags & CF_NESURE) {
  399.         match = cmdflags & CF_FIRSTNEG;
  400.         retstr = &str_no;
  401.         goto flipmaybe;
  402.         }
  403. #else
  404.         {
  405.         char *zap1, *zap2, zap1c, zap2c;
  406.         int  zaplen;
  407.  
  408.         zap1 = cmd->c_short->str_ptr;
  409.         zap2 = str_get(retstr);
  410.         zap1c = *zap1;
  411.         zap2c = *zap2;
  412.         zaplen = cmd->c_slen;
  413.         if ((zap1c == zap2c) && (bcmp(zap1, zap2, zaplen) == 0)) {
  414.             if (cmdflags & CF_EQSURE) {
  415.             if (sawampersand &&
  416.               (cmdflags & CF_OPTIMIZE) != CFT_STROP) {
  417.                 curspat = Nullspat;
  418.                 if (leftstab)
  419.                 str_nset(stab_val(leftstab),"",0);
  420.                 if (amperstab)
  421.                 str_sset(stab_val(amperstab),cmd->c_short);
  422.                 if (rightstab)
  423.                 str_nset(stab_val(rightstab),
  424.                      retstr->str_ptr + cmd->c_slen,
  425.                      retstr->str_cur - cmd->c_slen);
  426.             }
  427.              match = !(cmdflags & CF_FIRSTNEG);
  428.              retstr = &str_yes;
  429.              goto flipmaybe;
  430.             }
  431.         }
  432.         else if (cmdflags & CF_NESURE) {
  433.             match = cmdflags & CF_FIRSTNEG;
  434.             retstr = &str_no;
  435.             goto flipmaybe;
  436.         }
  437.         }
  438. #endif
  439.         break;            /* must evaluate */
  440.  
  441.     case CFT_SCAN:            /* non-anchored search */
  442.       scanner:
  443.         retstr = STAB_STR(cmd->c_stab);
  444.         newsp = -2;
  445.         if (retstr->str_pok & SP_STUDIED)
  446.         if (screamfirst[cmd->c_short->str_rare] >= 0)
  447.             tmps = screaminstr(retstr, cmd->c_short);
  448.         else
  449.             tmps = Nullch;
  450.         else {
  451.         tmps = str_get(retstr);        /* make sure it's pok */
  452. #ifndef lint
  453.         tmps = fbminstr((unsigned char*)tmps,
  454.             (unsigned char*)tmps + retstr->str_cur, cmd->c_short);
  455. #endif
  456.         }
  457.         if (tmps) {
  458.         if (cmdflags & CF_EQSURE) {
  459.             ++cmd->c_short->str_u.str_useful;
  460.             if (sawampersand) {
  461.             curspat = Nullspat;
  462.             if (leftstab)
  463.                 str_nset(stab_val(leftstab),retstr->str_ptr,
  464.                   tmps - retstr->str_ptr);
  465.             if (amperstab)
  466.                 str_sset(stab_val(amperstab),cmd->c_short);
  467.             if (rightstab)
  468.                 str_nset(stab_val(rightstab),
  469.                   tmps + cmd->c_short->str_cur,
  470.                   retstr->str_cur - (tmps - retstr->str_ptr) -
  471.                 cmd->c_short->str_cur);
  472.             }
  473.             match = !(cmdflags & CF_FIRSTNEG);
  474.             retstr = &str_yes;
  475.             goto flipmaybe;
  476.         }
  477.         else
  478.             hint = tmps;
  479.         }
  480.         else {
  481.         if (cmdflags & CF_NESURE) {
  482.             ++cmd->c_short->str_u.str_useful;
  483.             match = cmdflags & CF_FIRSTNEG;
  484.             retstr = &str_no;
  485.             goto flipmaybe;
  486.         }
  487.         }
  488.         if (--cmd->c_short->str_u.str_useful < 0) {
  489.         cmdflags &= ~CF_OPTIMIZE;
  490.         cmdflags |= CFT_EVAL;    /* never try this optimization again */
  491.         cmd->c_flags = (cmdflags & ~CF_ONCE);
  492.         }
  493.         break;            /* must evaluate */
  494.  
  495.     case CFT_NUMOP:        /* numeric op optimization */
  496.         retstr = STAB_STR(cmd->c_stab);
  497.         newsp = -2;
  498.         switch (cmd->c_slen) {
  499.         case O_EQ:
  500.         if (dowarn) {
  501.             if ((!retstr->str_nok && !looks_like_number(retstr)))
  502.             warn("Possible use of == on string value");
  503.         }
  504.         match = (str_gnum(retstr) == cmd->c_short->str_u.str_nval);
  505.         break;
  506.         case O_NE:
  507.         match = (str_gnum(retstr) != cmd->c_short->str_u.str_nval);
  508.         break;
  509.         case O_LT:
  510.         match = (str_gnum(retstr) <  cmd->c_short->str_u.str_nval);
  511.         break;
  512.         case O_LE:
  513.         match = (str_gnum(retstr) <= cmd->c_short->str_u.str_nval);
  514.         break;
  515.         case O_GT:
  516.         match = (str_gnum(retstr) >  cmd->c_short->str_u.str_nval);
  517.         break;
  518.         case O_GE:
  519.         match = (str_gnum(retstr) >= cmd->c_short->str_u.str_nval);
  520.         break;
  521.         }
  522.         if (match) {
  523.         if (cmdflags & CF_EQSURE) {
  524.             retstr = &str_yes;
  525.             goto flipmaybe;
  526.         }
  527.         }
  528.         else if (cmdflags & CF_NESURE) {
  529.         retstr = &str_no;
  530.         goto flipmaybe;
  531.         }
  532.         break;            /* must evaluate */
  533.  
  534.     case CFT_INDGETS:        /* while (<$foo>) */
  535.         last_in_stab = stabent(str_get(STAB_STR(cmd->c_stab)),TRUE);
  536.         if (!stab_io(last_in_stab))
  537.         stab_io(last_in_stab) = stio_new();
  538.         goto dogets;
  539.     case CFT_GETS:            /* really a while (<file>) */
  540.         last_in_stab = cmd->c_stab;
  541.       dogets:
  542.         fp = stab_io(last_in_stab)->ifp;
  543.         retstr = stab_val(defstab);
  544.         newsp = -2;
  545.       keepgoing:
  546.         if (fp && str_gets(retstr, fp, 0)) {
  547.         if (*retstr->str_ptr == '0' && retstr->str_cur == 1)
  548.             match = FALSE;
  549.         else
  550.             match = TRUE;
  551.         stab_io(last_in_stab)->lines++;
  552.         }
  553.         else if (stab_io(last_in_stab)->flags & IOF_ARGV) {
  554.         if (!fp)
  555.             goto doeval;    /* first time through */
  556.         fp = nextargv(last_in_stab);
  557.         if (fp)
  558.             goto keepgoing;
  559.         (void)do_close(last_in_stab,FALSE);
  560.         stab_io(last_in_stab)->flags |= IOF_START;
  561.         retstr = &str_undef;
  562.         match = FALSE;
  563.         }
  564.         else {
  565.         retstr = &str_undef;
  566.         match = FALSE;
  567.         }
  568.         goto flipmaybe;
  569.     case CFT_EVAL:
  570.         break;
  571.     case CFT_UNFLIP:
  572.         while (tmps_max > tmps_base)    /* clean up after last eval */
  573.         str_free(tmps_list[tmps_max--]);
  574.         newsp = eval(cmd->c_expr,gimme && (cmdflags & CF_TERM),sp);
  575.         st = stack->ary_array;    /* possibly reallocated */
  576.         retstr = st[newsp];
  577.         match = str_true(retstr);
  578.         if (cmd->c_expr->arg_type == O_FLIP)    /* undid itself? */
  579.         cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd);
  580.         goto maybe;
  581.     case CFT_CHOP:
  582.         retstr = stab_val(cmd->c_stab);
  583.         newsp = -2;
  584.         match = (retstr->str_cur != 0);
  585.         tmps = str_get(retstr);
  586.         tmps += retstr->str_cur - match;
  587.         str_nset(&str_chop_val,tmps,match);
  588.         *tmps = '\0';
  589.         retstr->str_nok = 0;
  590.         retstr->str_cur = tmps - retstr->str_ptr;
  591.         retstr = &str_chop_val;
  592.         goto flipmaybe;
  593.     case CFT_ARRAY:
  594.         match = (int)cmd->c_short->str_u.str_useful; /* just to get register */
  595.  
  596.         if (match < 0) {        /* first time through here? */
  597.         ar = stab_array(cmd->c_expr[1].arg_ptr.arg_stab);
  598.         aryoptsave = savestack->ary_fill;
  599.         savesptr(&stab_val(cmd->c_stab));
  600.         savelong(&cmd->c_short->str_u.str_useful);
  601.         }
  602.         else {
  603.         ar = stab_xarray(cmd->c_expr[1].arg_ptr.arg_stab);
  604.         if (cmd->c_type != C_WHILE && savestack->ary_fill > firstsave)
  605.             restorelist(firstsave);
  606.         }
  607.  
  608.         if (match >= ar->ary_fill) {    /* we're in LAST, probably */
  609.         retstr = &str_undef;
  610.         cmd->c_short->str_u.str_useful = -1;    /* actually redundant */
  611.         match = FALSE;
  612.         }
  613.         else {
  614.         match++;
  615.         if ((retstr = ar->ary_array[match]) == Nullstr)
  616.             retstr = afetch(ar,match,TRUE);
  617.         stab_val(cmd->c_stab) = retstr;
  618.         cmd->c_short->str_u.str_useful = (long)match;
  619.         match = TRUE;
  620.         }
  621.         newsp = -2;
  622.         goto maybe;
  623.     case CFT_D1:
  624.         break;
  625.     case CFT_D0:
  626.         if (DBsingle->str_u.str_nval != 0)
  627.         break;
  628.         if (DBsignal->str_u.str_nval != 0)
  629.         break;
  630.         if (DBtrace->str_u.str_nval != 0)
  631.         break;
  632.         goto next_cmd;
  633.     }
  634.  
  635.     /* we have tried to make this normal case as abnormal as possible */
  636.  
  637.     doeval:
  638.     if (gimme == G_ARRAY) {
  639.         lastretstr = Nullstr;
  640.         lastspbase = sp;
  641.         lastsize = newsp - sp;
  642.     }
  643.     else
  644.         lastretstr = retstr;
  645.     while (tmps_max > tmps_base)    /* clean up after last eval */
  646.         str_free(tmps_list[tmps_max--]);
  647.     newsp = eval(cmd->c_expr,
  648.       gimme && (cmdflags & CF_TERM) && cmd->c_type == C_EXPR &&
  649.         !cmd->ucmd.acmd.ac_expr,
  650.       sp);
  651.     st = stack->ary_array;    /* possibly reallocated */
  652.     retstr = st[newsp];
  653.     if (newsp > sp && retstr)
  654.         match = str_true(retstr);
  655.     else
  656.         match = FALSE;
  657.     goto maybe;
  658.  
  659.     /* if flipflop was true, flop it */
  660.  
  661.     flipmaybe:
  662.     if (match && cmdflags & CF_FLIP) {
  663.         while (tmps_max > tmps_base)    /* clean up after last eval */
  664.         str_free(tmps_list[tmps_max--]);
  665.         if (cmd->c_expr->arg_type == O_FLOP) {    /* currently toggled? */
  666.         newsp = eval(cmd->c_expr,G_SCALAR,sp);/*let eval undo it*/
  667.         cmdflags = copyopt(cmd,cmd->c_expr[3].arg_ptr.arg_cmd);
  668.         }
  669.         else {
  670.         newsp = eval(cmd->c_expr,G_SCALAR,sp);/* let eval do it */
  671.         if (cmd->c_expr->arg_type == O_FLOP)    /* still toggled? */
  672.             cmdflags = copyopt(cmd,cmd->c_expr[4].arg_ptr.arg_cmd);
  673.         }
  674.     }
  675.     else if (cmdflags & CF_FLIP) {
  676.         if (cmd->c_expr->arg_type == O_FLOP) {    /* currently toggled? */
  677.         match = TRUE;                /* force on */
  678.         }
  679.     }
  680.  
  681.     /* at this point, match says whether our expression was true */
  682.  
  683.     maybe:
  684.     if (cmdflags & CF_INVERT)
  685.         match = !match;
  686.     if (!match)
  687.         goto next_cmd;
  688.     }
  689. #ifdef TAINT
  690.     tainted = 0;    /* modifier doesn't affect regular expression */
  691. #endif
  692.  
  693.     /* now to do the actual command, if any */
  694.  
  695.     switch (cmd->c_type) {
  696.     case C_NULL:
  697.     fatal("panic: cmd_exec");
  698.     case C_EXPR:            /* evaluated for side effects */
  699.     if (cmd->ucmd.acmd.ac_expr) {    /* more to do? */
  700.         if (gimme == G_ARRAY) {
  701.         lastretstr = Nullstr;
  702.         lastspbase = sp;
  703.         lastsize = newsp - sp;
  704.         }
  705.         else
  706.         lastretstr = retstr;
  707.         while (tmps_max > tmps_base)    /* clean up after last eval */
  708.         str_free(tmps_list[tmps_max--]);
  709.         newsp = eval(cmd->ucmd.acmd.ac_expr,gimme && (cmdflags&CF_TERM),sp);
  710.         st = stack->ary_array;    /* possibly reallocated */
  711.         retstr = st[newsp];
  712.     }
  713.     break;
  714.     case C_NSWITCH:
  715.     {
  716.         double value = str_gnum(STAB_STR(cmd->c_stab));
  717.  
  718.         match = (int)value;
  719.         if (value < 0.0) {
  720.         if (((double)match) > value)
  721.             --match;        /* was fractional--truncate other way */
  722.         }
  723.     }
  724.     goto doswitch;
  725.     case C_CSWITCH:
  726.     match = *(str_get(STAB_STR(cmd->c_stab))) & 255;
  727.       doswitch:
  728.     match -= cmd->ucmd.scmd.sc_offset;
  729.     if (match < 0)
  730.         match = 0;
  731.     else if (match > cmd->ucmd.scmd.sc_max)
  732.         match = cmd->ucmd.scmd.sc_max;
  733.     cmd = cmd->ucmd.scmd.sc_next[match];
  734.     goto tail_recursion_entry;
  735.     case C_NEXT:
  736.     cmd = cmd->ucmd.ccmd.cc_alt;
  737.     goto tail_recursion_entry;
  738.     case C_ELSIF:
  739.     fatal("panic: ELSIF");
  740.     case C_IF:
  741.     oldspat = curspat;
  742.     oldsave = savestack->ary_fill;
  743. #ifdef DEBUGGING
  744.     olddlevel = dlevel;
  745. #endif
  746.     retstr = &str_yes;
  747.     newsp = -2;
  748.     if (cmd->ucmd.ccmd.cc_true) {
  749. #ifdef DEBUGGING
  750.         if (debug) {
  751.         debname[dlevel] = 't';
  752.         debdelim[dlevel] = '_';
  753.         if (++dlevel >= dlmax)
  754.             grow_dlevel();
  755.         }
  756. #endif
  757.         newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
  758.         st = stack->ary_array;    /* possibly reallocated */
  759.         retstr = st[newsp];
  760.     }
  761.     curspat = oldspat;
  762.     if (savestack->ary_fill > oldsave)
  763.         restorelist(oldsave);
  764. #ifdef DEBUGGING
  765.     dlevel = olddlevel;
  766. #endif
  767.     cmd = cmd->ucmd.ccmd.cc_alt;
  768.     goto tail_recursion_entry;
  769.     case C_ELSE:
  770.     oldspat = curspat;
  771.     oldsave = savestack->ary_fill;
  772. #ifdef DEBUGGING
  773.     olddlevel = dlevel;
  774. #endif
  775.     retstr = &str_undef;
  776.     newsp = -2;
  777.     if (cmd->ucmd.ccmd.cc_true) {
  778. #ifdef DEBUGGING
  779.         if (debug) {
  780.         debname[dlevel] = 'e';
  781.         debdelim[dlevel] = '_';
  782.         if (++dlevel >= dlmax)
  783.             grow_dlevel();
  784.         }
  785. #endif
  786.         newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
  787.         st = stack->ary_array;    /* possibly reallocated */
  788.         retstr = st[newsp];
  789.     }
  790.     curspat = oldspat;
  791.     if (savestack->ary_fill > oldsave)
  792.         restorelist(oldsave);
  793. #ifdef DEBUGGING
  794.     dlevel = olddlevel;
  795. #endif
  796.     break;
  797.     case C_BLOCK:
  798.     case C_WHILE:
  799.     if (!(cmdflags & CF_ONCE)) {    /* first time through here? */
  800.         cmdflags |= CF_ONCE;
  801.         if (++loop_ptr >= loop_max) {
  802.         loop_max += 128;
  803.         Renew(loop_stack, loop_max, struct loop);
  804.         }
  805.         loop_stack[loop_ptr].loop_label = cmd->c_label;
  806.         loop_stack[loop_ptr].loop_sp = sp;
  807. #ifdef DEBUGGING
  808.         if (debug & 4) {
  809.         deb("(Pushing label #%d %s)\n",
  810.           loop_ptr, cmd->c_label ? cmd->c_label : "");
  811.         }
  812. #endif
  813.     }
  814. #ifdef JMPCLOBBER
  815.     cmdparm = cmd;
  816. #endif
  817.     match = setjmp(loop_stack[loop_ptr].loop_env);
  818.     if (match) {
  819.         st = stack->ary_array;    /* possibly reallocated */
  820. #ifdef JMPCLOBBER
  821.         cmd = cmdparm;
  822.         cmdflags = cmd->c_flags|CF_ONCE;
  823.         go_to = goto_targ;
  824. #endif
  825.         if (savestack->ary_fill > oldsave)
  826.         restorelist(oldsave);
  827.         switch (match) {
  828.         default:
  829.         fatal("longjmp returned bad value (%d)",match);
  830.         case O_LAST:
  831.         if (lastretstr) {
  832.             retstr = lastretstr;
  833.             newsp = -2;
  834.         }
  835.         else {
  836.             newsp = sp + lastsize;
  837.             retstr = st[newsp];
  838.         }
  839.         curspat = oldspat;
  840.         goto next_cmd;
  841.         case O_NEXT:
  842. #ifdef JMPCLOBBER
  843.         newsp = -2;
  844.         retstr = &str_undef;
  845. #endif
  846.         goto next_iter;
  847.         case O_REDO:
  848. #ifdef DEBUGGING
  849.         dlevel = olddlevel;
  850. #endif
  851. #ifdef JMPCLOBBER
  852.         newsp = -2;
  853.         retstr = &str_undef;
  854. #endif
  855.         goto doit;
  856.         }
  857.     }
  858.     oldspat = curspat;
  859.     oldsave = savestack->ary_fill;
  860. #ifdef DEBUGGING
  861.     olddlevel = dlevel;
  862. #endif
  863.     doit:
  864.     if (cmd->ucmd.ccmd.cc_true) {
  865. #ifdef DEBUGGING
  866.         if (debug) {
  867.         debname[dlevel] = 't';
  868.         debdelim[dlevel] = '_';
  869.         if (++dlevel >= dlmax)
  870.             grow_dlevel();
  871.         }
  872. #endif
  873.         newsp = cmd_exec(cmd->ucmd.ccmd.cc_true,gimme && (cmdflags & CF_TERM),sp);
  874.         st = stack->ary_array;    /* possibly reallocated */
  875.         retstr = st[newsp];
  876.     }
  877.     /* actually, this spot is rarely reached anymore since the above
  878.      * cmd_exec() returns through longjmp().  Hooray for structure.
  879.      */
  880.       next_iter:
  881. #ifdef DEBUGGING
  882.     dlevel = olddlevel;
  883. #endif
  884.     if (cmd->ucmd.ccmd.cc_alt) {
  885. #ifdef DEBUGGING
  886.         if (debug) {
  887.         debname[dlevel] = 'a';
  888.         debdelim[dlevel] = '_';
  889.         if (++dlevel >= dlmax)
  890.             grow_dlevel();
  891.         }
  892. #endif
  893.         newsp = cmd_exec(cmd->ucmd.ccmd.cc_alt,gimme && (cmdflags & CF_TERM),sp);
  894.         st = stack->ary_array;    /* possibly reallocated */
  895.         retstr = st[newsp];
  896.     }
  897.       finish_while:
  898.     curspat = oldspat;
  899.     if (savestack->ary_fill > oldsave) {
  900.         if (cmdflags & CF_TERM) {
  901.         for (match = sp + 1; match <= newsp; match++)
  902.             st[match] = str_static(st[match]);
  903.         retstr = st[newsp];
  904.         }
  905.         restorelist(oldsave);
  906.     }
  907. #ifdef DEBUGGING
  908.     dlevel = olddlevel - 1;
  909. #endif
  910.     if (cmd->c_type != C_BLOCK)
  911.         goto until_loop;    /* go back and evaluate conditional again */
  912.     }
  913.     if (cmdflags & CF_LOOP) {
  914.     cmdflags |= CF_COND;        /* now test the condition */
  915. #ifdef DEBUGGING
  916.     dlevel = entdlevel;
  917. #endif
  918.     goto until_loop;
  919.     }
  920.   next_cmd:
  921.     if (cmdflags & CF_ONCE) {
  922. #ifdef DEBUGGING
  923.     if (debug & 4) {
  924.         tmps = loop_stack[loop_ptr].loop_label;
  925.         deb("(Popping label #%d %s)\n",loop_ptr, tmps ? tmps : "");
  926.     }
  927. #endif
  928.     loop_ptr--;
  929.     if ((cmdflags & CF_OPTIMIZE) == CFT_ARRAY &&
  930.       savestack->ary_fill > aryoptsave)
  931.         restorelist(aryoptsave);
  932.     }
  933.     cmd = cmd->c_next;
  934.     goto tail_recursion_entry;
  935. }
  936.  
  937. #ifdef DEBUGGING
  938. #ifndef STDARG
  939. #ifndef VARARGS
  940. /*VARARGS1*/
  941. void
  942. deb(pat,a1,a2,a3,a4,a5,a6,a7,a8)
  943. char *pat;
  944. {
  945.     register int i;
  946.  
  947.     fprintf(stderr,"%-4ld",(long)curcmd->c_line);
  948.     for (i=0; i<dlevel; i++)
  949.     fprintf(stderr,"%c%c ",debname[i],debdelim[i]);
  950.     fprintf(stderr,pat,a1,a2,a3,a4,a5,a6,a7,a8);
  951. }
  952. #else /* VARARGS */
  953. /*VARARGS1*/
  954. void
  955. deb(va_alist)
  956. va_dcl
  957. {
  958.     va_list args;
  959.     char *pat;
  960.     register int i;
  961.  
  962.     va_start(args);
  963.     fprintf(stderr,"%-4ld",(long)curcmd->c_line);
  964.     for (i=0; i<dlevel; i++)
  965.     fprintf(stderr,"%c%c ",debname[i],debdelim[i]);
  966.  
  967.     pat = va_arg(args, char *);
  968.     (void) vfprintf(stderr,pat,args);
  969.     va_end( args );
  970. }
  971. #endif /* VARARGS */
  972. #else /* STDARG */
  973. /*VARARGS1*/
  974. void
  975. deb(char *pat, ...)
  976. {
  977.     va_list ap;
  978.     register int i;
  979.  
  980.     va_start(ap,pat);
  981.     fprintf(stderr,"%-4ld",(long)curcmd->c_line);
  982.     for (i=0; i<dlevel; i++)
  983.     fprintf(stderr,"%c%c ",debname[i],debdelim[i]);
  984.  
  985.     (void) vfprintf(stderr,pat,ap);
  986.     va_end(ap);
  987. }
  988. #endif /* STDARG */
  989. #endif
  990.  
  991. int
  992. copyopt(cmd,which)
  993. register CMD *cmd;
  994. register CMD *which;
  995. {
  996.     cmd->c_flags &= CF_ONCE|CF_COND|CF_LOOP;
  997.     cmd->c_flags |= which->c_flags;
  998.     cmd->c_short = which->c_short;
  999.     cmd->c_slen = which->c_slen;
  1000.     cmd->c_stab = which->c_stab;
  1001.     return cmd->c_flags;
  1002. }
  1003.  
  1004. ARRAY *
  1005. saveary(stab)
  1006. STAB *stab;
  1007. {
  1008.     register STR *str;
  1009.  
  1010.     str = Str_new(10,0);
  1011.     str->str_state = SS_SARY;
  1012.     str->str_u.str_stab = stab;
  1013.     if (str->str_ptr) {
  1014.     Safefree(str->str_ptr);
  1015.     str->str_len = 0;
  1016.     }
  1017.     str->str_ptr = (char*)stab_array(stab);
  1018.     (void)apush(savestack,str); /* save array ptr */
  1019.     stab_xarray(stab) = Null(ARRAY*);
  1020.     return stab_xarray(aadd(stab));
  1021. }
  1022.  
  1023. HASH *
  1024. savehash(stab)
  1025. STAB *stab;
  1026. {
  1027.     register STR *str;
  1028.  
  1029.     str = Str_new(11,0);
  1030.     str->str_state = SS_SHASH;
  1031.     str->str_u.str_stab = stab;
  1032.     if (str->str_ptr) {
  1033.     Safefree(str->str_ptr);
  1034.     str->str_len = 0;
  1035.     }
  1036.     str->str_ptr = (char*)stab_hash(stab);
  1037.     (void)apush(savestack,str); /* save hash ptr */
  1038.     stab_xhash(stab) = Null(HASH*);
  1039.     return stab_xhash(hadd(stab));
  1040. }
  1041.  
  1042. void
  1043. saveitem(item)
  1044. register STR *item;
  1045. {
  1046.     register STR *str;
  1047.  
  1048.     (void)apush(savestack,item);        /* remember the pointer */
  1049.     str = Str_new(12,0);
  1050.     str_sset(str,item);
  1051.     (void)apush(savestack,str);            /* remember the value */
  1052. }
  1053.  
  1054. void
  1055. saveint(intp)
  1056. int *intp;
  1057. {
  1058.     register STR *str;
  1059.  
  1060.     str = Str_new(13,0);
  1061.     str->str_state = SS_SINT;
  1062.     str->str_u.str_useful = (long)*intp;    /* remember value */
  1063.     if (str->str_ptr) {
  1064.     Safefree(str->str_ptr);
  1065.     str->str_len = 0;
  1066.     }
  1067.     str->str_ptr = (char*)intp;        /* remember pointer */
  1068.     (void)apush(savestack,str);
  1069. }
  1070.  
  1071. void
  1072. savelong(longp)
  1073. long *longp;
  1074. {
  1075.     register STR *str;
  1076.  
  1077.     str = Str_new(14,0);
  1078.     str->str_state = SS_SLONG;
  1079.     str->str_u.str_useful = *longp;        /* remember value */
  1080.     if (str->str_ptr) {
  1081.     Safefree(str->str_ptr);
  1082.     str->str_len = 0;
  1083.     }
  1084.     str->str_ptr = (char*)longp;        /* remember pointer */
  1085.     (void)apush(savestack,str);
  1086. }
  1087.  
  1088. void
  1089. savesptr(sptr)
  1090. STR **sptr;
  1091. {
  1092.     register STR *str;
  1093.  
  1094.     str = Str_new(15,0);
  1095.     str->str_state = SS_SSTRP;
  1096.     str->str_magic = *sptr;        /* remember value */
  1097.     if (str->str_ptr) {
  1098.     Safefree(str->str_ptr);
  1099.     str->str_len = 0;
  1100.     }
  1101.     str->str_ptr = (char*)sptr;        /* remember pointer */
  1102.     (void)apush(savestack,str);
  1103. }
  1104.  
  1105. void
  1106. savenostab(stab)
  1107. STAB *stab;
  1108. {
  1109.     register STR *str;
  1110.  
  1111.     str = Str_new(16,0);
  1112.     str->str_state = SS_SNSTAB;
  1113.     str->str_magic = (STR*)stab;    /* remember which stab to free */
  1114.     (void)apush(savestack,str);
  1115. }
  1116.  
  1117. void
  1118. savehptr(hptr)
  1119. HASH **hptr;
  1120. {
  1121.     register STR *str;
  1122.  
  1123.     str = Str_new(17,0);
  1124.     str->str_state = SS_SHPTR;
  1125.     str->str_u.str_hash = *hptr;    /* remember value */
  1126.     if (str->str_ptr) {
  1127.     Safefree(str->str_ptr);
  1128.     str->str_len = 0;
  1129.     }
  1130.     str->str_ptr = (char*)hptr;        /* remember pointer */
  1131.     (void)apush(savestack,str);
  1132. }
  1133.  
  1134. void
  1135. savelist(sarg,maxsarg)
  1136. register STR **sarg;
  1137. int maxsarg;
  1138. {
  1139.     register STR *str;
  1140.     register int i;
  1141.  
  1142.     for (i = 1; i <= maxsarg; i++) {
  1143.     (void)apush(savestack,sarg[i]);        /* remember the pointer */
  1144.     str = Str_new(18,0);
  1145.     str_sset(str,sarg[i]);
  1146.     (void)apush(savestack,str);            /* remember the value */
  1147.     sarg[i]->str_u.str_useful = -1;
  1148.     }
  1149. }
  1150.  
  1151. void
  1152. restorelist(base)
  1153. int base;
  1154. {
  1155.     register STR *str;
  1156.     register STR *value;
  1157.     register STAB *stab;
  1158.  
  1159.     if (base < -1)
  1160.     fatal("panic: corrupt saved stack index");
  1161.     while (savestack->ary_fill > base) {
  1162.     value = apop(savestack);
  1163.     switch (value->str_state) {
  1164.     case SS_NORM:                /* normal string */
  1165.     case SS_INCR:
  1166.         str = apop(savestack);
  1167.         str_replace(str,value);
  1168.         STABSET(str);
  1169.         break;
  1170.     case SS_SARY:                /* array reference */
  1171.         stab = value->str_u.str_stab;
  1172.         afree(stab_xarray(stab));
  1173.         stab_xarray(stab) = (ARRAY*)value->str_ptr;
  1174.         value->str_ptr = Nullch;
  1175.         str_free(value);
  1176.         break;
  1177.     case SS_SHASH:                /* hash reference */
  1178.         stab = value->str_u.str_stab;
  1179.         (void)hfree(stab_xhash(stab), FALSE);
  1180.         stab_xhash(stab) = (HASH*)value->str_ptr;
  1181.         value->str_ptr = Nullch;
  1182.         str_free(value);
  1183.         break;
  1184.     case SS_SINT:                /* int reference */
  1185.         *((int*)value->str_ptr) = (int)value->str_u.str_useful;
  1186.         value->str_ptr = Nullch;
  1187.         str_free(value);
  1188.         break;
  1189.     case SS_SLONG:                /* long reference */
  1190.         *((long*)value->str_ptr) = value->str_u.str_useful;
  1191.         value->str_ptr = Nullch;
  1192.         str_free(value);
  1193.         break;
  1194.     case SS_SSTRP:                /* STR* reference */
  1195.         *((STR**)value->str_ptr) = value->str_magic;
  1196.         value->str_magic = Nullstr;
  1197.         value->str_ptr = Nullch;
  1198.         str_free(value);
  1199.         break;
  1200.     case SS_SHPTR:                /* HASH* reference */
  1201.         *((HASH**)value->str_ptr) = value->str_u.str_hash;
  1202.         value->str_ptr = Nullch;
  1203.         str_free(value);
  1204.         break;
  1205.     case SS_SNSTAB:
  1206.         stab = (STAB*)value->str_magic;
  1207.         value->str_magic = Nullstr;
  1208.         (void)stab_clear(stab);
  1209.         str_free(value);
  1210.         break;
  1211.     case SS_SCSV:                /* callsave structure */
  1212.         {
  1213.         CSV *csv = (CSV*) value->str_ptr;
  1214.  
  1215.         curcmd = csv->curcmd;
  1216.         curcsv = csv->curcsv;
  1217.         csv->sub->depth = csv->depth;
  1218.         if (csv->hasargs) {        /* put back old @_ */
  1219.             afree(csv->argarray);
  1220.             stab_xarray(defstab) = csv->savearray;
  1221.         }
  1222.         str_free(value);
  1223.         }
  1224.         break;
  1225.     default:
  1226.         fatal("panic: restorelist inconsistency");
  1227.     }
  1228.     }
  1229. }
  1230.  
  1231. #ifdef DEBUGGING
  1232. void
  1233. grow_dlevel()
  1234. {
  1235.     dlmax += 128;
  1236.     Renew(debname, dlmax, char);
  1237.     Renew(debdelim, dlmax, char);
  1238. }
  1239. #endif
  1240.