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