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