home *** CD-ROM | disk | FTP | other *** search
- 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 <pwd.h>
- -#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 <pwd.h>
- -#include <stdarg.h> /* had to change this to stdarg.h.old on one machine */
- -#include <errno.h>
- -#include <sys/dir.h>
- -#include <fcntl.h>
- -
- -/* 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---
-