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