From: pfalstad@phoenix.Princeton.EDU (Paul John Falstad) Newsgroups: alt.sources Subject: zsh - ksh/tcsh-like shell (part 5 of 8) Message-ID: <4746@idunno.Princeton.EDU> Date: 14 Dec 90 23:32:05 GMT ---cut here---cut here---cut here--- -{ -list2 l2 = (list2) alloc(sizeof *l2); -int iter = 0; - - for (;;) - { - if (peek == BANG) - { - l2->flags |= PFLAG_NOT; - matchit(); - } - else if (peek == TIME) - { - l2->flags |= PFLAG_TIMED; - matchit(); - } - else if (peek == COPROC) - { - l2->flags |= PFLAG_COPROC; - matchit(); - } - else - break; - iter = 1; - } - if (!(l2->left = parpline())) - { - free(l2); - if (!errflag && iter) - { - zerr("parse error: pipeline expected"); - errflag = 1; - } - return NULL; - } - if (peek == DAMPER || peek == DBAR) - { - l2->type = (peek == DAMPER) ? ANDNEXT : ORNEXT; - matchit(); - while (peek == NEWLIN) - matchit(); - if (!(l2->right = parlist2())) - { - if (!errflag) - { - zerr("invalid null command"); - errflag = 1; - } - freepline(l2->left); - free(l2); - return NULL; - } - } - else - { - l2->type = END; - l2->right = NULL; - } - return l2; -} - -/* parse a pipeline */ - -pline parpline(void) -{ -pline p = (pline) alloc(sizeof *p); - - if (!(p->left = parcmd())) - { - free(p); - return NULL; - } - if (peek == HERR) - { - freecmd(p->left); - free(p); - return NULL; - } - if (peek == BAR || peek == BARAMP) - { - if (peek == BARAMP) - { - struct fnode *f; - - f = alloc(sizeof *f); - f->type = MERGEOUT; - f->fd1 = 2; - f->u.fd2 = 1; - addnode(p->left->redir,f); - } - matchit(); - while (peek == NEWLIN) - matchit(); - p->type = PIPE; - if (!(p->right = parpline())) - { - if (!errflag) - { - zerr("invalid null command"); - errflag = 1; - } - freecmd(p->left); - free(p); - return NULL; - } - } - else - { - p->type = END; - p->right = NULL; - } - return p; -} - -/* parse a command */ - -comm parcmd(void) -{ -comm c = (comm) alloc(sizeof *c); -list l; -char *str; -int flag,iter = 0; - - incmd = 0; - c->left = NULL; - c->cmd = NULL; - c->args = newtable(); - c->redir = newtable(); - c->type = SIMPLE; - c->vars = NULL; - if (peek == EOF) - return NULL; -foo: - switch (peek) - { - case HERR: - return NULL; - case ENVSTRING: - if (!c->vars) - c->vars = newtable(); /* FIX */ - for (str = tstr; *str != '='; str++); - *str++ = '\0'; - addnode(c->vars,tstr); - addnode(c->vars,strdup(str)); - matchit(); - goto foo; - case FOR: - incmd = 1; - matchit(); - if (parfor(c,1)) - return NULL; - break; - case SELECT: - incmd = 1; - matchit(); - if (parfor(c,0)) - return NULL; - break; - case CASE: - incmd = 1; - matchit(); - if (parcase(c)) - return NULL; - break; - case IF: - matchit(); - if (parif(c)) - return NULL; - break; - case WHILE: - matchit(); - if (parwhile(c,0)) - return NULL; - break; - case UNTIL: - matchit(); - if (parwhile(c,1)) - return NULL; - break; - case REPEAT: - incmd = 1; - matchit(); - if (parrepeat(c)) - return NULL; - break; - case INPAR: - matchit(); - c->type = SUBSH; - if (!(c->left = parlist(1))) - { - freecmd(c); - return NULL; - } - if (peek != OUTPAR) - { - freecmd(c); - zerr("parse error: '}' expected"); - return NULL; - } - matchit(); - break; - case INBRACE: - matchit(); - c->type = CURSH; - if (!(c->left = parlist(1))) - { - freecmd(c); - return NULL; - } - if (peek != OUTBRACE) - { - freecmd(c); - zerr("parse error: '}' expected"); - return NULL; - } - matchit(); - break; - case FUNC: - matchit(); - str = tstr; - if (peek != STRING && peek != ENVSTRING) - { - c->cmd = strdup("function"); - incmd = 1; - if (isredir()) - goto jump1; - else - goto jump2; - } - do - matchit(); - while (peek == NEWLIN); - if (peek != INBRACE) - { - freecmd(c); - zerr("parse error: '{' expected"); - return NULL; - } - matchit(); - flag = peek == OUTBRACE; - if (!(l = parlist(1))) - { - freecmd(c); - return NULL; - } - if (peek != OUTBRACE) - { - freelist(l); - freecmd(c); - zerr("parse error: '}' expected"); - return NULL; - } - matchit(); - settrap(str,flag); - addhnode(str,l,shfunchtab,freeshfunc); - c->cmd = strdup(""); - c->type = SIMPLE; - break; - case EXEC: - c->flags |= CFLAG_EXEC; - matchit(); - iter = 1; - goto foo; - case COMMAND: - c->flags |= CFLAG_COMMAND; - matchit(); - iter = 1; - goto foo; - default: -jump1: - if (isredir()) - { - if (parredir(c)) - { - freecmd(c); - return NULL; - } - goto foo; - } - if (!(peek == STRING || peek == ENVSTRING)) - { - if (full(c->redir)) - { - c->cmd = strdup("cat"); - return c; - } - if (c->vars) - { - c->cmd = strdup(""); - return c; - } - free(c->args); - free(c->redir); - free(c); - if (iter && !errflag) - { - errflag = 1; - zerr("parse error: command expected"); - } - return NULL; - } -jump2: - while (peek == STRING || peek == ENVSTRING || isredir()) - if (isredir()) - { - if (parredir(c)) - { - freecmd(c); - return NULL; - } - } - else - { - if (tstr[0] == Inpar && tstr[1] == Outpar && !tstr[2]) - { - free(tstr); - incmd = 0; - matchit(); - if (full(c->args)) - { - zerr("illegal function definition"); - freecmd(c); - return NULL; - } - while (peek == NEWLIN) - matchit(); - if (peek != INBRACE) - { - freecmd(c); - zerr("parse error: '{' expected"); - return NULL; - } - matchit(); - flag = peek == OUTBRACE; - if (!(l = parlist(1))) - { - freecmd(c); - return NULL; - } - if (peek != OUTBRACE) - { - freelist(l); - freecmd(c); - zerr("parse error: '}' expected"); - return NULL; - } - matchit(); - settrap(c->cmd,flag); - addhnode(c->cmd,l,shfunchtab,freeshfunc); - c->cmd = strdup(""); - c->type = SIMPLE; - incmd = 0; - return c; - } - if (peek == ENVSTRING && (!incmd || opts[KEYWORD] == OPT_SET)) - { - if (!c->vars) - c->vars = newtable(); /* FIX */ - for (str = tstr; *str != '='; str++); - *str++ = '\0'; - addnode(c->vars,tstr); - addnode(c->vars,strdup(str)); - } - else if (c->cmd) - addnode(c->args,tstr); - else - { - c->cmd = tstr; - incmd = 1; - } - matchit(); - } - break; - } - while (isredir()) - if (parredir(c)) - { - freecmd(c); - return NULL; - } - incmd = 0; - if (peek == HERR) - { - freecmd(c); - return NULL; - } - return c; -} - -/* != 0 if peek is a redirection operator */ - -int isredir(void) -{ - return (peek >= OUTANG && peek <= DOUTANGAMPBANG); -} - -/* get fd associated with str */ - -int getfdstr(char *s) -{ - if (s[1]) - return -1; - if (isdigit(*s)) - return *s-'0'; - if (*s == 'p') - return -2; - return -1; -} - -int parredir(comm c) -{ -struct fnode *fn = (struct fnode *) alloc(sizeof *fn); -int pk = peek,ic = incmd,mrg2 = 0; - - fn->type = peek-OUTANG+WRITE; - if (peek == OUTANGAMP) - fn->type = MERGEOUT; - if (peekfd != -1) - fn->fd1 = peekfd; - else if (peek <= DOUTANGBANG || peek >= OUTANGAMP) - fn->fd1 = 1; - else - fn->fd1 = 0; - incmd = 1; - matchit(); - incmd = ic; - if (peek != STRING) - { - zerr("parse error: filename expected"); - return 1; - } - - if ((*tstr == Inang || *tstr == Outang) && tstr[1] == Inpar) - { - if (fn->type == WRITE) - fn->type = OUTPIPE; - else if (fn->type == READ) - fn->type = INPIPE; - else - { - zerr("parse error: bad process redirection"); - return 1; - } - fn->u.name = tstr; - } - else if (fn->type == HEREDOC) - fn->u.fd2 = gethere(tstr); - else if (pk >= OUTANGAMP && getfdstr(tstr) == -1) - { - mrg2 = 1; - fn->u.name = tstr; - fn->type = pk-OUTANGAMP; - } - else if (pk > OUTANGAMPBANG) - { - zerr("parse error: filename expected"); - return 1; - } - else if (pk == OUTANGAMPBANG) - { - struct fnode *fe = alloc(sizeof *fe); - - fe->fd1 = fn->fd1; - fe->type = CLOSE; - addnode(c->redir,fe); - fn->u.fd2 = getfdstr(tstr); - if (fn->u.fd2 == -2) - fn->u.fd2 = spout; - fn->type = MERGEOUT; - } - else if (fn->type == MERGE || fn->type == MERGEOUT) - { - if (*tstr == '-') - fn->type = CLOSE; - else - { - fn->u.fd2 = getfdstr(tstr); - if (fn->u.fd2 == -2) - fn->u.fd2 = (pk == OUTANGAMP) ? spout : spin; - } - } - else - fn->u.name = tstr; - addnode(c->redir,fn); - if (mrg2) - { - struct fnode *fe = alloc(sizeof *fe); - - fe->fd1 = 2; - fe->u.fd2 = fn->fd1; - fe->type = MERGEOUT; - addnode(c->redir,fe); - } - matchit(); - return 0; -} - End of parse.c echo parse.pro 1>&2 sed 's/^-//' >parse.pro <<'End of parse.pro' -list parlist(int nest); -list parlist1(int nest); -list2 parlist2(void); -pline parpline(void); -comm parcmd(void); -int isredir(void); -int getfdstr(char *s); -int parredir(comm c); End of parse.pro echo subst.c 1>&2 sed 's/^-//' >subst.c <<'End of subst.c' -/* - - subst.c - various substitution - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" -#include -#define MAXPATHLEN 1024 - -#define magicerr() { if (magic) putc('\n',stderr); } - -/* do substitutions before fork */ - -void prefork(table list) -{ -Node node = list->first; - - while (node) - { - char *str,*str3; - - str = str3 = node->dat; - if (!magic && str[1] == Inpar && (*str == Inang || - *str == Outang || *str == Equals)) - { - if (*str == Inang) - node->dat = getoutproc(str+2); /* <(...) */ - else if (*str == Equals) - node->dat = getoutputfile(str+2); /* =(...) */ - else - node->dat = getinproc(str+2); /* >(...) */ - free(str); - if (!node->dat) - { - zerr("parse error in process substitution"); - errflag = 1; - return; - } - } - else while (*str) - { - if (*str == String || *str == Qstring) - if (str[1] != Inpar) - if (str[1] == '*' || str[1] == Star) - parminsall(list,&node,&str,&str3); /* $* */ - else if (str[1] == Inbrack) - { - arithsuber((void **) &str,&str3); /* $[...] */ - if (magic) - magic = 2; - node->dat = str3; - } - else - { - parmsuber(str,&str3); /* $foo */ - node->dat = str = str3; - if (errflag) - return; - continue; - } - str++; - if (errflag) - return; - } - node = node->next; - } -} - -void postfork(table list,int globstat) -{ -Node node = list->first; -int glb = 1; - - if (isset(NOGLOBOPT) || globstat != GLOB) - glb = 0; - while (node) - { - char *str,*str3; - - str = str3 = node->dat; - while (*str) - { - if (((*str == String || *str == Qstring) && str[1] == Inpar) || - *str == Tick || *str == Qtick) - comminsall(list,&node,&str,&str3); /* `...`,$(...) */ - str++; - if (errflag) - return; - } - - /* now we remove the Nulargs tokens if this is not a null - arguments. The lexical analyzer throws these in so that - zsh will not look at this: - - $PA"TH" - - and expand it to $PATH. But after parameter substitution - these are only a nuisance, so we remove them. */ - - if (*(char *) node->dat) - remnulargs(node->dat); - - if (unset(IGNOREBRACES)) - while (hasbraces(node->dat)) - xpandbraces(list,&node); - filesub(&node->dat); - if (errflag) - return; - if (glb) - { - if (haswilds(node->dat)) - glob(list,&node); - if (errflag) - return; - } - else if (globstat == MOSTGLOB && *(char *) node->dat != '-') - glb = 1; - node = node->next; - } -} - -/* strdup, but returns "Nularg" if this is a null string */ - -void *nstrdup(void *s) -{ -char *t = s,u[] = {Nularg,'\0'}; - - if (!*t) - return strdup(u); - return strdup(t); -} - -/* $* */ - -void parminsall(table l,Node *nn,char **aptr,char **bptr) -{ -char *str3 = *aptr,*str = *bptr; -Node n = *nn,where = n->last; -table pl; - - if (magic) - magic = 2; - *str3 = '\0'; - str3 += 2; - remnode(l,n); - pl = duptable(pparms,nstrdup); - free(getnode(pl)); - if (pl->first) /* if $# > 1 */ - { - char *ptr; - Node tmp; - - ptr = pl->first->dat; - pl->first->dat = dyncat(str,ptr); - free(ptr); - ptr = pl->last->dat; - *bptr = pl->last->dat = dyncat(ptr,str3); - *aptr = *bptr+strlen(str)+strlen(ptr)-1; - free(ptr); - tmp = where->next; - where->next = pl->first; - pl->last->next = tmp; - pl->first->last = where; - if (tmp) - tmp->last = pl->last; - else - l->last = pl->last; - *nn = pl->last; - } - else /* just remove the $* */ - { - insnode(l,where,*bptr = dyncat(str,str3)); - *nn = where->next; - *aptr = *bptr+strlen(str)-1; - } -} - -char *dynread(char stop) -{ -int bsiz = 256,ct = 0,c; -char *buf = zalloc(bsiz),*ptr; - - ptr = buf; - while ((c = hgetc()) != stop) - { - *ptr++ = c; - if (++ct == bsiz) - { - buf = realloc(buf,bsiz *= 2); - ptr = buf+ct; - } - } - *ptr = 0; - return buf; -} - -int filesub(void **namptr) -{ -char *str = *namptr,*cnam; - - if (*str == Tilde && str[1] != '=') - { - if (str[1] == '+') - { - char *foo = strdup(cwd),*t = str; /* ~+ */ - - str+=2; - modify((void **) &foo,&str); - *namptr = dyncat(cwd,str); - free(foo); - free(t); - return 1; - } - else if (str[1] == '-') /* ~- */ - { - char *foo,*t = str; - - if (cnam = getparm("OLDPWD")) - foo = cnam; - else - foo = cwd; - str += 2; - foo = strdup(foo); - modify((void **) &foo,&str); - *namptr = dyncat(foo,str); - free(t); - free(foo); - return 1; - } - if (isalpha(str[1])) /* ~foo */ - { - char *ptr,*home; - - for (ptr = ++str; *ptr && !istok(*ptr) && (isalnum(*ptr) || *ptr == '-'); ptr++) - if (*ptr == '-') - *ptr = '-'; - if (!(home = gethome(str,ptr-str))) - { - if (magic) - home = completehome(str,ptr-str); - if (!home) - { - magicerr(); - zerr("user not found: %l",ptr-str,str); - errflag = 1; - return 0; - } - } - modify((void **) &home,&ptr); - *namptr = dyncat(home,ptr); - free(home); - free(str-1); - return 1; - } - else if (str[1] == '/') /* ~/foo */ - { - *namptr = dyncat(home,str+1); - free(str); - return 1; - } - else if (!str[1]) /* ~ by itself */ - { - free(str); - *namptr = strdup(home); - return 1; - } - } - if (*str == Equals && !istok(str[1]) && (isalnum(str[1]) || str[1] == '-')) - { - char *ptr,*s,*ds; - int val; - - untokenize(str); - if (isalpha(str[1])) /* =foo */ - { - struct chnode *chn; - struct anode *t; - char sav,*pp; - - for (pp = str+1; *pp && *pp != ':'; pp++); - sav = *pp; - *pp = '\0'; - if ((t = gethnode(str+1,alhtab)) && t->cmd) - if (t->cmd >= 0) - cnam = strdup(t->text); - else - { - magicerr(); - zerr("%s: shell reserved word",str+1); - errflag = 1; - return 0; - } - else if (chn = gethnode(str+1,chtab)) - if (chn->type != BUILTIN) - cnam = strdup(chn->u.nam); - else - { - magicerr(); - zerr("%s: shell built-in command",str+1); - errflag = 1; - return 0; - } - else if (!(cnam = findcmd(str+1))) - { - magicerr(); - zerr("%s not found",str+1); - errflag = 1; - return 0; - } - *namptr = cnam; - if ((*pp = sav) == ':') - { - modify(namptr,&pp); - s = *namptr; - *namptr = dyncat(*namptr,pp); - free(s); - } - free(str); - return 1; - } - if (str[1] == '-') /* =- */ - { - val = -1; - ptr = str+2; - } - else - val = strtol(str+1,&ptr,10); /* =# */ - ds = dstackent(val); - if (!ds) - return 1; - s = strdup(ds); - modify((void **) &s,&ptr); - *namptr = dyncat(s,ptr); - free(s); - free(str); - return 1; - } - return 0; -} - -/* get a user's directory */ - -char *gethome(char *user,int len) -{ -char sav,*str; -struct passwd *pw; - - sav = user[len]; - user[len] = '\0'; - if (!(pw = getpwnam(user))) - { - user[len] = sav; - return NULL; - } - str = xsymlink(pw->pw_dir); - user[len] = sav; - return str; -} - -/* complete a user and try to get his home directory */ - -char *completehome(char *user,int len) -{ -FILE *in; -char buf[MAXPATHLEN],*str; - - sprintf(buf,"%s/.zfriends",getparm("HOME")); - if (!(in = fopen(buf,"r"))) - return NULL; - while (fgetline(buf,MAXPATHLEN,in)) - if (!strncmp(user,buf,len)) - if (str = gethome(buf,strlen(buf))) - { - fclose(in); - return str; - } - fclose(in); - return NULL; -} - -/* get the value of the parameter specified by the first len - characters of s */ - -char *getsparmval(char *s,int len) -{ -char sav = s[len]; -char *val; -char buf[50]; -int t0; - - if (len == 1 && (istok(*s) || !isalnum(*s))) - switch(*s) - { - case Pound: - case '#': - sprintf(buf,"%d",ppcount()); - return strdup(buf); - case '-': - for (val = buf, t0 = ' '; t0 <= 'z'; t0++) - if (opts[t0] == OPT_SET) - *val++ = t0; - *val = '\0'; - return strdup(buf); - case '?': - case Quest: - sprintf(buf,"%d",lastval); - return strdup(buf); - case '$': - case String: - sprintf(buf,"%d",procnum); - return strdup(buf); - case '!': - sprintf(buf,"%d",proclast); - return strdup(buf); - default: - return NULL; - } - s[len] = '\0'; - if (isdigit(*s)) - { - int num; - Node node; - - num = atoi(s); - s[len] = sav; - for (node = pparms->first; node && num; num--,node = node->next); - return (node) ? strdup(node->dat) : NULL; - } - val = getparm(s); - s[len] = sav; - return (val) ? strdup(val) : NULL; -} - -/* set the parameter associated with the first len characters of s - to v. */ - -void setparml(char *s,int len,char *v) -{ -char c; - - c = s[len]; - s[len] = 0; - if (isdigit(*s)) - { - int num; - Node node; - - num = atoi(s); - for (node = pparms->first; node && num; num--,node = node->next); - if (node) - { - free(node->dat); - node->dat = v; - } - else - { - while (num--) - addnode(pparms,strdup("")); - addnode(pparms,v); - } - } - else - setparm(strdup(s),v,0,0); - s[len] = c; -} - -/* `...`, $(...) */ - -void comminsall(table l,Node *nn,char **aptr,char **bptr) -{ -char *str3 = *aptr,*str = *bptr,*str2; -Node n = *nn,where = n->last; -table pl; -int s31 = (*str3 == Qtick || *str3 == Qstring); - - if (magic) magic = 2; - if (*str3 == Tick || *str3 == Qtick) - { - *str3 = '\0'; - for (str2 = ++str3; *str3 != Tick && *str3 != Qtick; str3++); - *str3++ = '\0'; - } - else - { - *str3++ = '\0'; - for (str2 = ++str3; *str3 != Outpar; str3++); - *str3++ = '\0'; - } - remnode(l,n); - if (!(pl = getoutput(str2,s31))) - { - magicerr(); - zerr("parse error in command substitution"); - errflag = 1; - return; - } - if (pl->first) - { - char *ptr; - Node tmp; - - ptr = pl->first->dat; - pl->first->dat = dyncat(str,ptr); - free(ptr); - ptr = pl->last->dat; - *bptr = pl->last->dat = dyncat(ptr,str3); - *aptr = *bptr+strlen(str)+strlen(ptr)-1; - free(ptr); - tmp = where->next; - where->next = pl->first; - pl->last->next = tmp; - pl->first->last = where; - if (tmp) - tmp->last = pl->last; - else - l->last = pl->last; - /* free(tmp); */ - *nn = pl->last; - free(pl); - } - else - { - insnode(l,where,*bptr = dyncat(str,str3)); - *nn = where->next; - *aptr = *bptr+strlen(str)-1; - } -} - -/* do simple parameter substitution */ - -/* - consider an argument like this: - - abcde${fgh:-ijk}lmnop - - aptr will point to the $. - *bptr,ostr will point to the a. - t will point to the f. - u will point to the i. - s will point to the l (eventually). -*/ - -void parmsuber(char *aptr,char **bptr) -{ -char *s = aptr,*t,*u,*val,*ostr = *bptr; -int brs; /* != 0 means ${...}, otherwise $... */ -int vlen; /* the length of the name of the parameter */ -int colf; /* != 0 means we found a colon after the name */ -int doub = 0; /* != 0 means we have %%, not %, or ##, not # */ - - /* first, remove the $ so *bptr is pointing to a null-terminated - string containing the stuff before the $. Then check for braces, - and get the parameter name and value, if any. */ - - *s++ = '\0'; - if (brs = (*s == '{' || *s == Inbrace)) - s++; - t = s; - if (istok(*s) || !isalnum(*s)) - { - val = getsparmval(t,vlen = 1); - if (!val) - { - *(char *) aptr = '$'; - if (brs) - s[-1] = '{'; - return; - } - s++; - } - else - { - while (!istok(*s) && (isalnum(*s) || *s == '_')) - s++; - val = getsparmval(t,vlen = s-t); - } - - /* val can still be NULL at this point. */ - - if (colf = *s == ':') - s++; - - /* check for ${..?...} or ${..=..} or one of those. Only works - if the name is in braces. */ - - if (brs && (*s == '-' || *s == '=' || *s == '?' || *s == '+' || *s == '#' || - *s == '%' || *s == Quest || *s == Pound)) - { - if (*s == s[1]) - { - s++; - doub = 1; - } - u = ++s; - if (brs) - while (*s != '}' && *s != Outbrace) - s++; - else - { - while (*s++); - s--; - } - *s = '\0'; - switch (u[-1]) - { - case '-': - if (!val || (colf && !*val)) - val = strdup(u); - break; - case '=': - if (!val || (colf && !*val)) - setparml(t,vlen,val = strdup(u)); - break; - case '?': - case Quest: - if (!val || (colf && !*val)) - { - magicerr(); - zerr("%s",(*u) ? u : "parameter not set"); - if (!interact) - exit(1); - else - errflag = 1; - return; - } - break; - case '+': - if (!val || (colf && !*val)) - val = strdup(""); - else - val = strdup(u); - break; - case '#': - case Pound: - if (!val) - val = strdup(""); - getmatch(&val,u,doub); - break; - case '%': - if (!val) - val = strdup(""); - getmatch(&val,u,doub+2); - break; - } - } - else /* no ${...=...} or anything, but possible modifiers. */ - { - if (!val) - { - if (isset(NOUNSET)) - { - zerr("parameter not set: %l",vlen,t); - errflag = 1; - return; - } - val = strdup(""); - } - if (colf) - { - s--; - modify((void **) &val,&s); /* do modifiers */ - } - if (brs) - { - if (*s != '}' && *s != Outbrace) - { - zerr("closing brace expected"); - errflag = 1; - return; - } - s++; - } - } - if (errflag) - { - free(ostr); - return; - } - *bptr = zalloc((char *) aptr-(*bptr)+strlen(val)+strlen(s)+1); - strcpy(*bptr,ostr); - strcat(*bptr,val); - strcat(*bptr,s); - free(ostr); - if (magic) - magic = 2; -} - -/* arithmetic substitution */ - -void arithsuber(void **aptr,char **bptr) -{ -char *s = *aptr,*t,buf[16]; -long v; - - *s = '\0'; - for (; *s != Outbrack; s++); - *s++ = '\0'; - v = matheval(*aptr+2); - sprintf(buf,"%ld",v); - t = zalloc(strlen(*bptr)+strlen(buf)+strlen(s)+1); - strcpy(t,*bptr); - strcat(t,buf); - strcat(t,s); - free(*bptr); - *bptr = t; -} - -void modify(void **str,char **ptr) -{ -char *ptr1,*ptr2,*ptr3,del,*lptr; -int gbal; - - while (**ptr == ':') - { - lptr = *ptr; - (*ptr)++; - gbal = 0; -here: - switch(*(*ptr)++) - { - case 'h': - while (remtpath(str) && gbal); - break; - case 'r': - while (remtext(str) && gbal); - break; - case 'e': - while (rembutext(str) && gbal); - break; - case 't': - while (remlpaths(str) && gbal); - break; - case 's': - if (last) - free(last); - if (rast) - free(rast); - ptr1 = *ptr; - del = *ptr1++; - for (ptr2 = ptr1; *ptr2 != del && *ptr2; ptr2++); - if (!*ptr2) - { - magicerr(); - zerr("bad subtitution"); - errflag = 1; - return; - } - *ptr2++ = '\0'; - for (ptr3 = ptr2; *ptr3 != del && *ptr3; ptr3++); - if (*ptr3) - *ptr3++ = '\0'; - last = strdup(ptr1); - rast = strdup(ptr2); - *ptr = ptr3; - case '&': - if (last && rast) - subststr(str,last,rast,gbal); - break; - case 'g': - gbal = 1; - goto here; - default: - *ptr = lptr; - return; - } - } -} - -/* get a directory stack entry */ - -char *dstackent(int val) -{ -Node node; - - if ((val < 0 && !dirstack->first) || !val--) - return cwd; - if (val < 0) - node = dirstack->last; - else - for (node = dirstack->first; node && val; val--,node = node->next); - if (!node) - { - magicerr(); - zerr("not enough dir stack entries."); - errflag = 1; - return NULL; - } - return node->dat; -} - -void execshfunc(comm comm) -{ -table tab,oldlocals; -Node n; -char *s; - - tab = pparms; - oldlocals = locallist; - locallist = newtable(); - for (n = tab->first; n; n = n->next); - pparms = comm->args; - runlist(comm->left); - retflag = 0; - comm->left = NULL; - pparms = tab; - while (s = getnode(locallist)) - { - void *z = remhnode(s,parmhtab); - if (z) - freepm(z); - } - free(locallist); - locallist = oldlocals; -} - -/* make an alias hash table node */ - -struct anode *mkanode(char *txt,int cmflag) -{ -struct anode *ptr = (void *) alloc(sizeof(struct anode)); - - ptr->text = txt; - ptr->cmd = cmflag; - ptr->inuse = 0; - return ptr; -} - -/* perform TAB substitution */ - -char *docompsubs(char *str,int *i) -{ -table fake,curt = curtab; -char *s,*t; -int ct = 0; - - for (s = str; *s; s++) - for (t = tokens; *t; t++) - if (*s == *t) - { - *s = (t-tokens)+Pound; - break; - } - curtab = NULL; - magic = 1; - fake = newtable(); - addnode(fake,str); - prefork(fake); - if (!errflag) - postfork(fake,GLOB); - if (fake->first && fake->first->next) - ct = 1; - t = s = buildline(fake); - free(fake); - rl_prep_terminal(); - if (errflag) - { - rl_on_new_line(); - rl_redisplay(); - errflag = 0; - magic = 0; - curtab = curt; - *i = 0; - return NULL; - } - *i = (magic == 2) + ct; - magic = 0; - curtab = curt; - untokenize(s); - return s; -} - -/* perform substitution on the command name */ - -void docmdsubs(char **str) -{ -table fake; -char *s = strdup(*str); - - fake = newtable(); - addnode(fake,*str); - prefork(fake); - if (!errflag) postfork(fake,GLOB); - if (errflag) - { - free(fake); - free(s); - return; - } - if (fake->first && fake->first->next) - { - zerr("%s: ambiguous",s); - errflag = 1; - free(fake); - free(s); - return; - } - *str = getnode(fake); - free(s); - free(fake); -} - -/* perform substitution on the variables */ - -void dovarsubs(char **str) -{ -table fake; -char *s; - - fake = newtable(); - addnode(fake,*str); - prefork(fake); - if (!errflag) postfork(fake,GLOB); - if (errflag) - return; - s = buildline(fake); - untokenize(s); - *str = s; - free(fake); -} - End of subst.c echo subst.pro 1>&2 sed 's/^-//' >subst.pro <<'End of subst.pro' -void prefork(table list); -void postfork(table list,int globstat); -void *nstrdup(void *s); -void parminsall(table l,Node *nn,char **aptr,char **bptr); -char *dynread(char stop); -int filesub(void **namptr); -char *gethome(char *user,int len); -char *completehome(char *user,int len); -char *getsparmval(char *s,int len); -void setparml(char *s,int len,char *v); -void comminsall(table l,Node *nn,char **aptr,char **bptr); -void parmsuber(char *aptr,char **bptr); -void arithsuber(void **aptr,char **bptr); -void modify(void **str,char **ptr); -char *dstackent(int val); -void execshfunc(comm comm); -struct anode *mkanode(char *txt,int cmflag); -char *docompsubs(char *str,int *i); -void docmdsubs(char **str); -void dovarsubs(char **str); End of subst.pro echo table.c 1>&2 sed 's/^-//' >table.c <<'End of table.c' -/* - - table.c - linked list and hash table management - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" - -/* get an empty linked list header */ - -table newtable() -{ -table list; - - list = alloc(sizeof(*list)); - list->first = 0; - list->last = (Node) list; - return list; -} - -/* get an empty hash table */ - -htable newhtable(int size) -{ -htable ret; - - ret = alloc(sizeof(struct xhtab)); - ret->hsize = size; - ret->nodes = alloc(size*sizeof(struct hnode *)); - return ret; -} - -/* Peter Weinberger's hash function */ - -int hasher(char *s) -{ -unsigned hash = 0,g; - - for (; *s; s++) - { - hash = (hash << 4) + *s; - if (g = hash & 0xf0000000) - { - hash ^= g; - hash ^= g >> 24; - } - } - return hash; -} - -/* add a node to a hash table */ - -void addhnode(char *nam,void *dat,htable ht,void (*freefunc)(void *)) -{ -int hval = hasher(nam) % ht->hsize; -struct hnode *hp = ht->nodes[hval],*hn; - - for (; hp; hp = hp->hchain) - if (!strcmp(hp->nam,nam)) - { - freefunc(hp->dat); - hp->dat = dat; - free(nam); - return; - } - hn = (void *) alloc(sizeof(struct hnode)); - hn->nam = nam; - hn->dat = dat; - hn->hchain = ht->nodes[hval]; - ht->nodes[hval] = hn; - if (++ht->ct == ht->hsize*4) - expandhtab(ht); -} - -/* expand hash tables when they get too many entries */ - -void expandhtab(htable ht) -{ -struct hnode *hp,**arr,**ha,*hn; -int osize = ht->hsize,nsize = osize*8; - - ht->hsize = nsize; - arr = ht->nodes; - ht->nodes = alloc(nsize*sizeof(struct hnode *)); - for (ha = arr; osize; osize--,ha++) - for (hn = *ha; hn; ) - { - addhnode(hn->nam,hn->dat,ht,NULL); - hp = hn->hchain; - free(hn); - hn = hp; - } - free(arr); -} - -/* get an entry in a hash table */ - -void *gethnode(char *nam,htable ht) -{ -int hval = hasher(nam) % ht->hsize; -struct hnode *hn = ht->nodes[hval]; - - for (; hn; hn = hn->hchain) - if (!strcmp(hn->nam,nam)) - return hn->dat; - return NULL; -} - -void freehtab(htable ht,void (*freefunc)(void *)) -{ -int val; -struct hnode *hn,**hptr = &ht->nodes[0],*next; - - for (val = ht->hsize; val; val--,hptr++) - for (hn = *hptr; hn; ) - { - next = hn->hchain; - freefunc(hn); - hn = next; - } -} - -/* remove a hash table entry and return a pointer to it */ - -void *remhnode(char *nam,htable ht) -{ -int hval = hasher(nam) % ht->hsize; -struct hnode *hn = ht->nodes[hval],*hp; -void *dat; - - if (!hn) - return NULL; - if (!strcmp(hn->nam,nam)) - { - ht->nodes[hval] = hn->hchain; - dat = hn->dat; - free(hn->nam); - free(hn); - ht->ct--; - return dat; - } - for (hp = hn, hn = hn->hchain; hn; hn = (hp = hn)->hchain) - if (!strcmp(hn->nam,nam)) - { - hp->hchain = hn->hchain; - dat = hn->dat; - free(hn->nam); - free(hn); - ht->ct--; - return dat; - } - return NULL; -} - -void *zalloc(int l) -{ -void *z; - - if (!(z = malloc(l))) - { - zerr("fatal error: out of memory: restarting"); - execl(MYSELF,"zsh","-f",(void *) 0); - exit(1); - } - return z; -} - -void *alloc(int l) -{ -void *z; - - if (!(z = calloc(l,1))) - { - zerr("fatal error: out of memory: restarting"); - execl(MYSELF,"zsh","-f",(void *) 0); - exit(1); - } - return z; -} - -/* add a node to the end of a linked list */ - -void addnode(table list,void *str) -{ - insnode(list,list->last,str); -} - -/* insert a node in a linked list after 'last' */ - -void insnode(table list,Node last,void *dat) -{ -Node tmp; - - tmp = last->next; - last->next = alloc(sizeof(*tmp)); - last->next->last = last; - last->next->dat = dat; - last->next->next = tmp; - if (tmp) - tmp->last = last->next; - else - list->last = last->next; -} - -/* remove a node from a linked list */ - -void *remnode(table list,Node nd) -{ -void *dat; - - nd->last->next = nd->next; - if (nd->next) - nd->next->last = nd->last; - else - list->last = nd->last; - free(nd); - dat = nd->dat; - return dat; -} - -/* delete a character in a string */ - -void chuck(char *str) -{ - while (str[0] = str[1]) - str++; -} - -/* get a node in a linked list */ - -void *getnode(table list) -{ -void *dat; -Node node = list->first; - - if (!node) - return NULL; - dat = node->dat; - list->first = node->next; - if (node->next) - node->next->last = (Node) list; - else - list->last = (Node) list; - free(node); - return dat; -} - -/* != 0 if the linked list has at least one entry */ - -int full(table list) -{ - return list->first != NULL; -} - -void freetable(table tab,void (*freefunc)(void *)) -{ -Node node = tab->first,next; - - while (node) - { - next = node->next; - freefunc(node); - node = next; - } - free(tab); -} - -char *strdup(char *str) -{ -char *ret = zalloc(strlen(str)+1); - - strcpy(ret,str); - return ret; -} - -#ifndef STRSTR -const char *strstr(const char *s,const char *t) -{ -const char *p1,*p2; - - for (; *s; s++) - { - for (p1 = s, p2 = t; *p2; p1++,p2++) - if (*p1 != *p2) - break; - if (!*p2) - return (char *) s; - } - return NULL; -} -#endif - End of table.c echo table.pro 1>&2 sed 's/^-//' >table.pro <<'End of table.pro' -table newtable(); -htable newhtable(int size); -int hasher(char *s) /* copied from Programming in C++, p14 */; -void addhnode(char *nam,void *dat,htable ht,void (*freefunc)(void *)); -void expandhtab(htable ht); -void *gethnode(char *nam,htable ht); -void freehtab(htable ht,void (*freefunc)(void *)); -void *remhnode(char *nam,htable ht); -void *zalloc(int l); -void *alloc(int l); -void addnode(table list,void *str); -void insnode(table list,Node last,void *dat); -void *remnode(table list,Node nd); -void chuck(char *str); -void *getnode(table list); -int full(table list); -void freetable(table tab,void (*freefunc)(void *)); -char *strdup(char *str); -/*const char *strstr(const char *s,const char *t); */ End of table.pro echo test.c 1>&2 sed 's/^-//' >test.c <<'End of test.c' -/* - - test.c - the test builtin - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" - -#ifndef F_OK -#define F_OK 00 -#define R_OK 04 -#define W_OK 02 -#define X_OK 01 -#endif - -#include "test.pro" -#include "table.pro" - -static char **arg; -static int efg; - -void die(char *str) -{ - if (!efg) - zerrnam("test",str); - efg = 1; -} - -int test(comm comm) -{ -Node n; -int t0; -char **av,**ap; - - for (n = comm->args->first, t0 = 0; n; n = n->next,t0++); - ap = av = (char **) zalloc((sizeof(char *))*(t0+1)); - for (n = comm->args->first; n; n = n->next) - *ap++ = n->dat; - *ap = NULL; - t0 = testmain(av); - free(av); - return t0; -} - -int testmain(char **argv) -{ -int ret,isbrack; - - efg = 0; - arg = argv+1; - ret = testexpr(); - if (efg) - return 1; - isbrack = !strcmp(*argv,"["); - if (isbrack) - { - if (*arg && !strcmp(*arg,"]") && !arg[1]) - return !ret; - } - else - if (!*arg) - return !ret; - die("bad test format"); - return 1; -} - -int testexpr(void) -{ -int ret = testexpr2(),ret2; - - if (*arg && !strcmp(*arg,"-o")) - { - arg++; - ret2 = testexpr2(); - if (efg) - return 0; - ret = ret || ret2; - } - return ret; -} - -int testexpr2(void) -{ -int ret = testexpr3(),ret2; - - if (*arg && !strcmp(*arg,"-a")) - { - arg++; - ret2 = testexpr2(); - if (efg) - return 0; - ret = ret && ret2; - } - return ret; -} - -int testexpr3(void) -{ - if (*arg && !strcmp(*arg,"!")) - { - arg++; - return !testexpr3(); - } - return testexpr4(); -} - -int testexpr4(void) -{ -int ret,t0,t1; -struct stat *st; -char buf[16],*op; - - if (!*arg) - { - die("expression expected"); - return 0; - } - if (!strcmp(*arg,"(")) - { - arg++; - ret = testexpr(); - if (!*arg || strcmp(*arg,")")) - { - die("')' expected"); - return 0; - } - arg++; - return ret; - } - if (**arg == '-' && !(*arg)[2]) - { - switch((*arg++)[1]) - { - case 'a': return(doaccess(F_OK)); - case 'b': return(S_ISBLK(dostat())); - case 'c': return(S_ISCHR(dostat())); - case 'd': return(S_ISDIR(dostat())); - case 'f': return(S_ISREG(dostat())); - case 'g': return(!!(dostat() & S_ISGID)); - case 'k': return(!!(dostat() & S_ISVTX)); - case 'L': return(S_ISLNK(dostat())); - case 'p': return(S_ISFIFO(dostat())); - case 'r': return(doaccess(R_OK)); - case 's': return((st = getstat()) && !!(st->st_size)); - case 'S': return(S_ISSOCK(dostat())); - case 'u': return(!!(dostat() & S_ISUID)); - case 'w': return(doaccess(W_OK)); - case 'x': return(doaccess(X_OK)); - case 'O': return((st = getstat()) && st->st_uid == geteuid()); - case 'G': return((st = getstat()) && st->st_gid == getegid()); - case 't': { - int t0 = 1; - - if (*arg && isdigit(**arg)) - t0 = atoi(*arg++); - return isatty(t0); - } - case 'z': - if (!*arg) - { - die("string expected"); - return 0; - } - return !strlen(*arg++); - case 'n': - if (!*arg) - { - die("string expected"); - return 0; - } - return !!strlen(*arg++); - case 'l': - sprintf(buf,"%d",strlen(*arg)); - *arg = buf; - break; - } - } - if (!arg[1] || !strcmp(arg[1],"-o") || !strcmp(arg[1],"-a") || - !strcmp(arg[1],"]") || !strcmp(arg[1],")")) - return(!!strlen(*arg++)); - if (!arg[2]) - { - die("bad expression"); - return 0; - } - if (!strcmp(arg[1],"-nt")) - { - time_t a; - - if (!(st = getstat())) - { - arg += 2; - return 0; - } - a = st->st_mtime; - arg++; - if (!(st = getstat())) - { - arg += 2; - return 0; - } - return a > st->st_mtime; - } - if (!strcmp(arg[1],"-ot")) - { - time_t a; - - if (!(st = getstat())) - { - arg += 2; - return 0; - } - a = st->st_mtime; - arg++; - if (!(st = getstat())) - { - arg += 2; - return 0; - } - return a < st->st_mtime; - } - if (!strcmp(arg[1],"-ef")) - { - dev_t d; - ino_t i; - - if (!(st = getstat())) - { - arg += 2; - return 0; - } - d = st->st_dev; - i = st->st_ino; - arg++; - if (!(st = getstat())) - { - arg += 2; - return 0; - } - return d == st->st_dev && i == st->st_ino; - } - if (!strcmp(arg[1],"~=")) - { - arg += 3; - return patmatch(arg[-3],arg[-1]); - } - if (!strcmp(arg[1],"=")) - { - arg += 3; - return !strcmp(arg[-3],arg[-1]); - } - if (!strcmp(arg[1],"!=")) - { - arg += 3; - return !!strcmp(arg[-3],arg[-1]); - } - t0 = atoi(arg[0]); - op = arg[1]; - arg += 2; - if (!strcmp(*arg,"-l")) - { - if (!arg[1]) - { - die("string expected"); - return 0; - } - t1 = strlen(arg[1]); - arg += 2; - } - else - t1 = atoi(*arg++); - if (!strcmp(op,"-eq")) - return t0 == t1; - if (!strcmp(op,"-ne")) - return t0 != t1; - if (!strcmp(op,"-lt")) - return t0 < t1; - if (!strcmp(op,"-le")) - return t0 <= t1; - if (!strcmp(op,"-gt")) - return t0 > t1; - if (!strcmp(op,"-ge")) - return t0 >= t1; - if (!efg) - zerrnam("test","unrecognized operator: %s",op); - efg = 1; - return 0; -} - -int doaccess(int c) -{ - if (!*arg) - { - die("filename expected"); - return 0; - } - return !access(*arg++,c); -} - -struct stat *getstat(void) -{ -static struct stat st; - - if (!*arg) - { - die("filename expected"); - return NULL; - } - if (!strncmp(*arg,"/dev/fd/",8)) - { - if (fstat(atoi((*arg++)+8),&st)) - return NULL; - } - else if (lstat(*arg++,&st)) - return NULL; - return &st; -} - -unsigned short dostat(void) -{ -struct stat *st; - - if (!(st = getstat())) - return 0; - return st->st_mode; -} - End of test.c echo test.pro 1>&2 sed 's/^-//' >test.pro <<'End of test.pro' -void die(char *str); -int test(comm comm); -int testmain(char **argv); -int testexpr(void); -int testexpr2(void); -int testexpr3(void); -int testexpr4(void); -int doaccess(int c); -struct stat *getstat(void); -unsigned short dostat(void); End of test.pro echo utils.c 1>&2 sed 's/^-//' >utils.c <<'End of utils.c' -/* - - utils.c - miscellaneous utilities - - This file is part of zsh, the Z shell. - - zsh is free software; no one can prevent you from reading the source - code, or giving it to someone else. - This file is copyrighted under the GNU General Public License, which - can be found in the file called COPYING. - - Copyright (C) 1990 Paul Falstad - - zsh is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY. No author or distributor accepts - responsibility to anyone for the consequences of using it or for - whether it serves any particular purpose or works at all, unless he - says so in writing. Refer to the GNU General Public License - for full details. - - Everyone is granted permission to copy, modify and redistribute - zsh, but only under the conditions described in the GNU General Public - License. A copy of this license is supposed to have been given to you - along with zsh so you can know your rights and responsibilities. - It should be in a file named COPYING. - - Among other things, the copyright notice and this notice must be - preserved on all copies. - -*/ - -#include "zsh.h" -#include "funcs.h" -#include -#include /* had to change this to stdarg.h.old on one machine */ -#include -#include -#include - -/* add vars to the parm hash table */ - -void addvars(table vars) -{ -char *s1,*s2; -Node node; - - for (node = vars->first; node; node = node->next) - { - s1 = node->dat; - untokenize(s1); - node = node->next; - s2 = node->dat; - dovarsubs(&s2); - if (errflag) - break; - untokenize(s2); - setparm(s1,s2,0,0); - } - free(vars); -} - -/* set a parameter to an integer value */ - -void setiparm(char *s,long v,int isint) -{ -struct pmnode *pmn,*pmo; - - if (!strcmp(s,"RANDOM")) - { - srand((unsigned long) v); - return; - } - if (!strcmp(s,"SECONDS")) - { - shtimer = v+time(NULL); - return; - } - if (pmo = gethnode(s,parmhtab)) - { - char buf[12]; - - pmn = alloc(sizeof *pmn); - if (pmn->isint = pmo->isint | isint) - pmn->u.val = v; - else - { - sprintf(buf,"%ld",v); - pmn->u.str = strdup(buf); - } - addhnode(s,pmn,parmhtab,freepm); - } - else if (getenv(s) || (opts[ALLEXPORT] == OPT_SET)) - { - char buf[12]; - - sprintf(buf,"%ld",v); - putenv(tricat(s,"=",buf)); - } - else - { - char buf[12]; - - pmn = alloc(sizeof *pmn); - if (pmn->isint = isint) - pmn->u.val = v; - else - { - sprintf(buf,"%ld",v); - pmn->u.str = strdup(buf); - } - addhnode(s,pmn,parmhtab,freepm); - addlocal(s); - } - if (!strcmp(s,"PERIOD")) - { - period = v*60; - lastperiod = time(NULL)+period; - } - if (!strcmp(s,"HISTSIZE")) - { - tevs = v; - if (tevs <= 2) - tevs = 2; - } -} - -/* set a parameter to a string value */ - -void setparm(char *s,char *t,int ex,int isint) -{ -struct pmnode *pmn,*pmo; - - if (!strcmp(s,"RANDOM")) - { - srand((unsigned long) atol(t)); - return; - } - if (!strcmp(s,"SECONDS")) - { - shtimer = atol(t)+time(NULL); - return; - } - if (ex && gethnode(s,parmhtab)) - freepm(remhnode(s,parmhtab)); - if (pmo = gethnode(s,parmhtab)) - { - pmn = alloc(sizeof *pmn); - if (pmn->isint = pmo->isint | isint) - { - pmn->u.val = matheval(t); - free(t); - t = NULL; - } - else - pmn->u.str = t; - addhnode(s,pmn,parmhtab,freepm); - } - else if (ex || getenv(s) || (opts[ALLEXPORT] == OPT_SET)) - putenv(tricat(s,"=",t)); - else - { - pmn = alloc(sizeof *pmn); - if (pmn->isint = isint) - { - pmn->u.val = matheval(t); - free(t); - t = NULL; - } - else - pmn->u.str = t; - addhnode(s,pmn,parmhtab,freepm); -#if 0 - addlocal(s); -#endif - } - if (!t) - return; - if (!strcmp(s,"PATH")) - parsepath(); - if (!strcmp(s,"CDPATH")) - parsecdpath(); - if (!strcmp(s,"IFS")) - { - free(ifs); - ifs = strdup(t); - } - if (!strcmp(s,"PERIOD")) - { - period = atoi(t)*60; - lastperiod = time(NULL)+period; - } - if (!strcmp(s,"HISTSIZE")) - { - tevs = atoi(t); - if (tevs <= 2) - tevs = 2; - } - if (!strcmp(s,"HOME")) - { - free(home); - home = xsymlink(t); - } - if (!strcmp(s,"MAIL") || !strcmp(s,"MAILCHECK") || !strcmp(s,"MAILPATH")) - lastmailcheck = 0; -} - -void unsetparm(char *s) -{ -char **pp; - - if (!strcmp(s,"HOME")) - return; - if (!strcmp(s,"PERIOD")) - period = 0; - if (!strcmp(s,"HISTSIZE")) - tevs = 1; - if (gethnode(s,parmhtab)) - { - freepm(remhnode(s,parmhtab)); - return; - } - for (pp = environ; *pp; pp++) - if (!strncmp(*pp,s,strlen(s)) && (*pp)[strlen(s)] == '=') - { - while (pp[0] = pp[1]) - pp++; - return; - } -} - -/* get the integer value of a parameter */ - -long getiparm(char *s) -{ -struct pmnode *pmn; -char *t; - - if (!isalpha(*s) && !s[1]) - { - t = getsparmval(s,1); - return (t) ? atoi(t) : 0; - } - if (s[0] == 'T' && s[1] == 'C' && !s[4]) /* TCxx */ - return tgetnum(s+2); - if (!strcmp(s,"RANDOM")) - return rand() & 0x7fff; - if (!strcmp(s,"LINENO")) - return lineno; - if (!strcmp(s,"SECONDS")) - return time(NULL)-shtimer; - if (pmn = gethnode(s,parmhtab)) - { - if (pmn->isint) - return pmn->u.val; - return atol(pmn->u.str); - } - return atol(getenv(s)); -} - -/* get the string value of a parameter */ - -char *getparm(char *s) -{ -struct pmnode *pmn; - - if (!isalpha(*s) && !s[1]) - return getsparmval(s,1); - if (s[0] == 'T' && s[1] == 'C' && !s[4]) /* TCxx */ - { - static char buf[1024]; - char *ss = buf; - int t0; - - if (tgetstr(s+2,&ss)) - return buf; - if ((t0 = tgetnum(s+2)) != -1) - { - sprintf(buf,"%d",t0); - return buf; - } - return NULL; - } - if (!strcmp(s,"LINENO")) - { - static char buf[8]; - - sprintf(buf,"%d",lineno); - return buf; - } - if (!strcmp(s,"RANDOM")) - { - static char buf[8]; - - sprintf(buf,"%d",rand() & 0x7fff); - return buf; - } - if (!strcmp(s,"SECONDS")) - { - static char buf[12]; - - sprintf(buf,"%ld",time(NULL)-shtimer); - return buf; - } - if (pmn = gethnode(s,parmhtab)) - { - static char buf[12]; - - if (pmn->isint) - { - sprintf(buf,"%ld",pmn->u.val); - return buf; - } - return pmn->u.str; - } - return getenv(s); -} - -/* parse the PATH parameter into directory names in a array of - strings and create the command hash table */ - -void parsepath(void) -{ -char *pptr = getparm("PATH"),*ptr; - - if (path) - { - while(pathct) - free(path[--pathct]); - free(path); - } - for (pathct = 1, ptr = pptr; *ptr; ptr++) - if (*ptr == ':') - pathct++; - path = (char **) zalloc(pathct*sizeof(char *)); - pathct = 0; - ptr = pptr; - while(pptr) - { - ptr = strchr(pptr,':'); - if (ptr) - *ptr = '\0'; - path[pathct] = strdup(pptr); - if (ptr) - { - *ptr = ':'; - pptr = ptr+1; - } - else - pptr = NULL; - if (!*path[pathct]) - { - free(path[pathct]); - path[pathct] = strdup("."); - } - pathsub(&path[pathct]); - if (*path[pathct] != '/' && strcmp(path[pathct],".")) - { -#ifdef PATH_WARNINGS - zerr("PATH component not absolute pathname: %s",path[pathct]); -#endif - free(path[pathct--]); - } - pathct++; - } - createchtab(); -} - -void parsecdpath(void) -{ -char *pptr = getparm("CDPATH"),*ptr; - - if (cdpath) - { - while(cdpathct) - free(cdpath[--cdpathct]); - free(cdpath); - } - if (pptr == NULL) - { - cdpath = (char **) zalloc(sizeof(char *)); - cdpath[0] = strdup("."); - cdpathct = 1; - return; - } - for (cdpathct = 2, ptr = pptr; *ptr; ptr++) - if (*ptr == ':') - cdpathct++; - cdpath = (char **) zalloc(cdpathct*sizeof(char *)); - cdpath[0] = strdup("."); - cdpathct = 1; - ptr = pptr; - while (pptr) - { - ptr = strchr(pptr,':'); - if (ptr) - *ptr = '\0'; - cdpath[cdpathct] = strdup(pptr); - if (ptr) - { - *ptr = ':'; - pptr = ptr+1; - } - else - pptr = NULL; - pathsub(&cdpath[cdpathct]); - if (*cdpath[cdpathct] != '/') - { -#ifdef PATH_WARNINGS - zerr("CDPATH component not absolute pathname: %s",cdpath[cdpathct]); -#endif - free(cdpath[cdpathct--]); - } - cdpathct++; - } -} - -/* source a file */ - -int source(char *s) -{ -int fd,cj = curjob,iact = opts[INTERACTIVE]; -FILE *obshin = bshin; - - fd = SHIN; - opts[INTERACTIVE] = OPT_UNSET; - if ((SHIN = movefd(open(s,O_RDONLY))) == -1) - { - SHIN = fd; - curjob = cj; - opts[INTERACTIVE] = iact; - return 1; - } - bshin = fdopen(SHIN,"r"); - loop(); - fclose(bshin); - opts[INTERACTIVE] = iact; - bshin = obshin; - SHIN = fd; - peek = EMPTY; - curjob = cj; - errflag = 0; - retflag = 0; - return 0; -} - -/* try to source a file in our home directory */ - -void sourcehome(char *s) -{ -char buf[MAXPATHLEN]; - - sprintf(buf,"%s/%s",getparm("HOME"),s); - (void) source(buf); -} - -/* print an error */ - -void zerrnam(char *cmd, char *fmt, ...) -{ -va_list ap; -char *str; -int num; - - va_start(ap,fmt); - fputs(cmd,stderr); - putc(':',stderr); - putc(' ',stderr); - while (*fmt) - if (*fmt == '%') - { - fmt++; - switch(*fmt++) - { - case 's': /* string */ - str = va_arg(ap,char *); - while (*str) - niceputc(*str++,stderr); - break; - case 'l': /* string with a length */ - num = va_arg(ap,int); - str = va_arg(ap,char *); - while (num--) - niceputc(*str++,stderr); - break; - case 'd': /* number */ - num = va_arg(ap,int); - fprintf(stderr,"%d",num); - break; - case '%': - putc('%',stderr); - break; - case 'c': /* char */ - num = va_arg(ap,int); - niceputc(num,stderr); - break; - case 'e': /* system error */ - num = va_arg(ap,int); - if (num == EINTR) - { - fputs("interrupt\n",stderr); - errflag = 1; - return; - } - fputc(tolower(sys_errlist[num][0]),stderr); - fputs(sys_errlist[num]+1,stderr); - break; - } - } - else - putc(*fmt++,stderr); - putc('\n',stderr); - va_end(ap); -} - -void zerr(char *fmt,...) -{ -va_list ap; -char *str; -int num; - - va_start(ap,fmt); - fputs("zsh: ",stderr); - while (*fmt) - if (*fmt == '%') - { - fmt++; - switch(*fmt++) - { - case 's': - str = va_arg(ap,char *); - while (*str) - niceputc(*str++,stderr); - break; - case 'l': - num = va_arg(ap,int); - str = va_arg(ap,char *); - while (num--) - niceputc(*str++,stderr); - break; - case 'd': - num = va_arg(ap,int); - fprintf(stderr,"%d",num); - break; - case '%': - putc('%',stderr); - break; - case 'c': - num = va_arg(ap,int); - niceputc(num,stderr); - break; - case 'e': - num = va_arg(ap,int); - if (num == EINTR) - { - fputs("interrupt\n",stderr); - errflag = 1; - return; - } - fputc(tolower(sys_errlist[num][0]),stderr); - fputs(sys_errlist[num]+1,stderr); - break; - } - } - else - putc(*fmt++,stderr); - putc('\n',stderr); - va_end(ap); -} - -void niceputc(int c,FILE *f) -{ - if (istok(c)) - { - if (c >= Pound && c <= Qtick) - putc(tokens[c-Pound],f); - return; - } - c &= 0x7f; - if (c >= ' ' && c < '\x7f') - putc(c,f); - else if (c == '\n') - { - putc('\\',f); - putc('n',f); - } - else - { - putc('^',f); - putc(c|'A',f); - } -} - -/* enable ^C interrupts */ - -void intr(void) -{ -struct sigvec vec = { handler,sigmask(SIGINT),SV_INTERRUPT }; - - if (interact) - sigvec(SIGINT,&vec,NULL); - sigsetmask(0); -} - -void noholdintr(void) -{ - intr(); -} - -void holdintr(void) -{ -struct sigvec vec = { handler,sigmask(SIGINT),0 }; - - if (interact) - { - sigvec(SIGINT,&vec,NULL); - sigsetmask(0); - } -} - -char *fgetline(char *buf,int len,FILE *in) -{ - if (!fgets(buf,len,in)) - return NULL; - buf[len] = '\0'; - buf[strlen(buf)-1] = '\0'; - return buf; -} - -/* get a symlink-free pathname for s relative to PWD */ - -char *findcwd(char *s) -{ -char *t; - - if (*s == '/') - return xsymlink(s); - s = tricat((cwd[1]) ? cwd : "","/",s); - t = xsymlink(s); - free(s); - return t; -} - -static char xbuf[MAXPATHLEN]; - -/* expand symlinks in s, and remove other weird things */ - -char *xsymlink(char *s) -{ - if (*s != '/') - return NULL; - strcpy(xbuf,""); - if (xsymlinks(s+1)) - return strdup(s); - if (!*xbuf) - return strdup("/"); - return strdup(xbuf); -} - -char **slashsplit(char *s) -{ -char *t,**r,**q; -int t0; - - if (!*s) - return (char **) calloc(sizeof(char **),1); - for (t = s, t0 = 0; *t; t++) - if (*t == '/') - t0++; - q = r = (char **) zalloc(sizeof(char **)*(t0+2)); - while (t = strchr(s,'/')) - { - *t = '\0'; - *q++ = strdup(s); - *t = '/'; - while (*t == '/') - t++; - if (!*t) - { - *q = NULL; - return r; - } - s = t; - } - *q++ = strdup(s); - *q = NULL; - return r; -} - -int islink(char *s) -{ -char xbuf[MAXPATHLEN]; - - if (readlink(s,xbuf,1) == -1 && errno == EINVAL) - return 0; - return 1; -} - -int xsymlinks(char *s) -{ -char **pp,**opp; -char xbuf2[MAXPATHLEN],xbuf3[MAXPATHLEN]; -int t0; - - opp = pp = slashsplit(s); - for (; *pp; pp++) - { - if (!strcmp(*pp,".")) - { - free(*pp); - continue; - } - if (!strcmp(*pp,"..")) - { - char *p; - - free(*pp); - if (!strcmp(xbuf,"/")) - continue; - p = xbuf+strlen(xbuf); - while (*--p != '/'); - *p = '\0'; - continue; - } - sprintf(xbuf2,"%s/%s",xbuf,*pp); - t0 = readlink(xbuf2,xbuf3,MAXPATHLEN); - if (t0 == -1) - { - if (errno != EINVAL) - { - while (*pp) - free(*pp++); - free(opp); - return 1; - } - strcat(xbuf,"/"); - strcat(xbuf,*pp); - free(*pp); - } - else - { - xbuf3[t0] = '\0'; /* STUPID */ - if (*xbuf3 == '/') - { - strcpy(xbuf,""); - if (xsymlinks(xbuf3+1)) - return 1; - } - else - if (xsymlinks(xbuf3)) - return 1; - free(*pp); - } - } - free(opp); - return 0; -} - -void printdir(char *s) -{ -int t0; - - if (!strncmp(s,home,t0 = strlen(home))) - { - putchar('~'); - fputs(s+t0,stdout); - } - else - fputs(s,stdout); -} - - -int ddifftime(time_t t1,time_t t2) -{ - return ((long) t2-(long) t1); -} - -/* see if jobs need printing */ - -void scanjobs(void) -{ -int t0; - - for (t0 = 1; t0 != MAXJOB; t0++) - if (jobtab[t0].stat & STAT_CHANGED) - printjob(jobtab+t0,0); -} - -/* do pre-prompt stuff */ - -void preprompt(void) -{ -int diff; -list list; -char *mc = getparm("MAILCHECK"),*wc = getparm("LOGCHECK"); -struct schnode *sch,*schl; - - if (unset(NOTIFY)) - scanjobs(); - if (errflag) - return; - if (list = gethnode("precmd",shfunchtab)) - newrunlist(list); - if (errflag) - return; - if (period && (time(NULL) > lastperiod+period) && - (list = gethnode("periodic",shfunchtab))) - { - newrunlist(list); - lastperiod = time(NULL); - } - if (errflag) - return; - if (getparm("WATCH")) - { - diff = (int) ddifftime(lastwatch,time(NULL)); - if (diff > ((wc) ? atoi(wc)*60 : 300)) - { - lastwatch = time(NULL); - watch(); - } - } - if (errflag) - return; - diff = (int) ddifftime(lastmailcheck,time(NULL)); - if (diff > ((mc) ? atoi(mc) : 60)) - { - lastmailcheck = time(NULL); - if (getparm("MAILPATH")) - checkmailpath(); - else - checkmail(); - } - for (schl = (struct schnode *) &scheds, sch = scheds; sch; - sch = (schl = sch)->next) - { - if (sch->time < time(NULL)) - { - execstring(sch->cmd); - schl->next = sch->next; - free(sch); - } - if (errflag) - return; - } -} - -void checkmail(void) -{ -struct stat st; -char *s; - - if (!(s = getparm("MAIL"))) - return; - if (stat(s,&st) == -1) - { - if (errno != ENOENT) - zerr("%e: %s",errno,getparm("MAIL")); - lastmailval = 0; - lastmailsize = 0; - return; - } - else - if (lastmailval != -1 && lastmailval < st.st_mtime && - lastmailsize < st.st_size) - zerr("you have new mail."); - lastmailval = st.st_mtime; - lastmailsize = st.st_size; -} - -void checkfirstmail(void) -{ -struct stat st; -char *s; - - if (!(s = getparm("MAIL"))) - return; - if (stat(s,&st) == -1) - { - if (errno != ENOENT) - zerr("%e: %s",errno,getparm("MAIL")); - lastmailval = 0; - lastmailsize = 0; - return; - } - lastmailval = st.st_mtime; - lastmailsize = st.st_size; - zerr("you have mail."); -} - -void checkmailpath(void) -{ -struct stat st; -char *s = getparm("MAILPATH"),*v,*u,c,d; - - for (;;) - { - for (v = s; *v && *v != '?' && *v != ':'; v++); - c = *v; - *v = '\0'; - if (c != '?') - u = NULL; - else - { - for (u = v+1; *u && *u != ':'; u++); - d = *u; - *u = '\0'; - } - if (stat(s,&st) == -1) - { - if (errno != ENOENT) - zerr("%e: %s",errno,getparm("MAIL")); - } - else - if (lastmailval != -1 && lastmailval < st.st_mtime && - lastmailsize < st.st_size) - if (!u) - fprintf(stderr,"You have new mail.\n"); - else - { - char *z = u; - - while (*z) - if (*z == '$' && z[1] == '_') - { - fprintf(stderr,"%s",s); - z += 2; - } - else - fputc(*z++,stderr); - fputc('\n',stderr); - } - lastmailval = st.st_mtime; - lastmailsize = st.st_size; - *v = c; - if (u) - *u = d; - if (!c || (u && !d)) - break; - v = (u) ? u+1 : v+1; - } -} - -/* create command hash table */ - -void createchtab(void) -{ -int t0,dot = 0; -struct direct *de; -DIR *dir; -struct chnode *cc; - - holdintr(); - if (chtab) - freehtab(chtab,freechnode); - chtab = newhtable(101); - for (t0 = 0; t0 != pathct; t0++) - if (!strcmp(".",path[t0])) - { - dot = 1; - break; - } - for (t0 = pathct-1; t0 >= 0; t0--) - if (!strcmp(".",path[t0])) - dot = 0; - else - { - dir = opendir(path[t0]); - if (!dir) - { - zerr("%e: %s",errno,path[t0]); - continue; - } - readdir(dir); readdir(dir); - while (de = readdir(dir)) - { - cc = alloc(sizeof(struct chnode)); - cc->type = (dot) ? EXCMD_POSTDOT : EXCMD_PREDOT; - cc->globstat = GLOB; - cc->u.nam = tricat(path[t0],"/",de->d_name); - addhnode(strdup(de->d_name),cc,chtab,freechnode); - } - closedir(dir); - } - addintern(chtab); - noholdintr(); -} - -void freechnode(void *a) -{ -struct chnode *c = (struct chnode *) a; - - if (c->type != BUILTIN) - free(c->u.nam); - free(c); -} - -void freestr(void *a) -{ - free(a); -} - -void freeanode(void *a) -{ -struct anode *c = (struct anode *) a; - - free(c->text); - free(c); -} - -void freeredir(void *a) -{ -struct fnode *f = (struct fnode *) a; - - if (f) - { - if (f->type == HEREDOC) - close(f->u.fd2); - else - free(f->u.name); - free(f); - } -} - -void freeshfunc(void *a) -{ - freelist((list) a); -} - -void freepm(void *a) -{ -struct pmnode *pm = a; - - if (!pm->isint) - free(pm->u.str); - free(pm); -} - -void restoretty(void) -{ - settyinfo(&shttyinfo); -} - -void gettyinfo(struct ttyinfo *ti) -{ - if (jobbing) - { -#ifndef BUGGY_GCC -#ifdef TERMIOS - ioctl(SHTTY,TCGETS,&ti->termios); -#else - ioctl(SHTTY,TIOCGETP,&ti->sgttyb); - ioctl(SHTTY,TIOCGETC,&ti->tchars); - ioctl(SHTTY,TIOCGLTC,&ti->ltchars); -#endif - ioctl(SHTTY,TIOCGWINSZ,&ti->winsize); -#else -#ifdef TERMIOS - ioctl(SHTTY, ( 0x40000000 |((sizeof( struct termios)&0xff )<<16)|('T'<<8)| 8) ,&ti->termios); -#else - ioctl(SHTTY,(0x40000000|((sizeof(struct sgttyb)&0x1fff)<<16)| - ('t'<<8)|8),&ti->sgttyb); - ioctl(SHTTY,(0x40000000|((sizeof(struct tchars)&0x1fff)<<16)| - ('t'<<8)|18),&ti->tchars); - ioctl(SHTTY,(0x40000000|((sizeof(struct ltchars)&0x1fff)<<16)| - ('t'<<8)|116),&ti->ltchars); -#endif - ioctl(SHTTY,( 0x40000000 |((sizeof( struct winsize)&0xff )<<16)|('t'<<8)| 104) ,&ti->winsize); -#endif - } -} - -void settyinfo(struct ttyinfo *ti) -{ - if (jobbing) - { -#ifndef BUGGY_GCC -#ifdef TERMIOS - ioctl(SHTTY,TCSETS,&ti->termios); -#else - ioctl(SHTTY,TIOCSETP,&ti->sgttyb); - ioctl(SHTTY,TIOCSETC,&ti->tchars); - ioctl(SHTTY,TIOCSLTC,&ti->ltchars); -#endif - ioctl(SHTTY,TIOCSWINSZ,&ti->winsize); -#else -#ifdef TERMIOS - ioctl(SHTTY, ( 0x80000000 |((sizeof( struct termios)&0xff )<<16)|('T'<<8)| 9) ,&ti->termios); -#else - ioctl(SHTTY,(0x80000000|((sizeof( struct sgttyb)&0x1fff)<<16)| - ('t'<<8)|9),&ti->sgttyb); - ioctl(SHTTY,(0x80000000|((sizeof(struct tchars)&0x1fff)<<16)| - ('t'<<8)|17),&ti->tchars); - ioctl(SHTTY,(0x80000000|((sizeof(struct ltchars)&0x1fff)<<16)| - ('t'<<8)|117),&ti->ltchars); -#endif - ioctl(SHTTY,( 0x80000000 |((sizeof( struct winsize)&0xff )<<16)|('t'<<8)| 103) ,&ti->winsize); -#endif - } -} - -int zyztem(char *s,char *t) -{ -#ifdef WAITPID -int pid,statusp; - - if (!(pid = fork())) - { - s = tricat(s," ",t); - execl("/bin/sh","sh","-c",s,(char *) 0); - _exit(1); - } - waitpid(pid,&statusp,WUNTRACED); - if (WIFEXITED(SP(statusp))) - return WEXITSTATUS(SP(statusp)); - return 1; -#else - if (!waitfork()) - { - s = tricat(s," ",t); - execl("/bin/sh","sh","-c",s,(char *) 0); - _exit(1); - } - return 0; -#endif -} - -#ifndef WAITPID - -/* fork a process and wait for it to complete without confusing - the SIGCHLD handler */ - -int waitfork(void) -{ -int pipes[2]; -char x; - - pipe(pipes); - if (!fork()) - { - close(pipes[0]); - signal(SIGCHLD,SIG_DFL); - if (!fork()) - return 0; - wait(NULL); - _exit(0); - } - close(pipes[1]); - read(pipes[0],&x,1); - close(pipes[0]); - return 1; -} - -#endif - -/* move a fd to a place >= 10 */ - -int movefd(int fd) -{ -int fe; - - if (fd == -1) - return fd; - if ((fe = dup(fd)) < 10) - fe = movefd(fe); - close(fd); - return fe; -} - -/* move fd x to y */ - -void redup(int x,int y) -{ - if (x != y) - { - dup2(x,y); - close(x); - } -} - -void settrap(char *s,int empty) -{ -int t0; - - if (strncmp(s,"TRAP",4)) - return; - for (t0 = 0; t0 != SIGCOUNT+2; t0++) - if (!strcmp(s+4,sigs[t0])) - { - if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN - || t0 == SIGPIPE)) - { - zerr("can't trap SIG%s in interactive shells",s); - return; - } - if (empty) - { - sigtrapped[t0] = 2; - if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD) - { - signal(t0,SIG_IGN); - sigtrapped[t0] = 2; - } - } - else - { - if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD) - signal(t0,handler); - sigtrapped[t0] = 1; - } - return; ---cut here---cut here---cut here---