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