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