Commit | Line | Data |
---|---|---|
b208e9f0 WJ |
1 | /*- |
2 | * Copyright (c) 1980, 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #ifndef lint | |
35 | static char sccsid[] = "@(#)func.c 5.20 (Berkeley) 6/27/91"; | |
36 | #endif /* not lint */ | |
37 | ||
38 | #include <sys/types.h> | |
39 | #include <sys/stat.h> | |
40 | #include <signal.h> | |
41 | #include <locale.h> | |
42 | #include <stdlib.h> | |
43 | #include <string.h> | |
44 | #include <unistd.h> | |
45 | #if __STDC__ | |
46 | # include <stdarg.h> | |
47 | #else | |
48 | # include <varargs.h> | |
49 | #endif | |
50 | ||
51 | #include "csh.h" | |
52 | #include "extern.h" | |
53 | #include "pathnames.h" | |
54 | ||
55 | extern char **environ; | |
56 | ||
57 | static int zlast = -1; | |
58 | static void islogin __P((void)); | |
59 | static void reexecute __P((struct command *)); | |
60 | static void preread __P((void)); | |
61 | static void doagain __P((void)); | |
62 | static int getword __P((Char *)); | |
63 | static int keyword __P((Char *)); | |
64 | static void Unsetenv __P((Char *)); | |
65 | static void toend __P((void)); | |
66 | static void xecho __P((int, Char **)); | |
67 | ||
68 | struct biltins * | |
69 | isbfunc(t) | |
70 | struct command *t; | |
71 | { | |
72 | register Char *cp = t->t_dcom[0]; | |
73 | register struct biltins *bp, *bp1, *bp2; | |
74 | static struct biltins label = {"", dozip, 0, 0}; | |
75 | static struct biltins foregnd = {"%job", dofg1, 0, 0}; | |
76 | static struct biltins backgnd = {"%job &", dobg1, 0, 0}; | |
77 | ||
78 | if (lastchr(cp) == ':') { | |
79 | label.bname = short2str(cp); | |
80 | return (&label); | |
81 | } | |
82 | if (*cp == '%') { | |
83 | if (t->t_dflg & F_AMPERSAND) { | |
84 | t->t_dflg &= ~F_AMPERSAND; | |
85 | backgnd.bname = short2str(cp); | |
86 | return (&backgnd); | |
87 | } | |
88 | foregnd.bname = short2str(cp); | |
89 | return (&foregnd); | |
90 | } | |
91 | /* | |
92 | * Binary search Bp1 is the beginning of the current search range. Bp2 is | |
93 | * one past the end. | |
94 | */ | |
95 | for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { | |
96 | register i; | |
97 | ||
98 | bp = bp1 + ((bp2 - bp1) >> 1); | |
99 | if ((i = *cp - *bp->bname) == 0 && | |
100 | (i = Strcmp(cp, str2short(bp->bname))) == 0) | |
101 | return bp; | |
102 | if (i < 0) | |
103 | bp2 = bp; | |
104 | else | |
105 | bp1 = bp + 1; | |
106 | } | |
107 | return (0); | |
108 | } | |
109 | ||
110 | void | |
111 | func(t, bp) | |
112 | register struct command *t; | |
113 | register struct biltins *bp; | |
114 | { | |
115 | int i; | |
116 | ||
117 | xechoit(t->t_dcom); | |
118 | setname(bp->bname); | |
119 | i = blklen(t->t_dcom) - 1; | |
120 | if (i < bp->minargs) | |
121 | stderror(ERR_NAME | ERR_TOOFEW); | |
122 | if (i > bp->maxargs) | |
123 | stderror(ERR_NAME | ERR_TOOMANY); | |
124 | (*bp->bfunct) (t->t_dcom, t); | |
125 | } | |
126 | ||
127 | void | |
128 | doonintr(v) | |
129 | Char **v; | |
130 | { | |
131 | register Char *cp; | |
132 | register Char *vv = v[1]; | |
133 | ||
134 | if (parintr == SIG_IGN) | |
135 | return; | |
136 | if (setintr && intty) | |
137 | stderror(ERR_NAME | ERR_TERMINAL); | |
138 | cp = gointr; | |
139 | gointr = 0; | |
140 | xfree((ptr_t) cp); | |
141 | if (vv == 0) { | |
142 | if (setintr) | |
143 | (void) sigblock(sigmask(SIGINT)); | |
144 | else | |
145 | (void) signal(SIGINT, SIG_DFL); | |
146 | gointr = 0; | |
147 | } | |
148 | else if (eq((vv = strip(vv)), STRminus)) { | |
149 | (void) signal(SIGINT, SIG_IGN); | |
150 | gointr = Strsave(STRminus); | |
151 | } | |
152 | else { | |
153 | gointr = Strsave(vv); | |
154 | (void) signal(SIGINT, pintr); | |
155 | } | |
156 | } | |
157 | ||
158 | void | |
159 | donohup() | |
160 | { | |
161 | if (intty) | |
162 | stderror(ERR_NAME | ERR_TERMINAL); | |
163 | if (setintr == 0) { | |
164 | (void) signal(SIGHUP, SIG_IGN); | |
165 | } | |
166 | } | |
167 | ||
168 | void | |
169 | dozip() | |
170 | { | |
171 | ; | |
172 | } | |
173 | ||
174 | void | |
175 | prvars() | |
176 | { | |
177 | plist(&shvhed); | |
178 | } | |
179 | ||
180 | void | |
181 | doalias(v) | |
182 | register Char **v; | |
183 | { | |
184 | register struct varent *vp; | |
185 | register Char *p; | |
186 | ||
187 | v++; | |
188 | p = *v++; | |
189 | if (p == 0) | |
190 | plist(&aliases); | |
191 | else if (*v == 0) { | |
192 | vp = adrof1(strip(p), &aliases); | |
193 | if (vp) | |
194 | blkpr(vp->vec), xprintf("\n"); | |
195 | } | |
196 | else { | |
197 | if (eq(p, STRalias) || eq(p, STRunalias)) { | |
198 | setname(short2str(p)); | |
199 | stderror(ERR_NAME | ERR_DANGER); | |
200 | } | |
201 | set1(strip(p), saveblk(v), &aliases); | |
202 | } | |
203 | } | |
204 | ||
205 | void | |
206 | unalias(v) | |
207 | Char **v; | |
208 | { | |
209 | unset1(v, &aliases); | |
210 | } | |
211 | ||
212 | void | |
213 | dologout() | |
214 | { | |
215 | islogin(); | |
216 | goodbye(); | |
217 | } | |
218 | ||
219 | void | |
220 | dologin(v) | |
221 | Char **v; | |
222 | { | |
223 | islogin(); | |
224 | rechist(); | |
225 | (void) signal(SIGTERM, parterm); | |
226 | (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL); | |
227 | untty(); | |
228 | xexit(1); | |
229 | } | |
230 | ||
231 | static void | |
232 | islogin() | |
233 | { | |
234 | if (chkstop == 0 && setintr) | |
235 | panystop(0); | |
236 | if (loginsh) | |
237 | return; | |
238 | stderror(ERR_NOTLOGIN); | |
239 | } | |
240 | ||
241 | void | |
242 | doif(v, kp) | |
243 | Char **v; | |
244 | struct command *kp; | |
245 | { | |
246 | register int i; | |
247 | register Char **vv; | |
248 | ||
249 | v++; | |
250 | i = exp(&v); | |
251 | vv = v; | |
252 | if (*vv == NULL) | |
253 | stderror(ERR_NAME | ERR_EMPTYIF); | |
254 | if (eq(*vv, STRthen)) { | |
255 | if (*++vv) | |
256 | stderror(ERR_NAME | ERR_IMPRTHEN); | |
257 | setname(short2str(STRthen)); | |
258 | /* | |
259 | * If expression was zero, then scan to else, otherwise just fall into | |
260 | * following code. | |
261 | */ | |
262 | if (!i) | |
263 | search(T_IF, 0, NULL); | |
264 | return; | |
265 | } | |
266 | /* | |
267 | * Simple command attached to this if. Left shift the node in this tree, | |
268 | * munging it so we can reexecute it. | |
269 | */ | |
270 | if (i) { | |
271 | lshift(kp->t_dcom, vv - kp->t_dcom); | |
272 | reexecute(kp); | |
273 | donefds(); | |
274 | } | |
275 | } | |
276 | ||
277 | /* | |
278 | * Reexecute a command, being careful not | |
279 | * to redo i/o redirection, which is already set up. | |
280 | */ | |
281 | static void | |
282 | reexecute(kp) | |
283 | register struct command *kp; | |
284 | { | |
285 | kp->t_dflg &= F_SAVE; | |
286 | kp->t_dflg |= F_REPEAT; | |
287 | /* | |
288 | * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set | |
289 | * pgrp's as the jobs would then have no way to get the tty (we can't give | |
290 | * it to them, and our parent wouldn't know their pgrp, etc. | |
291 | */ | |
292 | execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL); | |
293 | } | |
294 | ||
295 | void | |
296 | doelse() | |
297 | { | |
298 | search(T_ELSE, 0, NULL); | |
299 | } | |
300 | ||
301 | void | |
302 | dogoto(v) | |
303 | Char **v; | |
304 | { | |
305 | register struct whyle *wp; | |
306 | Char *lp; | |
307 | ||
308 | /* | |
309 | * While we still can, locate any unknown ends of existing loops. This | |
310 | * obscure code is the WORST result of the fact that we don't really parse. | |
311 | */ | |
312 | zlast = T_GOTO; | |
313 | for (wp = whyles; wp; wp = wp->w_next) | |
314 | if (wp->w_end == 0) { | |
315 | search(T_BREAK, 0, NULL); | |
316 | wp->w_end = fseekp; | |
317 | } | |
318 | else | |
319 | bseek(wp->w_end); | |
320 | search(T_GOTO, 0, lp = globone(v[1], G_ERROR)); | |
321 | xfree((ptr_t) lp); | |
322 | /* | |
323 | * Eliminate loops which were exited. | |
324 | */ | |
325 | wfree(); | |
326 | } | |
327 | ||
328 | void | |
329 | doswitch(v) | |
330 | register Char **v; | |
331 | { | |
332 | register Char *cp, *lp; | |
333 | ||
334 | v++; | |
335 | if (!*v || *(*v++) != '(') | |
336 | stderror(ERR_SYNTAX); | |
337 | cp = **v == ')' ? STRNULL : *v++; | |
338 | if (*(*v++) != ')') | |
339 | v--; | |
340 | if (*v) | |
341 | stderror(ERR_SYNTAX); | |
342 | search(T_SWITCH, 0, lp = globone(cp, G_ERROR)); | |
343 | xfree((ptr_t) lp); | |
344 | } | |
345 | ||
346 | void | |
347 | dobreak() | |
348 | { | |
349 | if (whyles) | |
350 | toend(); | |
351 | else | |
352 | stderror(ERR_NAME | ERR_NOTWHILE); | |
353 | } | |
354 | ||
355 | void | |
356 | doexit(v) | |
357 | Char **v; | |
358 | { | |
359 | if (chkstop == 0 && (intty || intact) && evalvec == 0) | |
360 | panystop(0); | |
361 | /* | |
362 | * Don't DEMAND parentheses here either. | |
363 | */ | |
364 | v++; | |
365 | if (*v) { | |
366 | set(STRstatus, putn(exp(&v))); | |
367 | if (*v) | |
368 | stderror(ERR_NAME | ERR_EXPRESSION); | |
369 | } | |
370 | btoeof(); | |
371 | if (intty) | |
372 | (void) close(SHIN); | |
373 | } | |
374 | ||
375 | void | |
376 | doforeach(v) | |
377 | register Char **v; | |
378 | { | |
379 | register Char *cp, *sp; | |
380 | register struct whyle *nwp; | |
381 | ||
382 | v++; | |
383 | sp = cp = strip(*v); | |
384 | if (!letter(*sp)) | |
385 | stderror(ERR_NAME | ERR_VARBEGIN); | |
386 | while (*cp && alnum(*cp)) | |
387 | cp++; | |
388 | if (*cp) | |
389 | stderror(ERR_NAME | ERR_VARALNUM); | |
390 | if ((cp - sp) > MAXVARLEN) | |
391 | stderror(ERR_NAME | ERR_VARTOOLONG); | |
392 | cp = *v++; | |
393 | if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') | |
394 | stderror(ERR_NAME | ERR_NOPAREN); | |
395 | v++; | |
396 | gflag = 0, tglob(v); | |
397 | v = globall(v); | |
398 | if (v == 0) | |
399 | stderror(ERR_NAME | ERR_NOMATCH); | |
400 | nwp = (struct whyle *) xcalloc(1, sizeof *nwp); | |
401 | nwp->w_fe = nwp->w_fe0 = v; | |
402 | gargv = 0; | |
403 | nwp->w_start = fseekp; | |
404 | nwp->w_fename = Strsave(cp); | |
405 | nwp->w_next = whyles; | |
406 | whyles = nwp; | |
407 | /* | |
408 | * Pre-read the loop so as to be more comprehensible to a terminal user. | |
409 | */ | |
410 | zlast = T_FOREACH; | |
411 | if (intty) | |
412 | preread(); | |
413 | doagain(); | |
414 | } | |
415 | ||
416 | void | |
417 | dowhile(v) | |
418 | Char **v; | |
419 | { | |
420 | register int status; | |
421 | register bool again = whyles != 0 && whyles->w_start == lineloc && | |
422 | whyles->w_fename == 0; | |
423 | ||
424 | v++; | |
425 | /* | |
426 | * Implement prereading here also, taking care not to evaluate the | |
427 | * expression before the loop has been read up from a terminal. | |
428 | */ | |
429 | if (intty && !again) | |
430 | status = !exp0(&v, 1); | |
431 | else | |
432 | status = !exp(&v); | |
433 | if (*v) | |
434 | stderror(ERR_NAME | ERR_EXPRESSION); | |
435 | if (!again) { | |
436 | register struct whyle *nwp = | |
437 | (struct whyle *) xcalloc(1, sizeof(*nwp)); | |
438 | ||
439 | nwp->w_start = lineloc; | |
440 | nwp->w_end = 0; | |
441 | nwp->w_next = whyles; | |
442 | whyles = nwp; | |
443 | zlast = T_WHILE; | |
444 | if (intty) { | |
445 | /* | |
446 | * The tty preread | |
447 | */ | |
448 | preread(); | |
449 | doagain(); | |
450 | return; | |
451 | } | |
452 | } | |
453 | if (status) | |
454 | /* We ain't gonna loop no more, no more! */ | |
455 | toend(); | |
456 | } | |
457 | ||
458 | static void | |
459 | preread() | |
460 | { | |
461 | whyles->w_end = -1; | |
462 | if (setintr) | |
463 | (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); | |
464 | ||
465 | search(T_BREAK, 0, NULL); /* read the expression in */ | |
466 | if (setintr) | |
467 | (void) sigblock(sigmask(SIGINT)); | |
468 | whyles->w_end = fseekp; | |
469 | } | |
470 | ||
471 | void | |
472 | doend() | |
473 | { | |
474 | if (!whyles) | |
475 | stderror(ERR_NAME | ERR_NOTWHILE); | |
476 | whyles->w_end = fseekp; | |
477 | doagain(); | |
478 | } | |
479 | ||
480 | void | |
481 | docontin() | |
482 | { | |
483 | if (!whyles) | |
484 | stderror(ERR_NAME | ERR_NOTWHILE); | |
485 | doagain(); | |
486 | } | |
487 | ||
488 | static void | |
489 | doagain() | |
490 | { | |
491 | /* Repeating a while is simple */ | |
492 | if (whyles->w_fename == 0) { | |
493 | bseek(whyles->w_start); | |
494 | return; | |
495 | } | |
496 | /* | |
497 | * The foreach variable list actually has a spurious word ")" at the end of | |
498 | * the w_fe list. Thus we are at the of the list if one word beyond this | |
499 | * is 0. | |
500 | */ | |
501 | if (!whyles->w_fe[1]) { | |
502 | dobreak(); | |
503 | return; | |
504 | } | |
505 | set(whyles->w_fename, Strsave(*whyles->w_fe++)); | |
506 | bseek(whyles->w_start); | |
507 | } | |
508 | ||
509 | void | |
510 | dorepeat(v, kp) | |
511 | Char **v; | |
512 | struct command *kp; | |
513 | { | |
514 | register int i; | |
515 | register sigset_t omask = 0; | |
516 | ||
517 | i = getn(v[1]); | |
518 | if (setintr) | |
519 | omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); | |
520 | lshift(v, 2); | |
521 | while (i > 0) { | |
522 | if (setintr) | |
523 | (void) sigsetmask(omask); | |
524 | reexecute(kp); | |
525 | --i; | |
526 | } | |
527 | donefds(); | |
528 | if (setintr) | |
529 | (void) sigsetmask(omask); | |
530 | } | |
531 | ||
532 | void | |
533 | doswbrk() | |
534 | { | |
535 | search(T_BRKSW, 0, NULL); | |
536 | } | |
537 | ||
538 | int | |
539 | srchx(cp) | |
540 | register Char *cp; | |
541 | { | |
542 | register struct srch *sp, *sp1, *sp2; | |
543 | register i; | |
544 | ||
545 | /* | |
546 | * Binary search Sp1 is the beginning of the current search range. Sp2 is | |
547 | * one past the end. | |
548 | */ | |
549 | for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { | |
550 | sp = sp1 + ((sp2 - sp1) >> 1); | |
551 | if ((i = *cp - *sp->s_name) == 0 && | |
552 | (i = Strcmp(cp, str2short(sp->s_name))) == 0) | |
553 | return sp->s_value; | |
554 | if (i < 0) | |
555 | sp2 = sp; | |
556 | else | |
557 | sp1 = sp + 1; | |
558 | } | |
559 | return (-1); | |
560 | } | |
561 | ||
562 | static Char Stype; | |
563 | static Char *Sgoal; | |
564 | ||
565 | /*VARARGS2*/ | |
566 | void | |
567 | search(type, level, goal) | |
568 | int type; | |
569 | register int level; | |
570 | Char *goal; | |
571 | { | |
572 | Char wordbuf[BUFSIZ]; | |
573 | register Char *aword = wordbuf; | |
574 | register Char *cp; | |
575 | ||
576 | Stype = type; | |
577 | Sgoal = goal; | |
578 | if (type == T_GOTO) | |
579 | bseek((off_t) 0); | |
580 | do { | |
581 | if (intty && fseekp == feobp) | |
582 | xprintf("? "), flush(); | |
583 | aword[0] = 0; | |
584 | (void) getword(aword); | |
585 | switch (srchx(aword)) { | |
586 | ||
587 | case T_ELSE: | |
588 | if (level == 0 && type == T_IF) | |
589 | return; | |
590 | break; | |
591 | ||
592 | case T_IF: | |
593 | while (getword(aword)) | |
594 | continue; | |
595 | if ((type == T_IF || type == T_ELSE) && | |
596 | eq(aword, STRthen)) | |
597 | level++; | |
598 | break; | |
599 | ||
600 | case T_ENDIF: | |
601 | if (type == T_IF || type == T_ELSE) | |
602 | level--; | |
603 | break; | |
604 | ||
605 | case T_FOREACH: | |
606 | case T_WHILE: | |
607 | if (type == T_BREAK) | |
608 | level++; | |
609 | break; | |
610 | ||
611 | case T_END: | |
612 | if (type == T_BREAK) | |
613 | level--; | |
614 | break; | |
615 | ||
616 | case T_SWITCH: | |
617 | if (type == T_SWITCH || type == T_BRKSW) | |
618 | level++; | |
619 | break; | |
620 | ||
621 | case T_ENDSW: | |
622 | if (type == T_SWITCH || type == T_BRKSW) | |
623 | level--; | |
624 | break; | |
625 | ||
626 | case T_LABEL: | |
627 | if (type == T_GOTO && getword(aword) && eq(aword, goal)) | |
628 | level = -1; | |
629 | break; | |
630 | ||
631 | default: | |
632 | if (type != T_GOTO && (type != T_SWITCH || level != 0)) | |
633 | break; | |
634 | if (lastchr(aword) != ':') | |
635 | break; | |
636 | aword[Strlen(aword) - 1] = 0; | |
637 | if (type == T_GOTO && eq(aword, goal) || | |
638 | type == T_SWITCH && eq(aword, STRdefault)) | |
639 | level = -1; | |
640 | break; | |
641 | ||
642 | case T_CASE: | |
643 | if (type != T_SWITCH || level != 0) | |
644 | break; | |
645 | (void) getword(aword); | |
646 | if (lastchr(aword) == ':') | |
647 | aword[Strlen(aword) - 1] = 0; | |
648 | cp = strip(Dfix1(aword)); | |
649 | if (Gmatch(goal, cp)) | |
650 | level = -1; | |
651 | xfree((ptr_t) cp); | |
652 | break; | |
653 | ||
654 | case T_DEFAULT: | |
655 | if (type == T_SWITCH && level == 0) | |
656 | level = -1; | |
657 | break; | |
658 | } | |
659 | (void) getword(NULL); | |
660 | } while (level >= 0); | |
661 | } | |
662 | ||
663 | static int | |
664 | getword(wp) | |
665 | register Char *wp; | |
666 | { | |
667 | register int found = 0; | |
668 | register int c, d; | |
669 | int kwd = 0; | |
670 | Char *owp = wp; | |
671 | ||
672 | c = readc(1); | |
673 | d = 0; | |
674 | do { | |
675 | while (c == ' ' || c == '\t') | |
676 | c = readc(1); | |
677 | if (c == '#') | |
678 | do | |
679 | c = readc(1); | |
680 | while (c >= 0 && c != '\n'); | |
681 | if (c < 0) | |
682 | goto past; | |
683 | if (c == '\n') { | |
684 | if (wp) | |
685 | break; | |
686 | return (0); | |
687 | } | |
688 | unreadc(c); | |
689 | found = 1; | |
690 | do { | |
691 | c = readc(1); | |
692 | if (c == '\\' && (c = readc(1)) == '\n') | |
693 | c = ' '; | |
694 | if (c == '\'' || c == '"') | |
695 | if (d == 0) | |
696 | d = c; | |
697 | else if (d == c) | |
698 | d = 0; | |
699 | if (c < 0) | |
700 | goto past; | |
701 | if (wp) { | |
702 | *wp++ = c; | |
703 | *wp = 0; /* end the string b4 test */ | |
704 | } | |
705 | } while ((d || !(kwd = keyword(owp)) && c != ' ' | |
706 | && c != '\t') && c != '\n'); | |
707 | } while (wp == 0); | |
708 | ||
709 | /* | |
710 | * if we have read a keyword ( "if", "switch" or "while" ) then we do not | |
711 | * need to unreadc the look-ahead char | |
712 | */ | |
713 | if (!kwd) { | |
714 | unreadc(c); | |
715 | if (found) | |
716 | *--wp = 0; | |
717 | } | |
718 | ||
719 | return (found); | |
720 | ||
721 | past: | |
722 | switch (Stype) { | |
723 | ||
724 | case T_IF: | |
725 | stderror(ERR_NAME | ERR_NOTFOUND, "then/endif"); | |
726 | ||
727 | case T_ELSE: | |
728 | stderror(ERR_NAME | ERR_NOTFOUND, "endif"); | |
729 | ||
730 | case T_BRKSW: | |
731 | case T_SWITCH: | |
732 | stderror(ERR_NAME | ERR_NOTFOUND, "endsw"); | |
733 | ||
734 | case T_BREAK: | |
735 | stderror(ERR_NAME | ERR_NOTFOUND, "end"); | |
736 | ||
737 | case T_GOTO: | |
738 | setname(short2str(Sgoal)); | |
739 | stderror(ERR_NAME | ERR_NOTFOUND, "label"); | |
740 | } | |
741 | /* NOTREACHED */ | |
742 | return (0); | |
743 | } | |
744 | ||
745 | /* | |
746 | * keyword(wp) determines if wp is one of the built-n functions if, | |
747 | * switch or while. It seems that when an if statement looks like | |
748 | * "if(" then getword above sucks in the '(' and so the search routine | |
749 | * never finds what it is scanning for. Rather than rewrite doword, I hack | |
750 | * in a test to see if the string forms a keyword. Then doword stops | |
751 | * and returns the word "if" -strike | |
752 | */ | |
753 | ||
754 | static int | |
755 | keyword(wp) | |
756 | Char *wp; | |
757 | { | |
758 | static Char STRif[] = {'i', 'f', '\0'}; | |
759 | static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'}; | |
760 | static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'}; | |
761 | ||
762 | if (!wp) | |
763 | return (0); | |
764 | ||
765 | if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0) | |
766 | || (Strcmp(wp, STRswitch) == 0)) | |
767 | return (1); | |
768 | ||
769 | return (0); | |
770 | } | |
771 | ||
772 | static void | |
773 | toend() | |
774 | { | |
775 | if (whyles->w_end == 0) { | |
776 | search(T_BREAK, 0, NULL); | |
777 | whyles->w_end = fseekp - 1; | |
778 | } | |
779 | else | |
780 | bseek(whyles->w_end); | |
781 | wfree(); | |
782 | } | |
783 | ||
784 | void | |
785 | wfree() | |
786 | { | |
787 | long o = fseekp; | |
788 | ||
789 | while (whyles) { | |
790 | register struct whyle *wp = whyles; | |
791 | register struct whyle *nwp = wp->w_next; | |
792 | ||
793 | if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) | |
794 | break; | |
795 | if (wp->w_fe0) | |
796 | blkfree(wp->w_fe0); | |
797 | if (wp->w_fename) | |
798 | xfree((ptr_t) wp->w_fename); | |
799 | xfree((ptr_t) wp); | |
800 | whyles = nwp; | |
801 | } | |
802 | } | |
803 | ||
804 | void | |
805 | doecho(v) | |
806 | Char **v; | |
807 | { | |
808 | xecho(' ', v); | |
809 | } | |
810 | ||
811 | void | |
812 | doglob(v) | |
813 | Char **v; | |
814 | { | |
815 | xecho(0, v); | |
816 | flush(); | |
817 | } | |
818 | ||
819 | static void | |
820 | xecho(sep, v) | |
821 | int sep; | |
822 | register Char **v; | |
823 | { | |
824 | register Char *cp; | |
825 | int nonl = 0; | |
826 | ||
827 | if (setintr) | |
828 | (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); | |
829 | v++; | |
830 | if (*v == 0) | |
831 | return; | |
832 | gflag = 0, tglob(v); | |
833 | if (gflag) { | |
834 | v = globall(v); | |
835 | if (v == 0) | |
836 | stderror(ERR_NAME | ERR_NOMATCH); | |
837 | } | |
838 | else { | |
839 | v = gargv = saveblk(v); | |
840 | trim(v); | |
841 | } | |
842 | if (sep == ' ' && *v && eq(*v, STRmn)) | |
843 | nonl++, v++; | |
844 | while (cp = *v++) { | |
845 | register int c; | |
846 | ||
847 | while (c = *cp++) | |
848 | xputchar(c | QUOTE); | |
849 | ||
850 | if (*v) | |
851 | xputchar(sep | QUOTE); | |
852 | } | |
853 | if (sep && nonl == 0) | |
854 | xputchar('\n'); | |
855 | else | |
856 | flush(); | |
857 | if (setintr) | |
858 | (void) sigblock(sigmask(SIGINT)); | |
859 | if (gargv) | |
860 | blkfree(gargv), gargv = 0; | |
861 | } | |
862 | ||
863 | /* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things | |
864 | (and anything else with a modern compiler) */ | |
865 | ||
866 | void | |
867 | dosetenv(v) | |
868 | register Char **v; | |
869 | { | |
870 | Char *vp, *lp; | |
871 | ||
872 | v++; | |
873 | if ((vp = *v++) == 0) { | |
874 | register Char **ep; | |
875 | ||
876 | if (setintr) | |
877 | (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); | |
878 | for (ep = STR_environ; *ep; ep++) | |
879 | xprintf("%s\n", short2str(*ep)); | |
880 | return; | |
881 | } | |
882 | if ((lp = *v++) == 0) | |
883 | lp = STRNULL; | |
884 | Setenv(vp, lp = globone(lp, G_ERROR)); | |
885 | if (eq(vp, STRPATH)) { | |
886 | importpath(lp); | |
887 | dohash(); | |
888 | } | |
889 | else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) { | |
890 | #ifdef NLS | |
891 | int k; | |
892 | ||
893 | (void) setlocale(LC_ALL, ""); | |
894 | for (k = 0200; k <= 0377 && !Isprint(k); k++); | |
895 | AsciiOnly = k > 0377; | |
896 | #else | |
897 | AsciiOnly = 0; | |
898 | #endif /* NLS */ | |
899 | } | |
900 | xfree((ptr_t) lp); | |
901 | } | |
902 | ||
903 | void | |
904 | dounsetenv(v) | |
905 | register Char **v; | |
906 | { | |
907 | Char **ep, *p, *n; | |
908 | int i, maxi; | |
909 | static Char *name = NULL; | |
910 | ||
911 | if (name) | |
912 | xfree((ptr_t) name); | |
913 | /* | |
914 | * Find the longest environment variable | |
915 | */ | |
916 | for (maxi = 0, ep = STR_environ; *ep; ep++) { | |
917 | for (i = 0, p = *ep; *p && *p != '='; p++, i++); | |
918 | if (i > maxi) | |
919 | maxi = i; | |
920 | } | |
921 | ||
922 | name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char)); | |
923 | ||
924 | while (++v && *v) | |
925 | for (maxi = 1; maxi;) | |
926 | for (maxi = 0, ep = STR_environ; *ep; ep++) { | |
927 | for (n = name, p = *ep; *p && *p != '='; *n++ = *p++); | |
928 | *n = '\0'; | |
929 | if (!Gmatch(name, *v)) | |
930 | continue; | |
931 | maxi = 1; | |
932 | if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) { | |
933 | #ifdef NLS | |
934 | int k; | |
935 | ||
936 | (void) setlocale(LC_ALL, ""); | |
937 | for (k = 0200; k <= 0377 && !Isprint(k); k++); | |
938 | AsciiOnly = k > 0377; | |
939 | #else | |
940 | AsciiOnly = getenv("LANG") == NULL && | |
941 | getenv("LC_CTYPE") == NULL; | |
942 | #endif /* NLS */ | |
943 | } | |
944 | /* | |
945 | * Delete name, and start again cause the environment changes | |
946 | */ | |
947 | Unsetenv(name); | |
948 | break; | |
949 | } | |
950 | xfree((ptr_t) name), name = NULL; | |
951 | } | |
952 | ||
953 | void | |
954 | Setenv(name, val) | |
955 | Char *name, *val; | |
956 | { | |
957 | register Char **ep = STR_environ; | |
958 | register Char *cp, *dp; | |
959 | Char *blk[2]; | |
960 | Char **oep = ep; | |
961 | ||
962 | ||
963 | for (; *ep; ep++) { | |
964 | for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) | |
965 | continue; | |
966 | if (*cp != 0 || *dp != '=') | |
967 | continue; | |
968 | cp = Strspl(STRequal, val); | |
969 | xfree((ptr_t) * ep); | |
970 | *ep = strip(Strspl(name, cp)); | |
971 | xfree((ptr_t) cp); | |
972 | blkfree((Char **) environ); | |
973 | environ = short2blk(STR_environ); | |
974 | return; | |
975 | } | |
976 | cp = Strspl(name, STRequal); | |
977 | blk[0] = strip(Strspl(cp, val)); | |
978 | xfree((ptr_t) cp); | |
979 | blk[1] = 0; | |
980 | STR_environ = blkspl(STR_environ, blk); | |
981 | blkfree((Char **) environ); | |
982 | environ = short2blk(STR_environ); | |
983 | xfree((ptr_t) oep); | |
984 | } | |
985 | ||
986 | static void | |
987 | Unsetenv(name) | |
988 | Char *name; | |
989 | { | |
990 | register Char **ep = STR_environ; | |
991 | register Char *cp, *dp; | |
992 | Char **oep = ep; | |
993 | ||
994 | for (; *ep; ep++) { | |
995 | for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++) | |
996 | continue; | |
997 | if (*cp != 0 || *dp != '=') | |
998 | continue; | |
999 | cp = *ep; | |
1000 | *ep = 0; | |
1001 | STR_environ = blkspl(STR_environ, ep + 1); | |
1002 | environ = short2blk(STR_environ); | |
1003 | *ep = cp; | |
1004 | xfree((ptr_t) cp); | |
1005 | xfree((ptr_t) oep); | |
1006 | return; | |
1007 | } | |
1008 | } | |
1009 | ||
1010 | void | |
1011 | doumask(v) | |
1012 | register Char **v; | |
1013 | { | |
1014 | register Char *cp = v[1]; | |
1015 | register int i; | |
1016 | ||
1017 | if (cp == 0) { | |
1018 | i = umask(0); | |
1019 | (void) umask(i); | |
1020 | xprintf("%o\n", i); | |
1021 | return; | |
1022 | } | |
1023 | i = 0; | |
1024 | while (Isdigit(*cp) && *cp != '8' && *cp != '9') | |
1025 | i = i * 8 + *cp++ - '0'; | |
1026 | if (*cp || i < 0 || i > 0777) | |
1027 | stderror(ERR_NAME | ERR_MASK); | |
1028 | (void) umask(i); | |
1029 | } | |
1030 | ||
1031 | typedef int RLIM_TYPE; | |
1032 | ||
1033 | static struct limits { | |
1034 | int limconst; | |
1035 | char *limname; | |
1036 | int limdiv; | |
1037 | char *limscale; | |
1038 | } limits[] = { | |
1039 | RLIMIT_CPU, "cputime", 1, "seconds", | |
1040 | RLIMIT_FSIZE, "filesize", 1024, "kbytes", | |
1041 | RLIMIT_DATA, "datasize", 1024, "kbytes", | |
1042 | RLIMIT_STACK, "stacksize", 1024, "kbytes", | |
1043 | RLIMIT_CORE, "coredumpsize", 1024, "kbytes", | |
1044 | RLIMIT_RSS, "memoryuse", 1024, "kbytes", | |
1045 | RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes", | |
1046 | RLIMIT_NPROC, "maxproc", 1, "", | |
1047 | RLIMIT_OFILE, "openfiles", 1, "", | |
1048 | -1, NULL, 0, NULL | |
1049 | }; | |
1050 | ||
1051 | static struct limits *findlim(); | |
1052 | static RLIM_TYPE getval(); | |
1053 | static void limtail(); | |
1054 | static void plim(); | |
1055 | static int setlim(); | |
1056 | ||
1057 | static struct limits * | |
1058 | findlim(cp) | |
1059 | Char *cp; | |
1060 | { | |
1061 | register struct limits *lp, *res; | |
1062 | ||
1063 | res = (struct limits *) NULL; | |
1064 | for (lp = limits; lp->limconst >= 0; lp++) | |
1065 | if (prefix(cp, str2short(lp->limname))) { | |
1066 | if (res) | |
1067 | stderror(ERR_NAME | ERR_AMBIG); | |
1068 | res = lp; | |
1069 | } | |
1070 | if (res) | |
1071 | return (res); | |
1072 | stderror(ERR_NAME | ERR_LIMIT); | |
1073 | /* NOTREACHED */ | |
1074 | return (0); | |
1075 | } | |
1076 | ||
1077 | void | |
1078 | dolimit(v) | |
1079 | register Char **v; | |
1080 | { | |
1081 | register struct limits *lp; | |
1082 | register RLIM_TYPE limit; | |
1083 | char hard = 0; | |
1084 | ||
1085 | v++; | |
1086 | if (*v && eq(*v, STRmh)) { | |
1087 | hard = 1; | |
1088 | v++; | |
1089 | } | |
1090 | if (*v == 0) { | |
1091 | for (lp = limits; lp->limconst >= 0; lp++) | |
1092 | plim(lp, hard); | |
1093 | return; | |
1094 | } | |
1095 | lp = findlim(v[0]); | |
1096 | if (v[1] == 0) { | |
1097 | plim(lp, hard); | |
1098 | return; | |
1099 | } | |
1100 | limit = getval(lp, v + 1); | |
1101 | if (setlim(lp, hard, limit) < 0) | |
1102 | stderror(ERR_SILENT); | |
1103 | } | |
1104 | ||
1105 | static RLIM_TYPE | |
1106 | getval(lp, v) | |
1107 | register struct limits *lp; | |
1108 | Char **v; | |
1109 | { | |
1110 | register float f; | |
1111 | double atof(); | |
1112 | Char *cp = *v++; | |
1113 | ||
1114 | f = atof(short2str(cp)); | |
1115 | ||
1116 | while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') | |
1117 | cp++; | |
1118 | if (*cp == 0) { | |
1119 | if (*v == 0) | |
1120 | return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv)); | |
1121 | cp = *v; | |
1122 | } | |
1123 | switch (*cp) { | |
1124 | case ':': | |
1125 | if (lp->limconst != RLIMIT_CPU) | |
1126 | goto badscal; | |
1127 | return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1)))); | |
1128 | case 'h': | |
1129 | if (lp->limconst != RLIMIT_CPU) | |
1130 | goto badscal; | |
1131 | limtail(cp, "hours"); | |
1132 | f *= 3600.0; | |
1133 | break; | |
1134 | case 'm': | |
1135 | if (lp->limconst == RLIMIT_CPU) { | |
1136 | limtail(cp, "minutes"); | |
1137 | f *= 60.0; | |
1138 | break; | |
1139 | } | |
1140 | *cp = 'm'; | |
1141 | limtail(cp, "megabytes"); | |
1142 | f *= 1024.0 * 1024.0; | |
1143 | break; | |
1144 | case 's': | |
1145 | if (lp->limconst != RLIMIT_CPU) | |
1146 | goto badscal; | |
1147 | limtail(cp, "seconds"); | |
1148 | break; | |
1149 | case 'M': | |
1150 | if (lp->limconst == RLIMIT_CPU) | |
1151 | goto badscal; | |
1152 | *cp = 'm'; | |
1153 | limtail(cp, "megabytes"); | |
1154 | f *= 1024.0 * 1024.0; | |
1155 | break; | |
1156 | case 'k': | |
1157 | if (lp->limconst == RLIMIT_CPU) | |
1158 | goto badscal; | |
1159 | limtail(cp, "kbytes"); | |
1160 | f *= 1024.0; | |
1161 | break; | |
1162 | case 'u': | |
1163 | limtail(cp, "unlimited"); | |
1164 | return (RLIM_INFINITY); | |
1165 | default: | |
1166 | badscal: | |
1167 | stderror(ERR_NAME | ERR_SCALEF); | |
1168 | } | |
1169 | return ((RLIM_TYPE) (f + 0.5)); | |
1170 | } | |
1171 | ||
1172 | static void | |
1173 | limtail(cp, str) | |
1174 | Char *cp; | |
1175 | char *str; | |
1176 | { | |
1177 | while (*cp && *cp == *str) | |
1178 | cp++, str++; | |
1179 | if (*cp) | |
1180 | stderror(ERR_BADSCALE, str); | |
1181 | } | |
1182 | ||
1183 | ||
1184 | /*ARGSUSED*/ | |
1185 | static void | |
1186 | plim(lp, hard) | |
1187 | register struct limits *lp; | |
1188 | Char hard; | |
1189 | { | |
1190 | struct rlimit rlim; | |
1191 | RLIM_TYPE limit; | |
1192 | ||
1193 | xprintf("%s \t", lp->limname); | |
1194 | ||
1195 | (void) getrlimit(lp->limconst, &rlim); | |
1196 | limit = hard ? rlim.rlim_max : rlim.rlim_cur; | |
1197 | ||
1198 | if (limit == RLIM_INFINITY) | |
1199 | xprintf("unlimited"); | |
1200 | else if (lp->limconst == RLIMIT_CPU) | |
1201 | psecs((long) limit); | |
1202 | else | |
1203 | xprintf("%ld %s", (long) (limit / lp->limdiv), lp->limscale); | |
1204 | xprintf("\n"); | |
1205 | } | |
1206 | ||
1207 | void | |
1208 | dounlimit(v) | |
1209 | register Char **v; | |
1210 | { | |
1211 | register struct limits *lp; | |
1212 | int lerr = 0; | |
1213 | Char hard = 0; | |
1214 | ||
1215 | v++; | |
1216 | if (*v && eq(*v, STRmh)) { | |
1217 | hard = 1; | |
1218 | v++; | |
1219 | } | |
1220 | if (*v == 0) { | |
1221 | for (lp = limits; lp->limconst >= 0; lp++) | |
1222 | if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) | |
1223 | lerr++; | |
1224 | if (lerr) | |
1225 | stderror(ERR_SILENT); | |
1226 | return; | |
1227 | } | |
1228 | while (*v) { | |
1229 | lp = findlim(*v++); | |
1230 | if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0) | |
1231 | stderror(ERR_SILENT); | |
1232 | } | |
1233 | } | |
1234 | ||
1235 | static int | |
1236 | setlim(lp, hard, limit) | |
1237 | register struct limits *lp; | |
1238 | Char hard; | |
1239 | RLIM_TYPE limit; | |
1240 | { | |
1241 | struct rlimit rlim; | |
1242 | ||
1243 | (void) getrlimit(lp->limconst, &rlim); | |
1244 | ||
1245 | if (hard) | |
1246 | rlim.rlim_max = limit; | |
1247 | else if (limit == RLIM_INFINITY && geteuid() != 0) | |
1248 | rlim.rlim_cur = rlim.rlim_max; | |
1249 | else | |
1250 | rlim.rlim_cur = limit; | |
1251 | ||
1252 | if (setrlimit(lp->limconst, &rlim) < 0) { | |
1253 | xprintf("%s: %s: Can't %s%s limit\n", bname, lp->limname, | |
1254 | limit == RLIM_INFINITY ? "remove" : "set", | |
1255 | hard ? " hard" : ""); | |
1256 | return (-1); | |
1257 | } | |
1258 | return (0); | |
1259 | } | |
1260 | ||
1261 | void | |
1262 | dosuspend() | |
1263 | { | |
1264 | int ctpgrp; | |
1265 | ||
1266 | void (*old) (); | |
1267 | ||
1268 | if (loginsh) | |
1269 | stderror(ERR_SUSPLOG); | |
1270 | untty(); | |
1271 | ||
1272 | old = signal(SIGTSTP, SIG_DFL); | |
1273 | (void) kill(0, SIGTSTP); | |
1274 | /* the shell stops here */ | |
1275 | (void) signal(SIGTSTP, old); | |
1276 | ||
1277 | if (tpgrp != -1) { | |
1278 | retry: | |
1279 | ctpgrp = tcgetpgrp(FSHTTY); | |
1280 | if (ctpgrp != opgrp) { | |
1281 | old = signal(SIGTTIN, SIG_DFL); | |
1282 | (void) kill(0, SIGTTIN); | |
1283 | (void) signal(SIGTTIN, old); | |
1284 | goto retry; | |
1285 | } | |
1286 | (void) setpgid(0, shpgrp); | |
1287 | (void) tcsetpgrp(FSHTTY, shpgrp); | |
1288 | } | |
1289 | } | |
1290 | ||
1291 | /* This is the dreaded EVAL built-in. | |
1292 | * If you don't fiddle with file descriptors, and reset didfds, | |
1293 | * this command will either ignore redirection inside or outside | |
1294 | * its aguments, e.g. eval "date >x" vs. eval "date" >x | |
1295 | * The stuff here seems to work, but I did it by trial and error rather | |
1296 | * than really knowing what was going on. If tpgrp is zero, we are | |
1297 | * probably a background eval, e.g. "eval date &", and we want to | |
1298 | * make sure that any processes we start stay in our pgrp. | |
1299 | * This is also the case for "time eval date" -- stay in same pgrp. | |
1300 | * Otherwise, under stty tostop, processes will stop in the wrong | |
1301 | * pgrp, with no way for the shell to get them going again. -IAN! | |
1302 | */ | |
1303 | void | |
1304 | doeval(v) | |
1305 | Char **v; | |
1306 | { | |
1307 | Char **oevalvec; | |
1308 | Char *oevalp; | |
1309 | int odidfds; | |
1310 | jmp_buf osetexit; | |
1311 | int my_reenter; | |
1312 | Char **gv; | |
1313 | int saveIN; | |
1314 | int saveOUT; | |
1315 | int saveDIAG; | |
1316 | int oSHIN; | |
1317 | int oSHOUT; | |
1318 | int oSHDIAG; | |
1319 | ||
1320 | oevalvec = evalvec; | |
1321 | oevalp = evalp; | |
1322 | odidfds = didfds; | |
1323 | oSHIN = SHIN; | |
1324 | oSHOUT = SHOUT; | |
1325 | oSHDIAG = SHDIAG; | |
1326 | ||
1327 | v++; | |
1328 | if (*v == 0) | |
1329 | return; | |
1330 | gflag = 0, tglob(v); | |
1331 | if (gflag) { | |
1332 | gv = v = globall(v); | |
1333 | gargv = 0; | |
1334 | if (v == 0) | |
1335 | stderror(ERR_NOMATCH); | |
1336 | v = copyblk(v); | |
1337 | } | |
1338 | else { | |
1339 | gv = NULL; | |
1340 | v = copyblk(v); | |
1341 | trim(v); | |
1342 | } | |
1343 | ||
1344 | saveIN = dcopy(SHIN, -1); | |
1345 | saveOUT = dcopy(SHOUT, -1); | |
1346 | saveDIAG = dcopy(SHDIAG, -1); | |
1347 | ||
1348 | getexit(osetexit); | |
1349 | ||
1350 | if ((my_reenter = setexit()) == 0) { | |
1351 | evalvec = v; | |
1352 | evalp = 0; | |
1353 | SHIN = dcopy(0, -1); | |
1354 | SHOUT = dcopy(1, -1); | |
1355 | SHDIAG = dcopy(2, -1); | |
1356 | didfds = 0; | |
1357 | process(0); | |
1358 | } | |
1359 | ||
1360 | evalvec = oevalvec; | |
1361 | evalp = oevalp; | |
1362 | doneinp = 0; | |
1363 | didfds = odidfds; | |
1364 | (void) close(SHIN); | |
1365 | (void) close(SHOUT); | |
1366 | (void) close(SHDIAG); | |
1367 | SHIN = dmove(saveIN, oSHIN); | |
1368 | SHOUT = dmove(saveOUT, oSHOUT); | |
1369 | SHDIAG = dmove(saveDIAG, oSHDIAG); | |
1370 | ||
1371 | if (gv) | |
1372 | blkfree(gv); | |
1373 | resexit(osetexit); | |
1374 | if (my_reenter) | |
1375 | stderror(ERR_SILENT); | |
1376 | } |