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