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