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