📄 func.c
字号:
/*- * Copyright (c) 1980, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)func.c 8.1 (Berkeley) 5/31/93";#endif /* not lint */#include <sys/types.h>#include <sys/stat.h>#include <signal.h>#include <locale.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#if __STDC__# include <stdarg.h>#else# include <varargs.h>#endif#include "csh.h"#include "extern.h"#include "pathnames.h"extern char **environ;static int zlast = -1;static void islogin __P((void));static void reexecute __P((struct command *));static void preread __P((void));static void doagain __P((void));static void search __P((int, int, Char *));static int getword __P((Char *));static int keyword __P((Char *));static void toend __P((void));static void xecho __P((int, Char **));static void Unsetenv __P((Char *));struct biltins *isbfunc(t) struct command *t;{ register Char *cp = t->t_dcom[0]; register struct biltins *bp, *bp1, *bp2; static struct biltins label = {"", dozip, 0, 0}; static struct biltins foregnd = {"%job", dofg1, 0, 0}; static struct biltins backgnd = {"%job &", dobg1, 0, 0}; if (lastchr(cp) == ':') { label.bname = short2str(cp); return (&label); } if (*cp == '%') { if (t->t_dflg & F_AMPERSAND) { t->t_dflg &= ~F_AMPERSAND; backgnd.bname = short2str(cp); return (&backgnd); } foregnd.bname = short2str(cp); return (&foregnd); } /* * Binary search Bp1 is the beginning of the current search range. Bp2 is * one past the end. */ for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) { register i; bp = bp1 + ((bp2 - bp1) >> 1); if ((i = *cp - *bp->bname) == 0 && (i = Strcmp(cp, str2short(bp->bname))) == 0) return bp; if (i < 0) bp2 = bp; else bp1 = bp + 1; } return (0);}voidfunc(t, bp) register struct command *t; register struct biltins *bp;{ int i; xechoit(t->t_dcom); setname(bp->bname); i = blklen(t->t_dcom) - 1; if (i < bp->minargs) stderror(ERR_NAME | ERR_TOOFEW); if (i > bp->maxargs) stderror(ERR_NAME | ERR_TOOMANY); (*bp->bfunct) (t->t_dcom, t);}void/*ARGSUSED*/doonintr(v, t) Char **v; struct command *t;{ register Char *cp; register Char *vv = v[1]; if (parintr == SIG_IGN) return; if (setintr && intty) stderror(ERR_NAME | ERR_TERMINAL); cp = gointr; gointr = 0; xfree((ptr_t) cp); if (vv == 0) { if (setintr) (void) sigblock(sigmask(SIGINT)); else (void) signal(SIGINT, SIG_DFL); gointr = 0; } else if (eq((vv = strip(vv)), STRminus)) { (void) signal(SIGINT, SIG_IGN); gointr = Strsave(STRminus); } else { gointr = Strsave(vv); (void) signal(SIGINT, pintr); }}void/*ARGSUSED*/donohup(v, t) Char **v; struct command *t;{ if (intty) stderror(ERR_NAME | ERR_TERMINAL); if (setintr == 0) { (void) signal(SIGHUP, SIG_IGN); }}void/*ARGSUSED*/dozip(v, t) Char **v; struct command *t;{ ;}voidprvars(){ plist(&shvhed);}void/*ARGSUSED*/doalias(v, t) Char **v; struct command *t;{ register struct varent *vp; register Char *p; v++; p = *v++; if (p == 0) plist(&aliases); else if (*v == 0) { vp = adrof1(strip(p), &aliases); if (vp) { blkpr(cshout, vp->vec); fputc('\n', cshout); } } else { if (eq(p, STRalias) || eq(p, STRunalias)) { setname(vis_str(p)); stderror(ERR_NAME | ERR_DANGER); } set1(strip(p), saveblk(v), &aliases); }}void/*ARGSUSED*/unalias(v, t) Char **v; struct command *t;{ unset1(v, &aliases);}void/*ARGSUSED*/dologout(v, t) Char **v; struct command *t;{ islogin(); goodbye();}void/*ARGSUSED*/dologin(v, t) Char **v; struct command *t;{ islogin(); rechist(); (void) signal(SIGTERM, parterm); (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL); untty(); xexit(1);}static voidislogin(){ if (chkstop == 0 && setintr) panystop(0); if (loginsh) return; stderror(ERR_NOTLOGIN);}voiddoif(v, kp) Char **v; struct command *kp;{ register int i; register Char **vv; v++; i = expr(&v); vv = v; if (*vv == NULL) stderror(ERR_NAME | ERR_EMPTYIF); if (eq(*vv, STRthen)) { if (*++vv) stderror(ERR_NAME | ERR_IMPRTHEN); setname(vis_str(STRthen)); /* * If expression was zero, then scan to else, otherwise just fall into * following code. */ if (!i) search(T_IF, 0, NULL); return; } /* * Simple command attached to this if. Left shift the node in this tree, * munging it so we can reexecute it. */ if (i) { lshift(kp->t_dcom, vv - kp->t_dcom); reexecute(kp); donefds(); }}/* * Reexecute a command, being careful not * to redo i/o redirection, which is already set up. */static voidreexecute(kp) register struct command *kp;{ kp->t_dflg &= F_SAVE; kp->t_dflg |= F_REPEAT; /* * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set * pgrp's as the jobs would then have no way to get the tty (we can't give * it to them, and our parent wouldn't know their pgrp, etc. */ execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);}void/*ARGSUSED*/doelse(v, t) Char **v; struct command *t;{ search(T_ELSE, 0, NULL);}void/*ARGSUSED*/dogoto(v, t) Char **v; struct command *t;{ Char *lp; gotolab(lp = globone(v[1], G_ERROR)); xfree((ptr_t) lp);}voidgotolab(lab) Char *lab;{ register struct whyle *wp; /* * While we still can, locate any unknown ends of existing loops. This * obscure code is the WORST result of the fact that we don't really parse. */ zlast = T_GOTO; for (wp = whyles; wp; wp = wp->w_next) if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) { search(T_BREAK, 0, NULL); btell(&wp->w_end); } else bseek(&wp->w_end); search(T_GOTO, 0, lab); /* * Eliminate loops which were exited. */ wfree();}void/*ARGSUSED*/doswitch(v, t) Char **v; struct command *t;{ register Char *cp, *lp; v++; if (!*v || *(*v++) != '(') stderror(ERR_SYNTAX); cp = **v == ')' ? STRNULL : *v++; if (*(*v++) != ')') v--; if (*v) stderror(ERR_SYNTAX); search(T_SWITCH, 0, lp = globone(cp, G_ERROR)); xfree((ptr_t) lp);}void/*ARGSUSED*/dobreak(v, t) Char **v; struct command *t;{ if (whyles) toend(); else stderror(ERR_NAME | ERR_NOTWHILE);}void/*ARGSUSED*/doexit(v, t) Char **v; struct command *t;{ if (chkstop == 0 && (intty || intact) && evalvec == 0) panystop(0); /* * Don't DEMAND parentheses here either. */ v++; if (*v) { set(STRstatus, putn(expr(&v))); if (*v) stderror(ERR_NAME | ERR_EXPRESSION); } btoeof(); if (intty) (void) close(SHIN);}void/*ARGSUSED*/doforeach(v, t) Char **v; struct command *t;{ register Char *cp, *sp; register struct whyle *nwp; v++; sp = cp = strip(*v); if (!letter(*sp)) stderror(ERR_NAME | ERR_VARBEGIN); while (*cp && alnum(*cp)) cp++; if (*cp) stderror(ERR_NAME | ERR_VARALNUM); if ((cp - sp) > MAXVARLEN) stderror(ERR_NAME | ERR_VARTOOLONG); cp = *v++; if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') stderror(ERR_NAME | ERR_NOPAREN); v++; gflag = 0, tglob(v); v = globall(v); if (v == 0) stderror(ERR_NAME | ERR_NOMATCH); nwp = (struct whyle *) xcalloc(1, sizeof *nwp); nwp->w_fe = nwp->w_fe0 = v; gargv = 0; btell(&nwp->w_start); nwp->w_fename = Strsave(cp); nwp->w_next = whyles; nwp->w_end.type = F_SEEK; whyles = nwp; /* * Pre-read the loop so as to be more comprehensible to a terminal user. */ zlast = T_FOREACH; if (intty) preread(); doagain();}void/*ARGSUSED*/dowhile(v, t) Char **v; struct command *t;{ register int status; register bool again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) && whyles->w_fename == 0; v++; /* * Implement prereading here also, taking care not to evaluate the * expression before the loop has been read up from a terminal. */ if (intty && !again) status = !exp0(&v, 1); else status = !expr(&v); if (*v) stderror(ERR_NAME | ERR_EXPRESSION); if (!again) { register struct whyle *nwp = (struct whyle *) xcalloc(1, sizeof(*nwp)); nwp->w_start = lineloc; nwp->w_end.type = F_SEEK; nwp->w_end.f_seek = 0; nwp->w_next = whyles; whyles = nwp; zlast = T_WHILE; if (intty) { /* * The tty preread */ preread(); doagain(); return; } } if (status) /* We ain't gonna loop no more, no more! */ toend();}static voidpreread(){ whyles->w_end.type = I_SEEK; if (setintr) (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); search(T_BREAK, 0, NULL); /* read the expression in */ if (setintr) (void) sigblock(sigmask(SIGINT)); btell(&whyles->w_end);}void/*ARGSUSED*/doend(v, t) Char **v; struct command *t;{ if (!whyles) stderror(ERR_NAME | ERR_NOTWHILE); btell(&whyles->w_end); doagain();}void/*ARGSUSED*/docontin(v, t) Char **v; struct command *t;{ if (!whyles) stderror(ERR_NAME | ERR_NOTWHILE); doagain();}static voiddoagain(){ /* Repeating a while is simple */ if (whyles->w_fename == 0) { bseek(&whyles->w_start); return; } /* * The foreach variable list actually has a spurious word ")" at the end of * the w_fe list. Thus we are at the of the list if one word beyond this * is 0. */ if (!whyles->w_fe[1]) { dobreak(NULL, NULL); return; } set(whyles->w_fename, Strsave(*whyles->w_fe++)); bseek(&whyles->w_start);}voiddorepeat(v, kp) Char **v; struct command *kp;{ register int i; register sigset_t omask = 0; i = getn(v[1]); if (setintr) omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); lshift(v, 2); while (i > 0) { if (setintr) (void) sigsetmask(omask); reexecute(kp); --i; } donefds(); if (setintr) (void) sigsetmask(omask);}void/*ARGSUSED*/doswbrk(v, t) Char **v; struct command *t;{ search(T_BRKSW, 0, NULL);}intsrchx(cp) register Char *cp;{ register struct srch *sp, *sp1, *sp2; register i; /* * Binary search Sp1 is the beginning of the current search range. Sp2 is * one past the end. */ for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) { sp = sp1 + ((sp2 - sp1) >> 1); if ((i = *cp - *sp->s_name) == 0 && (i = Strcmp(cp, str2short(sp->s_name))) == 0) return sp->s_value; if (i < 0) sp2 = sp; else sp1 = sp + 1; } return (-1);}static Char Stype;static Char *Sgoal;/*VARARGS2*/static voidsearch(type, level, goal) int type; register int level; Char *goal;{ Char wordbuf[BUFSIZ]; register Char *aword = wordbuf; register Char *cp; Stype = type; Sgoal = goal; if (type == T_GOTO) { struct Ain a; a.type = F_SEEK; a.f_seek = 0; bseek(&a); } do { if (intty && fseekp == feobp && aret == F_SEEK) (void) fprintf(cshout, "? "), (void) fflush(cshout); aword[0] = 0; (void) getword(aword); switch (srchx(aword)) { case T_ELSE: if (level == 0 && type == T_IF) return; break; case T_IF: while (getword(aword)) continue; if ((type == T_IF || type == T_ELSE) && eq(aword, STRthen)) level++; break; case T_ENDIF: if (type == T_IF || type == T_ELSE) level--; break; case T_FOREACH: case T_WHILE: if (type == T_BREAK) level++; break; case T_END: if (type == T_BREAK) level--; break; case T_SWITCH: if (type == T_SWITCH || type == T_BRKSW) level++; break; case T_ENDSW: if (type == T_SWITCH || type == T_BRKSW) level--; break; case T_LABEL: if (type == T_GOTO && getword(aword) && eq(aword, goal)) level = -1; break; default: if (type != T_GOTO && (type != T_SWITCH || level != 0)) break; if (lastchr(aword) != ':') break; aword[Strlen(aword) - 1] = 0; if ((type == T_GOTO && eq(aword, goal)) || (type == T_SWITCH && eq(aword, STRdefault))) level = -1; break; case T_CASE: if (type != T_SWITCH || level != 0) break; (void) getword(aword); if (lastchr(aword) == ':') aword[Strlen(aword) - 1] = 0; cp = strip(Dfix1(aword)); if (Gmatch(goal, cp)) level = -1; xfree((ptr_t) cp); break; case T_DEFAULT: if (type == T_SWITCH && level == 0) level = -1; break; } (void) getword(NULL); } while (level >= 0);}static intgetword(wp) register Char *wp;{ register int found = 0; register int c, d; int kwd = 0; Char *owp = wp; c = readc(1); d = 0; do { while (c == ' ' || c == '\t') c = readc(1); if (c == '#') do c = readc(1); while (c >= 0 && c != '\n'); if (c < 0) goto past; if (c == '\n') { if (wp) break; return (0); } unreadc(c); found = 1; do { c = readc(1); if (c == '\\' && (c = readc(1)) == '\n')
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -