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