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