source: trunk/third/perl/cmd.c @ 9009

Revision 9009, 30.0 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9008, which included commits to RCS files with non-trunk default branches.
Line 
1/* $RCSfile: cmd.c,v $$Revision: 1.1.1.1 $$Date: 1996-10-02 06:39:57 $
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: not supported by cvs2svn $
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
41static STR strchop;
42
43void 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
56int
57cmd_exec(cmdparm,gimme,sp)
58CMD *VOLATILE cmdparm;
59VOLATILE int gimme;
60VOLATILE 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
85tail_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
297until_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*/
957void deb(pat,a1,a2,a3,a4,a5,a6,a7,a8)
958char *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*/
969void deb(va_alist)
970va_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
988int
989copyopt(cmd,which)
990register CMD *cmd;
991register 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
1001ARRAY *
1002saveary(stab)
1003STAB *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
1021HASH *
1022savehash(stab)
1023STAB *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
1041void
1042saveitem(item)
1043register 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
1053void
1054saveint(intp)
1055int *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
1070void
1071savelong(longp)
1072long *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
1087void
1088savesptr(sptr)
1089STR **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
1104void
1105savenostab(stab)
1106STAB *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
1116void
1117savehptr(hptr)
1118HASH **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
1133void
1134saveaptr(aptr)
1135ARRAY **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
1150void
1151savelist(sarg,maxsarg)
1152register STR **sarg;
1153int 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
1167void
1168restorelist(base)
1169int 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
1253void
1254grow_dlevel()
1255{
1256    dlmax += 128;
1257    Renew(debname, dlmax, char);
1258    Renew(debdelim, dlmax, char);
1259}
1260#endif
Note: See TracBrowser for help on using the repository browser.