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