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