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