2 * loop.c - loop execution
4 * This file is part of zsh, the Z shell.
6 * Copyright (c) 1992-1997 Paul Falstad
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
15 * In no event shall Paul Falstad or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Paul Falstad and the Zsh Development Group have been advised of
19 * the possibility of such damage.
21 * Paul Falstad and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose. The software
24 * provided hereunder is on an "as is" basis, and Paul Falstad and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
33 /* # of nested loops we are in */
38 /* # of continue levels */
41 mod_export
int contflag
;
43 /* # of break levels */
46 mod_export
int breaks
;
50 execfor(Estate state
, int do_exec
)
53 wordcode code
= state
->pc
[-1];
54 int iscond
= (WC_FOR_TYPE(code
) == WC_FOR_COND
), ctok
= 0, atok
= 0;
56 char *name
, *str
, *cond
= NULL
, *advance
= NULL
;
58 LinkList vars
= NULL
, args
= NULL
;
60 end
= state
->pc
+ WC_FOR_SKIP(code
);
63 str
= dupstring(ecgetstr(state
, EC_NODUP
, NULL
));
66 char *str2
= dupstring(str
);
69 fprintf(xtrerr
, "%s\n", str2
);
76 return lastval
= errflag
;
78 cond
= ecgetstr(state
, EC_NODUP
, &ctok
);
79 advance
= ecgetstr(state
, EC_NODUP
, &atok
);
81 vars
= ecgetlist(state
, *state
->pc
++, EC_NODUP
, NULL
);
83 if (WC_FOR_TYPE(code
) == WC_FOR_LIST
) {
86 if (!(args
= ecgetlist(state
, *state
->pc
++, EC_DUPTOK
, &htok
))) {
96 for (x
= pparams
; *x
; x
++)
97 addlinknode(args
, dupstring(*x
));
108 str
= dupstring(cond
);
118 fprintf(xtrerr
, "%s\n", str
);
121 val
= mathevali(str
);
136 for (node
= firstnode(vars
); node
; incnode(node
))
138 name
= (char *)getdata(node
);
139 if (!args
|| !(str
= (char *) ugetnode(args
)))
149 fprintf(xtrerr
, "%s=%s\n", name
, str
);
152 setsparam(name
, ztrdup(str
));
159 execlist(state
, 1, do_exec
&& args
&& empty(args
));
162 if (breaks
|| !contflag
)
168 if (iscond
&& !errflag
) {
170 str
= dupstring(advance
);
176 fprintf(xtrerr
, "%s\n", str
);
199 execselect(Estate state
, UNUSED(int do_exec
))
202 wordcode code
= state
->pc
[-1];
203 char *str
, *s
, *name
;
210 end
= state
->pc
+ WC_FOR_SKIP(code
);
211 name
= ecgetstr(state
, EC_NODUP
, NULL
);
213 if (WC_SELECT_TYPE(code
) == WC_SELECT_PPARAM
) {
216 args
= newlinklist();
217 for (x
= pparams
; *x
; x
++)
218 addlinknode(args
, dupstring(*x
));
222 if (!(args
= ecgetlist(state
, *state
->pc
++, EC_DUPTOK
, &htok
))) {
229 if (!args
|| empty(args
)) {
237 usezle
= interact
&& SHTTY
!= -1 && isset(USEZLE
);
238 inp
= fdopen(dup(usezle
? SHTTY
: 0), "r");
239 more
= selectlist(args
, 0);
243 if (empty(bufstack
)) {
248 str
= zleentry(ZLE_CMD_READ
, &prompt3
, NULL
,
254 str
= promptexpand(prompt3
, 0, NULL
, NULL
, NULL
);
258 str
= fgets(zalloc(256), 256, inp
);
261 str
= (char *)getlinknode(bufstack
);
262 if (!str
|| errflag
) {
265 fprintf(stderr
, "\n");
269 if ((s
= strchr(str
, '\n')))
273 more
= selectlist(args
, more
);
275 setsparam("REPLY", ztrdup(str
));
280 for (i
--, n
= firstnode(args
); n
&& i
; incnode(n
), i
--);
282 str
= (char *) getdata(n
);
286 setsparam(name
, ztrdup(str
));
288 execlist(state
, 1, 0);
292 if (breaks
|| !contflag
)
296 if (retflag
|| errflag
)
308 /* And this is used to print select lists. */
312 selectlist(LinkList l
, size_t start
)
314 size_t longest
= 1, fct
, fw
= 0, colsz
, t0
, t1
, ct
;
317 zleentry(ZLE_CMD_TRASH
);
318 arr
= hlinklist2array(l
, 0);
319 for (ap
= arr
; *ap
; ap
++)
320 if (strlen(*ap
) > longest
)
321 longest
= strlen(*ap
);
326 /* to compensate for added ')' */
327 fct
= (columns
- 1) / (longest
+ 3);
331 fw
= (columns
- 1) / fct
;
332 colsz
= (ct
+ fct
- 1) / fct
;
333 for (t1
= start
; t1
!= colsz
&& t1
- start
< lines
- 2; t1
++) {
336 size_t t2
= strlen(*ap
) + 2;
339 fprintf(stderr
, "%d) %s", t3
= ap
- arr
+ 1, *ap
);
342 for (; t2
< fw
; t2
++)
344 for (t0
= colsz
; t0
&& *ap
; t0
--, ap
++);
350 /* Below is a simple attempt at doing it the Korn Way..
355 fprintf(stderr,"%d) %s\n",t0,*ap);
361 return t1
< colsz
? t1
: 0;
366 execwhile(Estate state
, UNUSED(int do_exec
))
369 wordcode code
= state
->pc
[-1];
370 int olderrexit
, oldval
, isuntil
= (WC_WHILE_TYPE(code
) == WC_WHILE_UNTIL
);
372 end
= state
->pc
+ WC_WHILE_SKIP(code
);
373 olderrexit
= noerrexit
;
376 cmdpush(isuntil
? CS_UNTIL
: CS_WHILE
);
380 if (loop
[0] == WC_END
&& loop
[1] == WC_END
) {
382 /* This is an empty loop. Make sure the signal handler sets the
383 * flags and then just wait for someone hitting ^C. */
385 int old_simple_pline
= simple_pline
;
393 simple_pline
= old_simple_pline
;
398 execlist(state
, 1, 0);
399 noerrexit
= olderrexit
;
400 if (!((lastval
== 0) ^ isuntil
)) {
410 execlist(state
, 1, 0);
413 if (breaks
|| !contflag
)
435 execrepeat(Estate state
, UNUSED(int do_exec
))
438 wordcode code
= state
->pc
[-1];
442 end
= state
->pc
+ WC_REPEAT_SKIP(code
);
445 tmp
= ecgetstr(state
, EC_DUPTOK
, &htok
);
453 while (count
-- > 0) {
455 execlist(state
, 1, 0);
459 if (breaks
|| !contflag
)
479 execif(Estate state
, int do_exec
)
482 wordcode code
= state
->pc
[-1];
483 int olderrexit
, s
= 0, run
= 0;
485 olderrexit
= noerrexit
;
486 end
= state
->pc
+ WC_IF_SKIP(code
);
490 while (state
->pc
< end
) {
492 if (wc_code(code
) != WC_IF
||
493 (run
= (WC_IF_TYPE(code
) == WC_IF_ELSE
))) {
498 next
= state
->pc
+ WC_IF_SKIP(code
);
499 cmdpush(s
? CS_ELIF
: CS_IF
);
500 execlist(state
, 1, 0);
511 noerrexit
= olderrexit
;
514 cmdpush(run
== 2 ? CS_ELSE
: (s
? CS_ELIFTHEN
: CS_IFTHEN
));
515 execlist(state
, 1, do_exec
);
526 execcase(Estate state
, int do_exec
)
529 wordcode code
= state
->pc
[-1];
532 Patprog
*spprog
, pprog
;
534 end
= state
->pc
+ WC_CASE_SKIP(code
);
536 word
= ecgetstr(state
, EC_DUP
, NULL
);
542 while (state
->pc
< end
) {
544 if (wc_code(code
) != WC_CASE
)
551 spprog
= state
->prog
->pats
+ npat
;
553 next
= state
->pc
+ WC_CASE_SKIP(code
);
558 pat
= dupstring(opat
= ecrawstr(state
->prog
, state
->pc
, NULL
));
560 save
= (!(state
->prog
->flags
& EF_HEAP
) &&
561 !strcmp(pat
, opat
) && *spprog
!= dummy_patprog2
);
564 fprintf(xtrerr
, "case %s (", word
);
565 quote_tokenized_output(pat
, xtrerr
);
566 fprintf(xtrerr
, ")\n");
571 if (*spprog
!= dummy_patprog1
&& *spprog
!= dummy_patprog2
)
579 pat
= dupstring(opat
= ecrawstr(state
->prog
,
580 state
->pc
- 2, &htok
));
583 save
= (!(state
->prog
->flags
& EF_HEAP
) &&
584 !strcmp(pat
, opat
) && *spprog
!= dummy_patprog2
);
586 if (!(pprog
= patcompile(pat
, (save
? PAT_ZDUP
: PAT_STATIC
),
588 zerr("bad pattern: %s", pat
);
592 if (pprog
&& pattry(pprog
, word
)) {
593 execlist(state
, 1, ((WC_CASE_TYPE(code
) == WC_CASE_OR
) &&
595 while (!retflag
&& wc_code(code
) == WC_CASE
&&
596 WC_CASE_TYPE(code
) == WC_CASE_AND
) {
600 next
= state
->pc
+ WC_CASE_SKIP(code
) - 2;
601 execlist(state
, 1, ((WC_CASE_TYPE(code
) == WC_CASE_OR
) &&
604 if (WC_CASE_TYPE(code
) != WC_CASE_TESTAND
)
617 * Errflag from `try' block, may be reset in `always' block.
618 * Accessible from an integer parameter, so needs to be a zlong.
631 exectry(Estate state
, int do_exec
)
633 Wordcode end
, always
;
635 int save_retflag
, save_breaks
, save_contflag
;
636 zlong save_try_errflag
, save_try_tryflag
;
638 end
= state
->pc
+ WC_TRY_SKIP(state
->pc
[-1]);
639 always
= state
->pc
+ 1 + WC_TRY_SKIP(*state
->pc
);
644 /* The :try clause */
645 save_try_tryflag
= try_tryflag
;
648 execlist(state
, 1, do_exec
);
650 try_tryflag
= save_try_tryflag
;
652 /* Don't record errflag here, may be reset. */
660 /* The always clause. */
661 save_try_errflag
= try_errflag
;
662 try_errflag
= (zlong
)errflag
;
664 save_retflag
= retflag
;
666 save_breaks
= breaks
;
668 save_contflag
= contflag
;
672 execlist(state
, 1, do_exec
);
674 errflag
= try_errflag
? 1 : 0;
675 try_errflag
= save_try_errflag
;
677 retflag
= save_retflag
;
679 breaks
= save_breaks
;
681 contflag
= save_contflag
;