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