26763: fix problem on failed cd -s to relative path
[zsh.git] / Src / loop.c
blob40dbe6f8f1b6d764e21d5ac02cf29bd8996d177f
1 /*
2 * loop.c - loop execution
4 * This file is part of zsh, the Z shell.
6 * Copyright (c) 1992-1997 Paul Falstad
7 * All rights reserved.
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.
30 #include "zsh.mdh"
31 #include "loop.pro"
33 /* # of nested loops we are in */
35 /**/
36 int loops;
38 /* # of continue levels */
40 /**/
41 mod_export int contflag;
43 /* # of break levels */
45 /**/
46 mod_export int breaks;
48 /**/
49 int
50 execfor(Estate state, int do_exec)
52 Wordcode end, loop;
53 wordcode code = state->pc[-1];
54 int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0;
55 int last = 0;
56 char *name, *str, *cond = NULL, *advance = NULL;
57 zlong val = 0;
58 LinkList vars = NULL, args = NULL;
60 end = state->pc + WC_FOR_SKIP(code);
62 if (iscond) {
63 str = dupstring(ecgetstr(state, EC_NODUP, NULL));
64 singsub(&str);
65 if (isset(XTRACE)) {
66 char *str2 = dupstring(str);
67 untokenize(str2);
68 printprompt4();
69 fprintf(xtrerr, "%s\n", str2);
70 fflush(xtrerr);
72 if (!errflag)
73 matheval(str);
74 if (errflag) {
75 state->pc = end;
76 return lastval = errflag;
78 cond = ecgetstr(state, EC_NODUP, &ctok);
79 advance = ecgetstr(state, EC_NODUP, &atok);
80 } else {
81 vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL);
83 if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
84 int htok = 0;
86 if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
87 state->pc = end;
88 return 0;
90 if (htok)
91 execsubst(args);
92 } else {
93 char **x;
95 args = newlinklist();
96 for (x = pparams; *x; x++)
97 addlinknode(args, dupstring(*x));
100 lastval = 0;
101 loops++;
102 pushheap();
103 cmdpush(CS_FOR);
104 loop = state->pc;
105 while (!last) {
106 if (iscond) {
107 if (ctok) {
108 str = dupstring(cond);
109 singsub(&str);
110 } else
111 str = cond;
112 if (!errflag) {
113 while (iblank(*str))
114 str++;
115 if (*str) {
116 if (isset(XTRACE)) {
117 printprompt4();
118 fprintf(xtrerr, "%s\n", str);
119 fflush(xtrerr);
121 val = mathevali(str);
122 } else
123 val = 1;
125 if (errflag) {
126 if (breaks)
127 breaks--;
128 lastval = 1;
129 break;
131 if (!val)
132 break;
133 } else {
134 LinkNode node;
135 int count = 0;
136 for (node = firstnode(vars); node; incnode(node))
138 name = (char *)getdata(node);
139 if (!args || !(str = (char *) ugetnode(args)))
141 if (count) {
142 str = "";
143 last = 1;
144 } else
145 break;
147 if (isset(XTRACE)) {
148 printprompt4();
149 fprintf(xtrerr, "%s=%s\n", name, str);
150 fflush(xtrerr);
152 setsparam(name, ztrdup(str));
153 count++;
155 if (!count)
156 break;
158 state->pc = loop;
159 execlist(state, 1, do_exec && args && empty(args));
160 if (breaks) {
161 breaks--;
162 if (breaks || !contflag)
163 break;
164 contflag = 0;
166 if (retflag)
167 break;
168 if (iscond && !errflag) {
169 if (atok) {
170 str = dupstring(advance);
171 singsub(&str);
172 } else
173 str = advance;
174 if (isset(XTRACE)) {
175 printprompt4();
176 fprintf(xtrerr, "%s\n", str);
177 fflush(xtrerr);
179 if (!errflag)
180 matheval(str);
182 if (errflag) {
183 if (breaks)
184 breaks--;
185 lastval = 1;
186 break;
188 freeheap();
190 popheap();
191 cmdpop();
192 loops--;
193 state->pc = end;
194 return lastval;
197 /**/
199 execselect(Estate state, UNUSED(int do_exec))
201 Wordcode end, loop;
202 wordcode code = state->pc[-1];
203 char *str, *s, *name;
204 LinkNode n;
205 int i, usezle;
206 FILE *inp;
207 size_t more;
208 LinkList args;
210 end = state->pc + WC_FOR_SKIP(code);
211 name = ecgetstr(state, EC_NODUP, NULL);
213 if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) {
214 char **x;
216 args = newlinklist();
217 for (x = pparams; *x; x++)
218 addlinknode(args, dupstring(*x));
219 } else {
220 int htok = 0;
222 if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
223 state->pc = end;
224 return 0;
226 if (htok)
227 execsubst(args);
229 if (!args || empty(args)) {
230 state->pc = end;
231 return 1;
233 loops++;
234 lastval = 0;
235 pushheap();
236 cmdpush(CS_SELECT);
237 usezle = interact && SHTTY != -1 && isset(USEZLE);
238 inp = fdopen(dup(usezle ? SHTTY : 0), "r");
239 more = selectlist(args, 0);
240 loop = state->pc;
241 for (;;) {
242 for (;;) {
243 if (empty(bufstack)) {
244 if (usezle) {
245 int oef = errflag;
247 isfirstln = 1;
248 str = zleentry(ZLE_CMD_READ, &prompt3, NULL,
249 0, ZLCON_SELECT);
250 if (errflag)
251 str = NULL;
252 errflag = oef;
253 } else {
254 str = promptexpand(prompt3, 0, NULL, NULL, NULL);
255 zputs(str, stderr);
256 free(str);
257 fflush(stderr);
258 str = fgets(zalloc(256), 256, inp);
260 } else
261 str = (char *)getlinknode(bufstack);
262 if (!str || errflag) {
263 if (breaks)
264 breaks--;
265 fprintf(stderr, "\n");
266 fflush(stderr);
267 goto done;
269 if ((s = strchr(str, '\n')))
270 *s = '\0';
271 if (*str)
272 break;
273 more = selectlist(args, more);
275 setsparam("REPLY", ztrdup(str));
276 i = atoi(str);
277 if (!i)
278 str = "";
279 else {
280 for (i--, n = firstnode(args); n && i; incnode(n), i--);
281 if (n)
282 str = (char *) getdata(n);
283 else
284 str = "";
286 setsparam(name, ztrdup(str));
287 state->pc = loop;
288 execlist(state, 1, 0);
289 freeheap();
290 if (breaks) {
291 breaks--;
292 if (breaks || !contflag)
293 break;
294 contflag = 0;
296 if (retflag || errflag)
297 break;
299 done:
300 cmdpop();
301 popheap();
302 fclose(inp);
303 loops--;
304 state->pc = end;
305 return lastval;
308 /* And this is used to print select lists. */
310 /**/
311 size_t
312 selectlist(LinkList l, size_t start)
314 size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct;
315 char **arr, **ap;
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);
322 t0 = ct = ap - arr;
323 longest++;
324 while (t0)
325 t0 /= 10, longest++;
326 /* to compensate for added ')' */
327 fct = (columns - 1) / (longest + 3);
328 if (fct == 0)
329 fct = 1;
330 else
331 fw = (columns - 1) / fct;
332 colsz = (ct + fct - 1) / fct;
333 for (t1 = start; t1 != colsz && t1 - start < lines - 2; t1++) {
334 ap = arr + t1;
335 do {
336 size_t t2 = strlen(*ap) + 2;
337 int t3;
339 fprintf(stderr, "%d) %s", t3 = ap - arr + 1, *ap);
340 while (t3)
341 t2++, t3 /= 10;
342 for (; t2 < fw; t2++)
343 fputc(' ', stderr);
344 for (t0 = colsz; t0 && *ap; t0--, ap++);
346 while (*ap);
347 fputc('\n', stderr);
350 /* Below is a simple attempt at doing it the Korn Way..
351 ap = arr;
352 t0 = 0;
353 do {
354 t0++;
355 fprintf(stderr,"%d) %s\n",t0,*ap);
356 ap++;
358 while (*ap);*/
359 fflush(stderr);
361 return t1 < colsz ? t1 : 0;
364 /**/
366 execwhile(Estate state, UNUSED(int do_exec))
368 Wordcode end, loop;
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;
374 oldval = 0;
375 pushheap();
376 cmdpush(isuntil ? CS_UNTIL : CS_WHILE);
377 loops++;
378 loop = state->pc;
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;
387 simple_pline = 1;
389 while (!breaks)
391 breaks--;
393 simple_pline = old_simple_pline;
394 } else
395 for (;;) {
396 state->pc = loop;
397 noerrexit = 1;
398 execlist(state, 1, 0);
399 noerrexit = olderrexit;
400 if (!((lastval == 0) ^ isuntil)) {
401 if (breaks)
402 breaks--;
403 lastval = oldval;
404 break;
406 if (retflag) {
407 lastval = oldval;
408 break;
410 execlist(state, 1, 0);
411 if (breaks) {
412 breaks--;
413 if (breaks || !contflag)
414 break;
415 contflag = 0;
417 if (errflag) {
418 lastval = 1;
419 break;
421 if (retflag)
422 break;
423 freeheap();
424 oldval = lastval;
426 cmdpop();
427 popheap();
428 loops--;
429 state->pc = end;
430 return lastval;
433 /**/
435 execrepeat(Estate state, UNUSED(int do_exec))
437 Wordcode end, loop;
438 wordcode code = state->pc[-1];
439 int count, htok = 0;
440 char *tmp;
442 end = state->pc + WC_REPEAT_SKIP(code);
444 lastval = 0;
445 tmp = ecgetstr(state, EC_DUPTOK, &htok);
446 if (htok)
447 singsub(&tmp);
448 count = atoi(tmp);
449 pushheap();
450 cmdpush(CS_REPEAT);
451 loops++;
452 loop = state->pc;
453 while (count-- > 0) {
454 state->pc = loop;
455 execlist(state, 1, 0);
456 freeheap();
457 if (breaks) {
458 breaks--;
459 if (breaks || !contflag)
460 break;
461 contflag = 0;
463 if (errflag) {
464 lastval = 1;
465 break;
467 if (retflag)
468 break;
470 cmdpop();
471 popheap();
472 loops--;
473 state->pc = end;
474 return lastval;
477 /**/
479 execif(Estate state, int do_exec)
481 Wordcode end, next;
482 wordcode code = state->pc[-1];
483 int olderrexit, s = 0, run = 0;
485 olderrexit = noerrexit;
486 end = state->pc + WC_IF_SKIP(code);
488 if (!noerrexit)
489 noerrexit = 1;
490 while (state->pc < end) {
491 code = *state->pc++;
492 if (wc_code(code) != WC_IF ||
493 (run = (WC_IF_TYPE(code) == WC_IF_ELSE))) {
494 if (run)
495 run = 2;
496 break;
498 next = state->pc + WC_IF_SKIP(code);
499 cmdpush(s ? CS_ELIF : CS_IF);
500 execlist(state, 1, 0);
501 cmdpop();
502 if (!lastval) {
503 run = 1;
504 break;
506 if (retflag)
507 break;
508 s = 1;
509 state->pc = next;
511 noerrexit = olderrexit;
513 if (run) {
514 cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN));
515 execlist(state, 1, do_exec);
516 cmdpop();
517 } else
518 lastval = 0;
519 state->pc = end;
521 return lastval;
524 /**/
526 execcase(Estate state, int do_exec)
528 Wordcode end, next;
529 wordcode code = state->pc[-1];
530 char *word, *pat;
531 int npat, save;
532 Patprog *spprog, pprog;
534 end = state->pc + WC_CASE_SKIP(code);
536 word = ecgetstr(state, EC_DUP, NULL);
537 singsub(&word);
538 untokenize(word);
539 lastval = 0;
541 cmdpush(CS_CASE);
542 while (state->pc < end) {
543 code = *state->pc++;
544 if (wc_code(code) != WC_CASE)
545 break;
547 pat = NULL;
548 pprog = NULL;
549 save = 0;
550 npat = state->pc[1];
551 spprog = state->prog->pats + npat;
553 next = state->pc + WC_CASE_SKIP(code);
555 if (isset(XTRACE)) {
556 char *opat;
558 pat = dupstring(opat = ecrawstr(state->prog, state->pc, NULL));
559 singsub(&pat);
560 save = (!(state->prog->flags & EF_HEAP) &&
561 !strcmp(pat, opat) && *spprog != dummy_patprog2);
563 printprompt4();
564 fprintf(xtrerr, "case %s (", word);
565 quote_tokenized_output(pat, xtrerr);
566 fprintf(xtrerr, ")\n");
567 fflush(xtrerr);
569 state->pc += 2;
571 if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
572 pprog = *spprog;
574 if (!pprog) {
575 if (!pat) {
576 char *opat;
577 int htok = 0;
579 pat = dupstring(opat = ecrawstr(state->prog,
580 state->pc - 2, &htok));
581 if (htok)
582 singsub(&pat);
583 save = (!(state->prog->flags & EF_HEAP) &&
584 !strcmp(pat, opat) && *spprog != dummy_patprog2);
586 if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
587 NULL)))
588 zerr("bad pattern: %s", pat);
589 else if (save)
590 *spprog = pprog;
592 if (pprog && pattry(pprog, word)) {
593 execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
594 do_exec));
595 while (!retflag && wc_code(code) == WC_CASE &&
596 WC_CASE_TYPE(code) == WC_CASE_AND) {
597 state->pc = next;
598 code = *state->pc;
599 state->pc += 3;
600 next = state->pc + WC_CASE_SKIP(code) - 2;
601 execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
602 do_exec));
604 if (WC_CASE_TYPE(code) != WC_CASE_TESTAND)
605 break;
607 state->pc = next;
609 cmdpop();
611 state->pc = end;
613 return lastval;
617 * Errflag from `try' block, may be reset in `always' block.
618 * Accessible from an integer parameter, so needs to be a zlong.
621 /**/
622 zlong
623 try_errflag = -1;
625 /**/
626 zlong
627 try_tryflag = 0;
629 /**/
631 exectry(Estate state, int do_exec)
633 Wordcode end, always;
634 int endval;
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);
640 state->pc++;
641 pushheap();
642 cmdpush(CS_CURSH);
644 /* The :try clause */
645 save_try_tryflag = try_tryflag;
646 try_tryflag = 1;
648 execlist(state, 1, do_exec);
650 try_tryflag = save_try_tryflag;
652 /* Don't record errflag here, may be reset. */
653 endval = lastval;
655 freeheap();
657 cmdpop();
658 cmdpush(CS_ALWAYS);
660 /* The always clause. */
661 save_try_errflag = try_errflag;
662 try_errflag = (zlong)errflag;
663 errflag = 0;
664 save_retflag = retflag;
665 retflag = 0;
666 save_breaks = breaks;
667 breaks = 0;
668 save_contflag = contflag;
669 contflag = 0;
671 state->pc = always;
672 execlist(state, 1, do_exec);
674 errflag = try_errflag ? 1 : 0;
675 try_errflag = save_try_errflag;
676 if (!retflag)
677 retflag = save_retflag;
678 if (!breaks)
679 breaks = save_breaks;
680 if (!contflag)
681 contflag = save_contflag;
683 cmdpop();
684 popheap();
685 state->pc = end;
687 return endval;