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