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