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