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