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