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