From: pfalstad@phoenix.Princeton.EDU (Paul John Falstad) Newsgroups: alt.sources Subject: zsh - a ksh/tcsh-like shell (part 3 of 8) Message-ID: <4744@idunno.Princeton.EDU> Date: 14 Dec 90 23:30:38 GMT ---cut here---cut here---cut here--- - close(pipes[1]); - entersubsh(1); - exiting = 1; - execpline2(pline->right,ASYNC,pipes[0],output,1); - _exit(lastval); - } - else if (pid == -1) - { - zerr("fork failed: %e",errno); - errflag = 1; - } - else - { - char *s,*text; - - close(pipes[0]); - text = s = getptext(pline->right); - for (;*s;s++) - if (*s == '\n') - *s = ';'; - untokenize(text); - addproc(pid,text)->lastfg = 1; - freepline(pline->right); - pline->right = NULL; - } - } - - /* otherwise just do the pipeline normally. */ - - execcomm(pline->left,input,pipes[1],how==ASYNC,0); - pline->left = NULL; - close(pipes[1]); - if (pline->right) - { - execpline2(pline->right,how,pipes[0],output,last1); - close(pipes[0]); - } - } -} - -/* make the argv array */ - -char **makecline(char *nam,struct xlist *list) -{ -int ct = 0; -Node node; -char **argv,**ptr; - - if (isset(XTRACE)) - { - for (node = list->first; node; node = node->next,ct++); - ptr = argv = (char **) zalloc((ct+2)*sizeof(char *)); - *ptr++ = nam; - fprintf(stderr,"+ %s",nam); - if (list->first) - fputc(' ',stderr); - for (node = list->first; node; node = node->next) - if (*(char *) node->dat) - { - *ptr++ = node->dat; - untokenize(node->dat); - fputs(node->dat,stderr); - if (node->next) - fputc(' ',stderr); - } - *ptr = NULL; - fputc('\n',stderr); - return(argv); - } - else - { - for (node = list->first; node; node = node->next,ct++); - ptr = argv = (char **) zalloc((ct+2)*sizeof(char *)); - *ptr++ = nam; - for (node = list->first; node; node = node->next) - if (*(char *) node->dat) - { - *ptr++ = node->dat; - untokenize(node->dat); - } - *ptr = NULL; - return(argv); - } -} - -/* untokenize the command line and remove null arguments */ - -void fixcline(table l) -{ -Node node,next; - - for (node = l->first; node; node = next) - { - next = node->next; - if (*(char *) node->dat) - untokenize(node->dat); - else - remnode(l,node); - } -} - -void untokenize(char *s) -{ - for (; *s; s++) - if (istok(*s)) - if (*s == HQUOT || *s == Nularg) - chuck(s--); - else - *s = tokens[*s-Pound]; -} - -/* add vars to the environment */ - -void addenv(table list) -{ -char *s,*t; - - while (s = getnode(list)) - { - dovarsubs(&s); - if (errflag) - break; - untokenize(s); - t = getnode(list); - dovarsubs(&t); - if (errflag) - break; - untokenize(t); - setparm(s,t,1,0); - } -} - -/* nonzero if we shouldn't clobber a file */ - -int dontclob(struct fnode *f) -{ -struct stat buf; - - if (isset(CLOBBER) || f->type & 1) - return 0; - if (stat(f->u.name,&buf) == -1) - return 1; - return S_ISREG(buf.st_mode); -} - -/* close an mnode (success) */ - -void closemn(struct mnode *mfds[10],int fd) -{ - if (mfds[fd]) - { - if (mfds[fd]->ct > 1) - if (mfds[fd]->rflag == 0) - catproc(mfds[fd]); - else - teeproc(mfds[fd]); - free(mfds[fd]); - mfds[fd] = NULL; - } -} - -/* close all the mnodes (failure) */ - -void closemnodes(struct mnode *mfds[10]) -{ -int t0,t1; - - for (t0 = 0; t0 != 10; t0++) - if (mfds[t0]) - { - for (t1 = 0; t1 != mfds[t0]->ct; t1++) - close(mfds[t0]->fds[t1]); - free(mfds[t0]); - mfds[t0] = NULL; - } -} - -/* add a fd to an mnode */ -/* an mnode is a list of fds associated with a certain fd. - thus if you do "foo >bar >ble", the mnode for fd 1 will have - two fds, the result of open("bar",...), and the result of - open("ble",....). */ - -void addfd(int forked,int save[10],struct mnode *mfds[10],int fd1,int fd2,int rflag) -{ -int pipes[2]; - - if (!mfds[fd1]) /* starting a new mnode */ - { - mfds[fd1] = alloc(sizeof(struct mnode)); - if (!forked && fd1 != fd2 && fd1 < 10) - save[fd1] = movefd(fd1); - redup(fd2,fd1); - mfds[fd1]->ct = 1; - mfds[fd1]->fds[0] = fd1; - mfds[fd1]->rflag = rflag; - } - else - { - if (mfds[fd1]->rflag != rflag) - { - zerr("file mode mismatch on fd %d",fd1); - errflag = 1; - return; - } - if (mfds[fd1]->ct == 1) /* split the stream */ - { - mfds[fd1]->fds[0] = movefd(fd1); - mfds[fd1]->fds[1] = movefd(fd2); - mpipe(pipes); - mfds[fd1]->pipe = pipes[1-rflag]; - redup(pipes[rflag],fd1); - mfds[fd1]->ct = 2; - } - else /* add another fd to an already split stream */ - mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2); - } -} - -void execcomm(comm comm,int input,int output,int bkg,int last1) -{ -int type; -long pid = 0; -table args = comm->args; -int save[10] = {0,0,0,0,0,0,0,0,0,0},gstat; -struct fnode *fn; -struct mnode *mfds[10] = {0,0,0,0,0,0,0,0,0,0}; -int fil,forked = 0,iscursh = 0,t0; -struct chnode *chn = NULL; -char *text; -list l; - - if ((type = comm->type) == SIMPLE && !*comm->cmd) - { - if (comm->vars) - addvars(comm->vars); - return; - } - if (comm->cmd) - { - if (*comm->cmd == '%') - { - if (full(args)) - { - zerrnam(comm->cmd,"too many arguments"); - return; - } - addnode(args,comm->cmd); - comm->cmd = strdup((bkg) ? "bg" : "fg"); - bkg = 0; - } - docmdsubs(&comm->cmd); - if (errflag) - { - freecmd(comm); - lastval = 1; - return; - } - untokenize(comm->cmd); - } - if (jobbing) /* get the text associated with this command */ - { - char *s; - s = text = gettext(comm); - for (;*s;s++) - if (*s == '\n') - *s = ';'; - untokenize(text); - } - else - text = NULL; - prefork(comm->args); /* do prefork substitutions */ - if (comm->cmd && !(comm->flags & CFLAG_COMMAND)) - { - if (isset(CORRECT) && jobbing) - spckcmd(&comm->cmd); - if ((l = gethnode(comm->cmd,shfunchtab)) && - !(comm->flags & CFLAG_COMMAND)) - { - insnode(comm->args,(Node) comm->args,comm->cmd); - comm->cmd = NULL; - comm->left = duplist(l); - type = comm->type = SHFUNC; - } - else - chn = gethnode(comm->cmd,chtab); - } - if (unset(RMSTARSILENT) && jobbing && chn && chn->type != BUILTIN && - !strcmp(comm->cmd,"rm") && full(comm->args) && - ((char *) comm->args->first->dat)[0] == Star && - ((char *) comm->args->first->dat)[1] == '\0') - checkrmall(); - if (errflag) - { - freecmd(comm); - lastval = 1; - return; - } - - /* this is nonzero if comm is a current shell procedure */ - - iscursh = (type >= CURSH) || (type == SIMPLE && chn && - chn->type == BUILTIN); - - gstat = (chn) ? chn->globstat : GLOB; - - /* if this command is backgrounded or (this is an external - command and we are not exec'ing it) or this is a builtin - with output piped somewhere, then fork. If this is the - last stage in a subshell pipeline, don't fork, but make - the rest of the function think we forked. */ - - if (bkg || !(iscursh || (comm->flags & CFLAG_EXEC)) || - (chn && chn->type == BUILTIN && output)) - { - pid = (last1 && execok()) ? 0 : phork(); - if (pid == -1) - return; - if (pid) - { - if (pid == -1) - zerr("%e",errno); - else - (void) addproc(pid,text); - return; - } - entersubsh(bkg); - forked = 1; - } - if (bkg && isset(BGNICE)) /* stupid */ - nice(5); - if (input) /* add pipeline input/output to mnodes */ - addfd(forked,save,mfds,0,input,0); - if (output) - addfd(forked,save,mfds,1,output,1); - spawnpipes(comm->redir); /* do process substitutions */ - while (full(comm->redir)) - if ((fn = getnode(comm->redir))->type == INPIPE) - { - if (fn->u.fd2 == -1) - execerr(); - addfd(forked,save,mfds,fn->fd1,fn->u.fd2,0); - free(fn); - } - else if (fn->type == OUTPIPE) - { - if (fn->u.fd2 == -1) - execerr(); - addfd(forked,save,mfds,fn->fd1,fn->u.fd2,1); - free(fn); - } - else - { - if (!(fn->type == HEREDOC || fn->type == CLOSE || fn->type == - MERGE || fn->type == MERGEOUT)) - if (xpandredir(fn,comm->redir)) - continue; - if (fn->type == READ || fn->type == HEREDOC) - { - fil = (fn->type == READ) ? open(fn->u.name,O_RDONLY) : fn->u.fd2; - if (fil == -1) - { - if (errno != EINTR) - zerr("%e: %s",errno,fn->u.name); - execerr(); - } - addfd(forked,save,mfds,fn->fd1,fil,0); - if (fn->type == READ) - free(fn->u.name); - } - else if (fn->type == CLOSE) - { - if (!forked && fn->fd1 < 3) - { - zerr("can't close fd %d without forking",fn->fd1); - execerr(); - } - closemn(mfds,fn->fd1); - close(fn->fd1); - } - else if (fn->type == MERGE || fn->type == MERGEOUT) - { - fil = dup(fn->u.fd2); - if (mfds[fn->fd1]) - redup(fil,fn->fd1); - else - addfd(forked,save,mfds,fn->fd1,fil,fn->type == MERGEOUT); - } - else - { - if (fn->type >= APP) - fil = open(fn->u.name,dontclob(fn) ? - O_WRONLY|O_APPEND : O_WRONLY|O_APPEND|O_CREAT,0666); - else - fil = open(fn->u.name,dontclob(fn) ? - O_WRONLY|O_CREAT|O_EXCL : O_WRONLY|O_CREAT|O_TRUNC,0666); - if (fil == -1) - { - if (errno != EINTR) - zerr("%e: %s",errno,fn->u.name); - execerr(); - } - addfd(forked,save,mfds,fn->fd1,fil,1); - free(fn->u.name); - } - free(fn); - } - postfork(comm->args,gstat); /* perform postfork substitutions */ - if (errflag) - { - lastval = 1; - goto err; - } - - /* we are done with redirection. close the mnodes, spawning - tee/cat processes as necessary. */ - for (t0 = 0; t0 != 10; t0++) - closemn(mfds,t0); - - if (unset(NOEXEC)) - if (type >= CURSH) /* current shell proc */ - { - void (*func[])(struct cnode *) = {execcursh,execshfunc, - execfor,execwhile,execrepeat,execif,execcase,execselect}; - - fixcline(comm->args); - (func[type-CURSH])(comm); - fflush(stdout); - if (ferror(stdout)) - { - zerr("write error: %e",errno); - clearerr(stdout); - } - } - else if (iscursh) /* builtin */ - { - int (*func)() = chn->u.func; - - if (comm->vars) - { - addvars(comm->vars); - comm->vars = NULL; - } - fixcline(comm->args); - if (func == test) /* let test know if it is test or [ */ - insnode(comm->args,(Node) comm->args,strdup(comm->cmd)); - lastval = func(comm); - if (isset(PRINTEXITVALUE) && lastval) - zerr("exit %d",lastval); - } - else - { - if (comm->vars) - addenv(comm->vars); - if (type == SIMPLE) - { - closem(); - execute(comm->cmd,args); - } - else /* ( ... ) */ - execlist(comm->left); - } -err: - if (forked) - _exit(lastval); - fixfds(save); - freecmd(comm); -} - -/* restore fds after redirecting a builtin */ - -void fixfds(int save[10]) -{ -int t0; - - for (t0 = 0; t0 != 10; t0++) - if (save[t0]) - redup(save[t0],t0); -} - -void entersubsh(int bkg) -{ - if (!jobbing) - { - if (bkg && isatty(0)) - { - close(0); - if (open("/dev/null",O_RDWR)) - { - zerr("can't open /dev/null: %e",errno); - _exit(1); - } - } - } - else if (!jobtab[curjob].gleader) - { - setpgrp(0L,jobtab[curjob].gleader = getpid()); - if (!bkg) - attachtty(jobtab[curjob].gleader); - } - else - setpgrp(0L,jobtab[curjob].gleader); - subsh = 1; - if (SHTTY != -1) - { - close(SHTTY); - SHTTY = -1; - } - if (jobbing) - { - signal(SIGTTOU,SIG_DFL); - signal(SIGTTIN,SIG_DFL); - signal(SIGTSTP,SIG_DFL); - signal(SIGPIPE,SIG_DFL); - } - if (interact) - { - signal(SIGTERM,SIG_DFL); - if (sigtrapped[SIGINT]) - signal(SIGINT,SIG_IGN); - } - if (!sigtrapped[SIGQUIT]) - signal(SIGQUIT,SIG_DFL); - opts[MONITOR] = OPT_UNSET; - clearjobtab(); -} - -/* close all shell files */ - -void closem(void) -{ -int t0; - - for (t0 = 10; t0 != NOFILE; t0++) - close(t0); -} - -/* get here document */ - -int gethere(char *str) -{ -char pbuf[256],*nam = gettemp(); -int tfil = creat(nam,0666); -FILE *in = fdopen(SHIN,"r"); - - FOREVER - { - fgetline(pbuf,256,in); - if (strcmp(str,pbuf)) - { - pbuf[strlen(pbuf)] = '\n'; - write(tfil,pbuf,strlen(pbuf)); - } - else - break; - } - close(tfil); - tfil = open(nam,O_RDONLY); - unlink(nam); - free(nam); - return(tfil); -} - -void catproc(struct mnode *mn) -{ -int len,t0; -char *buf; - - if (phork()) - { - for (t0 = 0; t0 != mn->ct; t0++) - close(mn->fds[t0]); - close(mn->pipe); - return; - } - closeallelse(mn); - buf = zalloc(4096); - for (t0 = 0; t0 != mn->ct; t0++) - while (len = read(mn->fds[t0],buf,4096)) - write(mn->pipe,buf,len); - _exit(0); -} - -void teeproc(struct mnode *mn) -{ -int len,t0; -char *buf; - - if (phork()) - { - for (t0 = 0; t0 != mn->ct; t0++) - close(mn->fds[t0]); - close(mn->pipe); - return; - } - buf = zalloc(4096); - closeallelse(mn); - while ((len = read(mn->pipe,buf,4096)) > 0) - for (t0 = 0; t0 != mn->ct; t0++) - write(mn->fds[t0],buf,len); - _exit(0); -} - -void closeallelse(struct mnode *mn) -{ -int t0,t1; - - for (t0 = 0; t0 != NOFILE; t0++) - if (mn->pipe != t0) - { - for (t1 = 0; t1 != mn->ct; t1++) - if (mn->fds[t1] == t0) - break; - if (t1 == mn->ct) - close(t0); - } -} - -/* strtol() doesn't work right on my system */ - -long int zstrtol(const char *s,char **t,int base) -{ -int ret = 0; - - for (; *s >= '0' && *s < ('0'+base); s++) - ret = ret*base+*s-'0'; - if (t) - *t = (char *) s; - return ret; -} - -/* $(...) */ - -table getoutput(char *cmd,int qt) -{ -list list; -int pipes[2]; - - if (*cmd == '<') - { - int stream; - char *fi; - - fi = strdup(cmd+1); - if (*fi == '~') - *fi = Tilde; - else if (*fi == '=') - *fi = Equals; - filesub((void **) &fi); - if (errflag) - return NULL; - stream = open(fi,O_RDONLY); - if (stream == -1) - { - magicerr(); - zerr("%e: %s",errno,cmd+1); - return NULL; - } - return readoutput(stream,qt); - } - hungets(strdup(cmd)); - strinbeg(); - if (!(list = parlist(1))) - { - strinend(); - hflush(); - return NULL; - } - if (peek != EOF && peek != EMPTY) - { - strinend(); - hflush(); - return NULL; - } - strinend(); - mpipe(pipes); - if (phork()) - { - close(pipes[1]); - return readoutput(pipes[0],qt); - } - subsh = 1; - close(pipes[0]); - redup(pipes[1],1); - entersubsh(0); - signal(SIGTSTP,SIG_IGN); - exiting = 1; - execlist(list); - close(1); - exit(0); return NULL; -} - -/* read output of command substitution */ - -table readoutput(int in,int qt) -{ -table ret; -char *buf,*ptr; -int bsiz,c,cnt = 0; -FILE *fin; - - fin = fdopen(in,"r"); - ret = newtable(); - ptr = buf = zalloc(bsiz = 256); - while ((c = fgetc(fin)) != EOF) - if (!qt && znspace(c)) - { - if (cnt) - { - *ptr = '\0'; - addnode(ret,strdup(buf)); - cnt = 0; - ptr = buf; - } - } - else - { - *ptr++ = c; - if (++cnt == bsiz) - { - char *pp = zalloc(bsiz *= 2); - - memcpy(pp,buf,cnt); - free(buf); - ptr = (buf = pp)+cnt; - } - } - if (qt && ptr != buf && ptr[-1] == '\n') - ptr[-1] = '\0'; - if (cnt) - addnode(ret,strdup(buf)); - free(buf); - fclose(fin); - return ret; -} - -/* =(...) */ - -char *getoutputfile(char *cmd) -{ -#ifdef WAITPID -int pid; -#endif -char *nam = gettemp(),*str; -int tfil; -list list; - - for (str = cmd; *str && *str != Outpar; str++); - if (!*str) - zerr("oops."); - *str = '\0'; - hungets(strdup(cmd)); - strinbeg(); - if (!(list = parlist(1))) - { - hflush(); - strinend(); - return NULL; - } - if (peek != EOF && peek != EMPTY) - { - strinend(); - hflush(); - return NULL; - } - strinend(); - if (!jobtab[curjob].filelist) - jobtab[curjob].filelist = newtable(); - addnode(jobtab[curjob].filelist,strdup(nam)); -#ifdef WAITPID - if (pid = phork()) - { - waitpid(pid,NULL,WUNTRACED); - return nam; - } -#else - if (waitfork()) - return nam; -#endif - subsh = 1; - close(1); - entersubsh(0); - tfil = creat(nam,0666); - exiting = 1; - execlist(list); - close(1); - exit(0); return NULL; -} - -/* get a temporary named pipe */ - -char *namedpipe(void) -{ -char *tnam = gettemp(); - - mknod(tnam,0010666,0); - return tnam; -} - -/* <(...) */ - -char *getoutproc(char *cmd) -{ -list list; -int fd; -char *pnam,*str; - - for (str = cmd; *str && *str != Outpar; str++); - if (!*str) - zerr("oops."); - *str = '\0'; - hungets(strdup(cmd)); - strinbeg(); - if (!(list = parlist(1))) - { - strinend(); - hflush(); - return NULL; - } - if (peek != EOF && peek != EMPTY) - { - strinend(); - hflush(); - return NULL; - } - strinend(); - pnam = namedpipe(); - if (!jobtab[curjob].filelist) - jobtab[curjob].filelist = newtable(); - addnode(jobtab[curjob].filelist,strdup(pnam)); - if (phork()) - return pnam; - entersubsh(1); - fd = open(pnam,O_WRONLY); - if (fd == -1) - { - zerr("can't open %s: %e",pnam,errno); - _exit(0); - } - redup(fd,1); - fd = open("/dev/null",O_RDONLY); - redup(fd,0); - exiting = 1; - execlist(list); - close(1); - _exit(0); return NULL; -} - -/* >(...) */ - -char *getinproc(char *cmd) -{ -list list; -int pid,fd; -char *pnam,*str; - - for (str = cmd; *str && *str != Outpar; str++); - if (!*str) - zerr("oops."); - *str = '\0'; - hungets(strdup(cmd)); - strinbeg(); - if (!(list = parlist(1))) - { - strinend(); - hflush(); - return NULL; - } - if (peek != EOF && peek != EMPTY) - { - strinend(); - hflush(); - return NULL; - } - strinend(); - pnam = namedpipe(); - if (!jobtab[curjob].filelist) - jobtab[curjob].filelist = newtable(); - addnode(jobtab[curjob].filelist,strdup(pnam)); - if (pid = phork()) - return pnam; - entersubsh(1); - fd = open(pnam,O_RDONLY); - redup(fd,0); - exiting = 1; - execlist(list); - _exit(0); return NULL; -} - -/* > >(...) (does not use named pipes) */ - -int getinpipe(char *cmd) -{ -list list; -int pipes[2]; -char *str = cmd; - - for (str = cmd; *str && *str != Outpar; str++); - if (!*str) - zerr("oops."); - *str = '\0'; - hungets(strdup(cmd+2)); - strinbeg(); - if (!(list = parlist(1))) - { - strinend(); - hflush(); - return -1; - } - if (peek != EOF && peek != EMPTY) - { - strinend(); - hflush(); - return NULL; - } - strinend(); - mpipe(pipes); - if (phork()) - { - close(pipes[1]); - return pipes[0]; - } - close(pipes[0]); - entersubsh(1); - redup(pipes[1],1); - exiting = 1; - execlist(list); - _exit(0); return 0; -} - -/* < <(...) */ - -int getoutpipe(char *cmd) -{ -list list; -int pipes[2]; -char *str; - - for (str = cmd; *str && *str != Outpar; str++); - if (!*str) - zerr("oops."); - *str = '\0'; - hungets(strdup(cmd+2)); - strinbeg(); - if (!(list = parlist(1))) - { - strinend(); - hflush(); - return -1; - } - if (peek != EOF && peek != EMPTY) - { - strinend(); - hflush(); - return NULL; - } - strinend(); - mpipe(pipes); - if (phork()) - { - close(pipes[0]); - return pipes[1]; - } - close(pipes[1]); - entersubsh(1); - redup(pipes[0],0); - exiting = 1; - execlist(list); - _exit(0); return 0; -} - -/* run a list, saving the current job num */ - -void runlist(list l) -{ -int cj = curjob; - - execlist(l); - curjob = cj; -} - -char *gettemp(void) -{ - return mktemp(strdup("/tmp/zshXXXXXX")); -} - -/* my getwd; all the other ones I tried confused the SIGCHLD handler */ - -char *zgetwd(void) -{ -static char buf0[MAXPATHLEN]; -char buf3[MAXPATHLEN],*buf2 = buf0+1; -struct stat sbuf; -struct direct *de; -DIR *dir; -ino_t ino = -1; -dev_t dev = -1; - - holdintr(); - buf2[0] = '\0'; - buf0[0] = '/'; - for(;;) - { - if (stat(".",&sbuf) < 0) - { - chdir(buf0); - noholdintr(); - return strdup("."); - } - ino = sbuf.st_ino; - dev = sbuf.st_dev; - if (stat("..",&sbuf) < 0) - { - chdir(buf0); - noholdintr(); - return strdup("."); - } - if (sbuf.st_ino == ino && sbuf.st_dev == dev) - { - chdir(buf0); - noholdintr(); - return strdup(buf0); - } - dir = opendir(".."); - if (!dir) - { - chdir(buf0); - noholdintr(); - return strdup("."); - } - chdir(".."); - readdir(dir); readdir(dir); - while (de = readdir(dir)) - if (de->d_fileno == ino) - { - lstat(de->d_name,&sbuf); - if (sbuf.st_dev == dev) - goto match; - } - rewinddir(dir); - readdir(dir); readdir(dir); - while (de = readdir(dir)) - { - lstat(de->d_name,&sbuf); - if (sbuf.st_dev == dev) - goto match; - } - noholdintr(); - closedir(dir); - return strdup("."); -match: - strcpy(buf3,de->d_name); - if (*buf2) - strcat(buf3,"/"); - strcat(buf3,buf2); - strcpy(buf2,buf3); - closedir(dir); - } -} - -/* open pipes with fds >= 10 */ - -void mpipe(int pp[2]) -{ - pipe(pp); - pp[0] = movefd(pp[0]); - pp[1] = movefd(pp[1]); -} - -/* do process substitution with redirection */ - -void spawnpipes(table l) -{ -Node n = l->first; -struct fnode *f; - - for (; n; n = n->next) - { - f = n->dat; - if (f->type == OUTPIPE) - { - char *str = f->u.name; - f->u.fd2 = getoutpipe(str); - free(str); - } - if (f->type == INPIPE) - { - char *str = f->u.name; - f->u.fd2 = getinpipe(str); - free(str); - } - } -} - End of exec.c echo exec.pro 1>&2 sed 's/^-//' >exec.pro <<'End of exec.pro' -void execstring(char *s); -void newrunlist(list l); -int phork(void); -void execcursh(comm comm); -void execute(char *arg0,table args); -char *findcmd(char *arg0); -void execlist(list list); -void execlist1(list list); -void execlist2(list2 list,int type,int last1); -int execpline(list2 l,int how,int last1); -void execpline2(pline pline,int how,int input,int output,int last1); -char **makecline(char *nam,struct xlist *list); -void fixcline(table l); -void untokenize(char *s); -void addenv(table list); -int dontclob(struct fnode *f); -void closemn(struct mnode *mfds[10],int fd); -void closemnodes(struct mnode *mfds[10]); -void addfd(int forked,int save[10],struct mnode *mfds[10],int fd1,int fd2,int rflag); -void execcomm(comm comm,int input,int output,int bkg,int last1); -void fixfds(int save[10]); -void entersubsh(int bkg); -void closem(void); -int gethere(char *str); -void catproc(struct mnode *mn); -void teeproc(struct mnode *mn); -void closeallelse(struct mnode *mn); -long int zstrtol(const char *s,char **t,int base); -table getoutput(char *cmd,int qt); -table readoutput(int in,int qt); -char *getoutputfile(char *cmd); -char *namedpipe(void); -char *getoutproc(char *cmd); -char *getinproc(char *cmd); -int getinpipe(char *cmd); -int getoutpipe(char *cmd); -void runlist(list l); -char *gettemp(void); -char *zgetwd(void); -void mpipe(int pp[2]); -void spawnpipes(table l); End of exec.pro echo funcs.h 1>&2 sed 's/^-//' >funcs.h <<'End of funcs.h' -/* - - funcs.h - includes for all prototype files - - 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 "glob.pro" -#include "hist.pro" -#include "table.pro" -#include "subst.pro" -#include "builtin.pro" -#include "loop.pro" -#include "jobs.pro" -#include "exec.pro" -#include "init.pro" -#include "lex.pro" -#include "parse.pro" -#include "utils.pro" -#include "test.pro" -char *readline(char *); -char *mktemp(char *); End of funcs.h echo glob.c 1>&2 sed 's/^-//' >glob.c <<'End of glob.c' -/* - - glob.c - filename generation and brace expansion - - 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" -#ifndef INT_MAX -#include -#endif -#include -#include - -#define exists(X) (access(X,0) == 0) -#define magicerr() { if (magic) putc('\n',stderr); errflag = 1; } - -static int gtype; /* file type for (X) */ -static int mode; /* != 0 if we are parsing glob patterns */ -static int sense; /* (X) or (^X) */ -static int pathpos; /* position in pathbuf */ -static int matchsz; /* size of matchbuf */ -static int matchct; /* number of matches found */ -static char pathbuf[MAXPATHLEN]; /* pathname buffer */ -static char **matchbuf; /* array of matches */ -static char **matchptr; /* &matchbuf[matchct] */ - -/* pathname component in filename patterns */ - -/* qath is a struct xpath * */ - -struct xpath { - qath next; - comp comp; - int closure; /* 1 if this is a (foo/)# */ - }; -struct xcomp { - comp nx1,nx2; - char *str; - }; - -void glob(table list,Node *np) -{ -Node node = (*np)->last; /* the node before this one */ -Node next = (*np)->next; /* the node after this one */ -int sl; /* length of the pattern */ -char *ostr; /* the pattern before the parser chops it up */ -char *wd; /* the cwd */ -qath q; /* pattern after parsing */ -char *str = (*np)->dat; /* the pattern */ - - sl = strlen(str); - ostr = strdup(str); - remnode(list,*np); - gtype = 0; - if (str[sl-1] == Outpar) /* check for (X) or (^X) */ - { - if (sl > 4 && str[sl-4] == Inpar && str[sl-3] == Hat) - sense = 1; - else if (sl > 3 && str[sl-3] == Inpar) - sense = 0; - else - sense = 2; - if (sense != 2) - { - str[sl-3-sense] = '\0'; - switch (str[sl-2]) - { - case '@': gtype = S_IFLNK; break; - case '=': gtype = S_IFSOCK; break; - case Inang: gtype = S_IFIFO; break; - case '/': gtype = S_IFDIR; break; - case '.': gtype = S_IFREG; break; - case Star: gtype = 0100; break; - case '%': gtype = S_IFCHR; break; - case 'R': gtype = 0004; break; - case 'W': gtype = 0002; break; - case 'X': gtype = 0001; break; - case 'r': gtype = 0400; break; - case 'w': gtype = 0200; break; - case 'x': gtype = 0100; break; - default: - magicerr(); - zerr("unknown file attribute"); - return; - }; - } - } - else if (str[sl-1] == '/') /* foo/ == foo(/) */ - { - gtype = S_IFDIR; - sense = 0; - } - if (*str == '/') /* pattern has absolute path */ - { - wd = zgetwd(); - str++; - chdir("/"); - pathbuf[0] = '/'; - pathbuf[pathpos = 1] = '\0'; - } - else /* pattern is relative to cwd */ - { - wd = NULL; - pathbuf[pathpos = 0] = '\0'; - } - q = parsepat(str); - if (!q || errflag) /* if parsing failed */ - { - if (isset(NOBADPATTERN)) - { - insnode(list,node,ostr); - return; - } - magicerr(); - zerr("bad pattern: %s",ostr); - free(ostr); - return; - } - matchptr = matchbuf = (char **) zalloc((matchsz = 16)*sizeof(char *)); - matchct = 0; - scanner(q); /* do the globbing */ - freepath(q); - if (wd) /* reset cwd */ - { - chdir(wd); - free(wd); - } - if (!matchct && unset(NULLGLOB)) - if (unset(NONOMATCH)) - { - if (!errflag) - { - magicerr(); - zerr("no matches found: %s",ostr); - } - free(matchbuf); - free(ostr); - errflag = 1; - return; - } - else - { - *matchptr++ = strdup(ostr); - matchct = 1; - } - qsort(&matchbuf[0],matchct,sizeof(char *),notstrcmp); - matchptr = matchbuf; - while (matchct--) /* insert matches in the arg list */ - insnode(list,node,*matchptr++); - free(matchbuf); - free(ostr); - if (magic) - magic = 2; /* tell readline we did something */ - *np = (next) ? next->last : list->last; -} - -int notstrcmp(char **a,char **b) -{ -char *c = *b,*d = *a; - - for (; *c == *d && *c; c++,d++); - return ((int) (unsigned char) *c-(int) (unsigned char) *d); -} - -/* add a match to the list */ - -void insert(char *s) -{ -struct stat buf; - - if (isset(MARKDIRS) && !lstat(s,&buf) && S_ISDIR(buf.st_mode)) /* grrr */ - { - char *t; - int ll = strlen(s); - - t = zalloc(ll+2); - strcpy(t,s); - t[ll] = '/'; - t[ll+1] = '\0'; - free(s); - s = t; - } - *matchptr++ = s; - if (++matchct == matchsz) - { - matchbuf = (char **) realloc(matchbuf,sizeof(char **)*(matchsz *= 2)); - matchptr = matchbuf+matchct; - } -} - -/* check to see if str is eligible for filename generation */ - -int haswilds(char *str) -{ - if (!str[1] && (*str == Inbrack || *str == Outbrack)) - return 0; - if (str[0] == '%') - return 0; - for (; *str; str++) - if (!strncmp(str,"..../",5)) - return 1; - else if (*str == Pound || *str == Hat || *str == Star || - *str == Bar || *str == Inbrack || *str == Inang || - *str == Quest) - return 1; - return 0; -} - -/* check to see if str is eligible for brace expansion */ - -int hasbraces(char *str) -{ -int mb,bc,cmct1,cmct2; -char *lbr = NULL; - - if (str[0] == Inbrace && str[1] == Outbrace) - return 0; - for (mb = bc = cmct1 = cmct2 = 0; *str; str++) - { - if (*str == Inbrace) - { - if (!bc) - lbr = str; - bc++; - if (str[4] == Outbrace && str[2] == '-') /* {a-z} */ - { - cmct1++; - if (bc == 1) - cmct2++; - } - } - else if (*str == Outbrace) - { - bc--; - if (!bc && !cmct2) - { - *lbr = '{'; - *str = '}'; - } - cmct2 = 0; - } - else if (*str == Comma && bc) - { - cmct1++; - if (bc == 1) - cmct2++; - } - if (bc > mb) - mb = bc; - if (bc < 0) - return 0; - } - return (mb && bc == 0 && cmct1); -} - -/* expand stuff like >>*.c */ - -int xpandredir(struct fnode *fn,table tab) -{ -table fake; -char *nam; -struct fnode *ff; -int ret = 0; - - fake = newtable(); - addnode(fake,fn->u.name); - prefork(fake); - if (!errflag) - postfork(fake,GLOB); - if (errflag) - { - freetable(fake,freestr); - return 0; - } - if (fake->first && !fake->first->next) - { - fn->u.name = fake->first->dat; - untokenize(fn->u.name); - } - else - while (nam = getnode(fake)) - { - ff = alloc(sizeof(struct fnode)); - ff->u.name = nam; - ff->type = fn->type; - addnode(tab,ff); - ret = 1; - } - free(fake); - return ret; -} - -/* concatenate s1 and s2 in dynamically allocated buffer */ - -char *dyncat(char *s1,char *s2) -{ -char *ptr; - - ptr = zalloc(strlen(s1)+strlen(s2)+1); - strcpy(ptr,s1); - strcat(ptr,s2); - return ptr; -} - -/* concatenate s1, s2, and s3 in dynamically allocated buffer */ - -char *tricat(char *s1,char *s2,char *s3) -{ -char *ptr; - - ptr = zalloc(strlen(s1)+strlen(s2)+strlen(s3)+1); - strcpy(ptr,s1); - strcat(ptr,s2); - strcat(ptr,s3); - return ptr; -} - -/* brace expansion */ - -void xpandbraces(table list,Node *np) -{ -Node node = (*np),last = node->last; -char *str = node->dat,*str3 = str,*str2; -int prev; - - if (magic) - magic = 2; - for (; *str != Inbrace; str++); - if (str[2] == '-' && str[4] == Outbrace) /* {a-z} */ - { - char c1,c2; - - remnode(list,node); - chuck(str); - c1 = *str; - chuck(str); - chuck(str); - c2 = *str; - chuck(str); - if (istok(c1)) - c1 = tokens[c1-Pound]; - if (istok(c2)) - c2 = tokens[c2-Pound]; - if (c1 < c2) - for (; c2 >= c1; c2--) /* {a-z} */ - { - *str = c2; - insnode(list,last,strdup(str3)); - } - else - for (; c2 <= c1; c2++) /* {z-a} */ - { - *str = c2; - insnode(list,last,strdup(str3)); - } - free(str3); - *np = last->next; - return; - } - prev = str-str3; - str2 = getparen(str++); - if (!str2) - { - errflag = 1; - zerr("how did you get this error?"); - return; - } - remnode(list,node); - node = last; - FOREVER - { - char *zz,*str4; - int cnt; - - for (str4 = str, cnt = 0; cnt || *str != Comma && *str != - Outbrace; str++) - if (*str == Inbrace) - cnt++; - else if (*str == Outbrace) - cnt--; - else if (!*str) - exit(10); - zz = zalloc(prev+(str-str4)+strlen(str2)+1); - strncpy(zz,str3,prev); - zz[prev] = '\0'; - strncat(zz,str4,str-str4); - strcat(zz,str2); - insnode(list,node,zz); - node = node->next; - if (*str != Outbrace) - str++; - else - break; - } - free(str3); - *np = last->next; -} - -/* get closing paren, given pointer to opening paren */ - -char *getparen(char *str) -{ -int cnt = 1; -char typein = *str++,typeout = typein+1; - - for (; *str && cnt; str++) - if (*str == typein) - cnt++; - else if (*str == typeout) - cnt--; - if (!str && cnt) - return NULL; - return str; -} - -/* check to see if a matches b (b is not a filename pattern) */ - -int matchpat(char *a,char *b) -{ -comp c; -int val; - - c = parsereg(b); - if (!c) - { - zerr("bad pattern: %s"); - errflag = 1; - return NULL; - } - val = doesmatch(a,c,0); - freecomp(c); - return val; -} - -/* do the ${foo%%bar}, ${foo#bar} stuff */ -/* please do not laugh at this code. */ - -void getmatch(char **sp,char *pat,int dd) -{ -comp c; -char *t,*lng = NULL,cc,*s = *sp; - - c = parsereg(pat); - if (!c) - { - magicerr(); - zerr("bad pattern: %s",pat); - return; - } - if (!(dd & 2)) - { - for (t = s; t==s || t[-1]; t++) - { - cc = *t; - *t = '\0'; - if (doesmatch(s,c,0)) - { - if (!(dd & 1)) - { - *t = cc; - t = strdup(t); - free(s); - freecomp(c); - *sp = t; - return; - } - lng = t; - } - *t = cc; - } - if (lng) - { - t = strdup(lng); - free(s); - freecomp(c); - *sp = t; - return; - } - } - else - { - for (t = s+strlen(s); t >= s; t--) - { - if (doesmatch(t,c,0)) - { - if (!(dd & 1)) - { - *t = '\0'; - freecomp(c); - return; - } - lng = t; - } - } - if (lng) - { - *lng = '\0'; - freecomp(c); - return; - } - } - freecomp(c); -} - -/* add a component to pathbuf */ - -void addpath(char *s) -{ - while (pathbuf[pathpos++] = *s++); - pathbuf[pathpos-1] = '/'; - pathbuf[pathpos] = '\0'; -} - -/* do the globbing */ - -void scanner(qath q) -{ -comp c; - - if (q->closure) /* (foo/)# */ - if (q->closure == 2) /* (foo/)## */ - q->closure = 1; - else - scanner(q->next); - if (c = q->comp) - { - if (!(c->nx1 || c->nx2) && !haswilds(c->str)) - if (q->next) - { - char *wd = NULL; - - if (errflag) - return; - if (islink(c->str) || !strcmp(c->str,"..")) - wd = zgetwd(); - if (!chdir(c->str)) - { - int oppos = pathpos; - - addpath(c->str); - scanner((q->closure) ? q : q->next); - if (wd) - chdir(wd); - else if (strcmp(c->str,".")) - chdir(".."); - pathbuf[pathpos = oppos] = '\0'; - } - else - { - magicerr(); - zerr("%e: %s",errno,c->str); - if (wd) - chdir(wd); - else if (strcmp(c->str,".")) - chdir(".."); - return; - } - } - else - { - if (exists(c->str)) - insert(dyncat(pathbuf,c->str)); - } - else - { - char *fn; - int type,type3,dirs = !!q->next; - struct direct *de; - DIR *lock = opendir("."); - static struct stat buf; - - if (lock == NULL) - { - magicerr(); - if (errno != EINTR) - zerr("%e: %s",errno,pathbuf); - return; - } - readdir(lock); readdir(lock); /* skip . and .. */ - while (de = readdir(lock)) - { - if (errflag) - break; - fn = &de->d_name[0]; - if (dirs) - { - if (lstat(fn,&buf) == -1) - { - magicerr(); - zerr("%e: %s",errno,fn); - } - type3 = buf.st_mode & S_IFMT; - if (type3 != S_IFDIR) - continue; - } - else - if (gtype) /* do the (X) (^X) stuff */ - { - if (lstat(fn,&buf) == -1) - { - if (errno != ENOENT) - { - magicerr(); - zerr("%e: %s",errno,fn); - } - continue; - } - type3 = (type = buf.st_mode) & S_IFMT; - if (gtype & 0777) - { - if ((!(type & gtype) ^ sense) || type3 == S_IFLNK) - continue; - } - else if (gtype == S_IFCHR) - { - if ((type3 != S_IFCHR && type3 != S_IFBLK) ^ sense) - continue; - } - else if ((gtype != type3) ^ sense) - continue; - } - if (doesmatch(fn,c,unset(GLOBDOTS))) - if (dirs) - { - if (!chdir(fn)) - { - int oppos = pathpos; - - addpath(fn); - scanner((q->closure) ? q : q->next); /* scan next level */ - chdir(".."); - pathbuf[pathpos = oppos] = '\0'; - } - } - else - insert(dyncat(pathbuf,fn)); - } - closedir(lock); - } - } - else - { - zerr("no idea how you got this error message."); - errflag = 1; - } -} - -/* do the [..(foo)..] business */ - -int minimatch(char **pat,char **str) -{ -char *pt = *pat+1,*s = *str; - - for (; *pt != Outpar; s++,pt++) - if ((*pt != Quest || !*s) && *pt != *s) - { - *pat = getparen(*pat)-1; - return 0; - } - *str = s-1; - return 1; -} - -/* see if str matches c; first means worry about matching . explicitly */ - -int doesmatch(char *str,comp c,int first) -{ -char *pat = c->str; - - FOREVER - { - if (!*pat) - { - if (errflag) - return 0; - if (!(*str || c->nx1 || c->nx2)) - return 1; - return (c->nx1 && doesmatch(str,c->nx1,first)) || - (c->nx2 && doesmatch(str,c->nx2,first)); - } - if (first && *str == '.' && *pat != '.') - return 0; - if (*pat == Star) /* final * is not expanded to ?#; returns success */ - return 1; - first = 0; - if (*pat == Quest && *str) - { - str++; - pat++; - continue; - } - if (*pat == Hat) - return 1-doesmatch(str,c->nx1,first); - if (*pat == Inbrack) - if (pat[1] == Hat) - { - for (pat += 2; *pat != Outbrack && *pat; pat++) - if (*pat == '-' && pat[-1] != Hat && pat[1] != Outbrack) - { - if (pat[-1] <= *str && pat[1] >= *str) - break; - } - else if (*str == *pat) - break; - if (!*pat) - { - zerr("something is very wrong."); - return 0; - } - if (*pat != Outbrack) - break; - pat++; - str++; - continue; - } - else - { - for (pat++; *pat != Outbrack && *pat; pat++) - if (*pat == Inpar) - { - if (minimatch(&pat,&str)) - break; - } - else if (*pat == '-' && pat[-1] != Inbrack && pat[1] != Outbrack) - { - if (pat[-1] <= *str && pat[1] >= *str) - break; - } - else if (*str == *pat) - break; - if (!pat || !*pat) - { - zerr("oh dear. that CAN'T be right."); - return 0; - } - if (*pat == Outbrack) - break; - for (str++; *pat != Outbrack; pat++); - pat++; - continue; - } - if (*pat == Inang) - { - int t1,t2,t3; - char *ptr; - - if (*++pat == Outang) /* handle <> case */ - { - (void) zstrtol(str,&ptr,10); - if (ptr == str) - break; - str = ptr; - pat++; - } - else - { - t1 = zstrtol(str,&ptr,10); - if (ptr == str) - break; - str = ptr; - t2 = zstrtol(pat,&ptr,10); - if (*ptr != '-') - exit(31); - t3 = zstrtol(ptr+1,&pat,10); - if (!t3) - t3 = INT_MAX; - if (*pat++ != Outang) - exit(21); - if (t1 < t2 || t1 > t3) - break; - } - continue; - } - if (*str == *pat) - { - str++; - pat++; - continue; - } - break; - } - return 0; -} - -static char *pptr; - -qath parsepat(char *str) -{ - mode = 0; - pptr = str; - return parseqath(); -} - -comp parsereg(char *str) -{ - mode = 1; - pptr = str; - return parsecompsw(); -} - -qath parseqath(void) -{ -comp c1; -qath p1; - - if (pptr[0] == '.' && pptr[1] == '.' && pptr[2] == '.' && pptr[3] == - '.' && pptr[4] == '/') - { - pptr[0] = Inpar; - pptr[1] = Star; - pptr[2] = '/'; - pptr[3] = Outpar; - pptr[4] = Pound; /* "..../" -> "( * /)#" */ - } - if (*pptr == Inpar) - { - char *str; - int pars = 1; - - for (str = pptr+1; *str && pars; str++) - if (*str == Inpar) - pars++; - else if (*str == Outpar) - pars--; - if (str[0] != Pound || str[-1] != Outpar || str[-2] != '/') - goto kludge; - pptr++; - if (!(c1 = parsecompsw())) - return NULL; - if (pptr[0] == '/' && pptr[1] == Outpar && pptr[2] == Pound) - { - int pdflag = 0; - - pptr += 3; - if (*pptr == Pound) - { - pdflag = 1; - pptr++; - } - p1 = (qath) alloc(sizeof(struct xpath)); - p1->comp = c1; - p1->closure = 1+pdflag; - p1->next = parseqath(); - return (p1->comp) ? p1 : NULL; - } - } - else - { -kludge: - if (!(c1 = parsecompsw())) - return NULL; - if (*pptr == '/' || !*pptr) - { - int ef = *pptr == '/'; - - p1 = (qath) alloc(sizeof(struct xpath)); - p1->comp = c1; - p1->closure = 0; - p1->next = (*pptr == '/') ? (pptr++,parseqath()) : NULL; - return (ef && !p1->next) ? NULL : p1; - } - } - magicerr(); - errflag = 1; - return NULL; -} - -comp parsecomp(void) -{ -comp c = (comp) alloc(sizeof(struct xcomp)),c1,c2; -char *s = c->str = alloc(MAXPATHLEN*2),*ls = NULL; - - c->nx2 = NULL; - while (*pptr && (mode || *pptr != '/') && *pptr != Bar && - *pptr != Outpar) - { - if (*pptr == Hat) - { - *s++ = Hat; - *s++ = '\0'; - pptr++; - if (!(c->nx1 = parsecomp())) - { - free(c->str); - free(c); - return NULL; - } - return c; - } - if (*pptr == Star && pptr[1] && (mode || pptr[1] != '/')) - { - *s++ = '\0'; - pptr++; - c->nx1 = c1 = (comp) alloc(sizeof(struct xcomp)); - *((c1->nx1 = c1)->str = strdup("?")) = Quest; - c->nx2 = c1->nx2 = parsecomp(); - return (c->nx2) ? c : NULL; - } - if (*pptr == Inpar) - { - *s++ = '\0'; - pptr++; - c->nx1 = c1 = parsecompsw(); - if (*pptr != Outpar) - { - errflag = 1; - free(c); - free(c->str); - return NULL; - } - pptr++; - if (*pptr == Pound) - { - int dpnd = 0; - - pptr++; - if (*pptr == Pound) - { - pptr++; - dpnd = 1; - } - c2 = parsecomp(); - if (dpnd) - c->nx2 = NULL; - else - c->nx2 = c2; - if (!c2) - { - free(c); - free(c->str); - return NULL; - } - adjustcomp(c1,c2,c1); - return c; - } - c2 = parsecomp(); - if (!c2) - { - free(c); - free(c->str); - return NULL; - } - adjustcomp(c1,c2,NULL); - return c; - } - if (*pptr == Pound) - { - int dpnd = 0; - - *s = '\0'; - pptr++; - if (*pptr == Pound) - { - pptr++; - dpnd = 1; - } - if (!ls) - return NULL; - c->nx1 = c1 = (comp) alloc(sizeof(struct xcomp)); - (c1->nx2 = c1)->str = strdup(ls); - c->nx2 = c1->nx1 = parsecomp(); - if (!c->nx2) - { - free(c); - free(c->str); - return NULL; - } - if (dpnd) - c->nx2 = NULL; - *ls++ = '\0'; - return c; - } - ls = s; - if (*pptr == Inang) - { - int dshct; - - dshct = (pptr[1] == Outang); - *s++ = *pptr++; - while (*pptr && (*s++ = *pptr++) != Outang) - if (s[-1] == '-') - dshct++; - else if (!isdigit(s[-1])) - break; - if (s[-1] != Outang || dshct != 1) - { - free(c); - free(c->str); - return NULL; - } - } - else if (*pptr == Inbrack) - { - while (*pptr && (*s++ = *pptr++) != Outbrack); - if (s[-1] != Outbrack) - { - free(c); - free(c->str); - return NULL; - } - } - else if (istok(*pptr) && *pptr != Star && *pptr != Quest) - *s++ = tokens[*pptr++-Pound]; - else - *s++ = *pptr++; - } - *s++ = '\0'; - c->nx1 = NULL; - return c; -} - -comp parsecompsw(void) -{ -comp c1,c2,c3; - - c1 = parsecomp(); - if (!c1) - return NULL; - if (*pptr == Bar) - { - c2 = (comp) alloc(sizeof(struct xcomp)); - pptr++; - c3 = parsecompsw(); - if (!c3) - return NULL; - c2->str = strdup(""); - c2->nx1 = c1; - c2->nx2 = c3; - return c2; - } - return c1; -} - -#define MARKER ((void *) 1L) - -void adjustcomp(comp c1,comp c2,comp c3) -{ -comp z; - - if (c1->nx1 == c2 && c1->nx2 == c3) - return; - if (c1->nx1) - { - if ((z = c1->nx1) == MARKER) - return; - c1->nx1 = MARKER; - adjustcomp(z,c2,c3); - c1->nx1 = z; - } - if (c1->nx2) - adjustcomp(c1->nx2,c2,c3); - if (!(c1->nx1 || c1->nx2)) - { - c1->nx1 = c2; - c1->nx2 = c3; - } -} - -void freepath(qath p) -{ - if (p) - { - freepath(p->next); - freecomp(p->comp); - free(p); - } -} - -void freecomp(comp c) -{ - if (c && c->str) - { - free(c->str); - c->str = NULL; - freecomp(c->nx1); - freecomp(c->nx2); - free(c); - } -} - -/* tokenize and see if ss matches tt */ - -int patmatch(char *ss,char *tt) -{ -char *s = ss,*t; - - for (; *s; s++) - if (*s == '\\') - chuck(s); - else - for (t = tokens; *t; t++) - if (*t == *s) - { - *s = (t-tokens)+Pound; - break; - } - return matchpat(ss,tt); -} - -/* remove unnecessary Nulargs */ - -void remnulargs(char *s) -{ -int nl = *s; -char *t = s; - - while (*s) - if (*s == Nularg) - chuck(s); - else - s++; - if (!*t && nl) - { - t[0] = Nularg; - t[1] = '\0'; - } -} - End of glob.c echo glob.pro 1>&2 sed 's/^-//' >glob.pro <<'End of glob.pro' -void glob(table list,Node *np); -int notstrcmp(char **a,char **b); -void insert(char *s); -int haswilds(char *str); -int hasbraces(char *str); -int xpandredir(struct fnode *fn,table tab); -char *dyncat(char *s1,char *s2); -char *tricat(char *s1,char *s2,char *s3); -void xpandbraces(table list,Node *np); -char *getparen(char *str); -int matchpat(char *a,char *b); -void getmatch(char **sp,char *pat,int dd); -void addpath(char *s); -void scanner(qath q); -int minimatch(char **pat,char **str); -int doesmatch(char *str,comp c,int first); -qath parsepat(char *str); -comp parsereg(char *str); -qath parseqath(void); -comp parsecomp(void); -comp parsecompsw(void); -void adjustcomp(comp c1,comp c2,comp c3); -void freepath(qath p); -void freecomp(comp c); -int patmatch(char *ss,char *tt); -void remnulargs(char *s); End of glob.pro echo hist.c 1>&2 sed 's/^-//' >hist.c <<'End of hist.c' -/* - - hist.c - ! history - - 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" - -int lastc; - -/* add a character to the current history word */ - -void hwaddc(int c) -{ - if (hlastw) - { - if (c == EOF || c == HERR) - return; - *hlastp++ = c; - if (hlastp-hlastw == hlastsz) - { - hlastw = realloc(hlastw,hlastsz *= 2); - hlastp = hlastw+(hlastsz/2); - } - } -} - -#define habort() { errflag = 1; return HERR; } - -/* get a character after performing history substitution */ - -int hgetc(void) -{ -int c,ev,farg,larg,argc,marg = -1,cflag = 0,bflag = 0; -char buf[256],*ptr; -table slist,elist; - -tailrec: - c = hgetch(); - if (stophist) - { - hwaddc(c); - return c; - } - if (firstch && c == '^' && !(ungots && !magic)) - { - firstch = 0; - hungets(strdup(":s^")); - c = '!'; - goto hatskip; - } - if (c != ' ') - firstch = 0; - if (c == '\\') - { - int g = hgetch(); - - if (g != '!') - hungetch(g); - else - { - hwaddc('!'); - return '!'; - } - } - if (c != '!' || (ungots && !magic)) - { - hwaddc(c); - return c; - } -hatskip: - if ((c = hgetch()) == '{') - { - bflag = cflag = 1; - c = hgetch(); - } - if (c == '\"') - { - stophist = 1; - goto tailrec; - } - if (!cflag && znspace(c) || c == '=' || c == '(') - { - hungetch(c); - hwaddc('!'); - return '!'; - } - cflag = 0; - ptr = buf; - - /* get event number */ - - if (c == '?') - { - FOREVER - { - c = hgetch(); - if (c == '?' || c == '\n') - break; - else - *ptr++ = c; - } - if (c != '\n') - c = hgetch(); - *ptr = NULL; - ev = hconsearch(last = strdup(buf),&marg); - if (ev == -1) - { - herrflush(); - zerr("no such event: %s",buf); - habort(); - } - } - else - { - int t0; - - FOREVER - { - if (znspace(c) || c == ':' || c == '^' || c == '$' || c == '*' - || c == '%' || c == '}') - break; - if (ptr != buf && c == '-') - break; - *ptr++ = c; - if (c == '#' || c == '!') - { - c = hgetch(); - break; - } - c = hgetch(); - } - *ptr = 0; - if (!*buf) - ev = dev; - else if (t0 = atoi(buf)) - ev = (t0 < 0) ? cev+t0 : t0; - else if (*buf == '!') - ev = cev-1; - else if (*buf == '#') - ev = cev; - else if ((ev = hcomsearch(buf)) == -1) - { - zerr("event not found: %s",buf); - while (c != '\n') - c = hgetch(); - habort(); - } - } - - /* get the event */ - - if (!(elist = getevent(dev = ev))) - habort(); - - /* extract the relevant arguments */ - - argc = getargc(elist)-1; - if (c == ':') - { - cflag = 1; - c = hgetch(); - } - if (c == '*') - { - farg = 1; - larg = argc; - cflag = 0; - } - else - { - hungetch(c); - larg = farg = getargspec(argc,marg); - if (larg == -2) - habort(); - if (farg != -1) - cflag = 0; - c = hgetch(); - if (c == '*') - { - cflag = 0; - larg = argc; - } - else if (c == '-') - { - cflag = 0; - larg = getargspec(argc,marg); - if (larg == -2) - habort(); - if (larg == -1) - larg = argc-1; - } - else - hungetch(c); - } - if (farg == -1) - farg = 0; - if (larg == -1) - larg = argc; - if (!(slist = getargs(elist,farg,larg))) - habort(); - - /* do the modifiers */ - - FOREVER - { - c = (cflag) ? ':' : hgetch(); - cflag = 0; - if (c == ':') - { - int gbal = 0; - - if ((c = hgetch()) == 'g') - { - gbal = 1; - c = hgetch(); - } - switch(c) - { - case 'p': - hflag = 2; - break; - case 'h': - if (!apply1(gbal,remtpath,slist)) - { - herrflush(); - zerr("modifier failed: h"); - habort(); - } - break; - case 'e': - if (!apply1(gbal,rembutext,slist)) - { - herrflush(); - zerr("modifier failed: e"); - habort(); - } - break; - case 'r': - if (!apply1(gbal,remtext,slist)) - { - herrflush(); - zerr("modifier failed: r"); - habort(); - } - break; - case 't': - if (!apply1(gbal,remlpaths,slist)) - { - herrflush(); - zerr("modifier failed: t"); - habort(); - } - break; - case 's': - { - int del; - char *ptr1,*ptr2; - - del = hgetch(); - ptr1 = hdynread(del); - if (!ptr1) - habort(); - ptr2 = hdynread2(del); - if (strlen(ptr1)) - { - if (last) - free(last); - last = ptr1; - } - if (rast) - free(rast); - rast = ptr2; - } - case '&': - if (last && rast) - { - if (subst(gbal,slist,last,rast)) - habort(); - } - else - { - herrflush(); - zerr("no previous substitution with &"); - habort(); - } - break; - case 'q': - apply1(0,quote,slist); - break; - case 'x': - apply1(0,quotebreak,slist); - break; - default: - herrflush(); - zerr("illegal modifier: %c",c); - habort(); - break; - } - } - else - { - if (c != '}' || !bflag) - hungetch(c); - if (c != '}' && bflag) - { - zerr("'}' expected"); - habort(); - } - break; - } - } - - /* stuff the resulting string in the input queue and start over */ - - hungets(makehlist(slist,1)); - hflag |= 1; - goto tailrec; -} - -/* begin reading a string */ - -void strinbeg(void) -{ - strin = 1; -} - -/* done reading a string */ - -void strinend(void) -{ - strin = 0; - firstch = 1; - hflag = 0; - free(ungots); - ungotptr = ungots = NULL; - peek = EMPTY; -} - -static char *line = NULL,*oline = NULL; - -/* stuff a whole FILE into the input queue */ - -int stuff(char *fn) -{ -FILE *in; -char *buf; -int len; - - if (!(in = fopen(fn,"r"))) - { - zerr("can't open %s",fn); - return 1; - } - fseek(in,0,2); - len = ftell(in); - fseek(in,0,0); - buf = alloc(len+1); - if (!(fread(buf,len,1,in))) - { - zerr("read error on %s",fn); - fclose(fn); - free(buf); - return 1; - } - fclose(in); - if (!line) - line = oline = buf; - else - { - line = dyncat(line,buf); - free(oline); - oline = line; - } - return 0; -} - -/* get a char without history */ - -int hgetch(void) -{ -char *pmpt = NULL,*s; - - if (ungots) - { - if (*ungotptr) - { - if (*ungotptr == ALPOP) /* done expanding an alias, - pop the alias stack */ - { - if (!alix) - { - ungotptr++; - return lastc = HERR; - } - alstack[--alix]->inuse = 0; - s = alstack[alix]->text; - if (*s && s[strlen(s)-1] == ' ') - alstat = ALSTAT_MORE; - else - alstat = ALSTAT_JUNK; - ungotptr++; - return lastc = hgetch(); - } - return lastc = *ungotptr++; - } - if (strin) - return lastc = EOF; - ungotptr = 0; - free(ungots); - ungots = NULL; - } -kludge: - if (errflag) - { - if (oline) - free(oline); - oline = line = NULL; - return lastc = HERR; - } - if (line && *line) - return lastc = (*line++); - if (line) - free(oline); - if (interact) - if (!firstln) - pmpt = putprompt("PROMPT2"); - else - pmpt = putprompt("PROMPT"); - if (interact && SHTTY == -1) - write(2,pmpt,strlen(pmpt)); - oline = line = (interact && SHTTY != -1) ? readline(pmpt) : - fgets(zalloc(256),256,bshin); - if (isset(VERBOSE) && line) - fputs(line,stderr); - if (!line) - return lastc = EOF; - if (line[strlen(line)-1] == '\n') - lineno++; - firstch = 1; - firstln = 0; - goto kludge; -} - -/* unget a character */ - -void hungetch(int c) -{ -static char ubuf2[] = {'x',0}; - - if (c == EOF) - return; - ubuf2[0] = c; - hungets(strdup(ubuf2)); -} - -/* unget a character and remove it from the history word */ - -void hungetc(int c) -{ - if (hlastw) - { - if (hlastw == hlastp) - zerr("hungetc attempted at buffer start"); - else - hlastp--; - } - hungetch(c); -} - -void hflush(void) -{ - if (ungots) - free(ungots); - ungots = ungotptr = NULL; -} - -/* unget a string into the input queue */ - -void hungets(char *str) -{ - if (ungots && !*ungotptr) - { - free(ungots); - ungots = NULL; - } - if (ungots) - { - char *ptr; - - ptr = dyncat(str,ungotptr); - free(ungots); - free(str); - ungotptr = ungots = ptr; - } - else - ungots = ungotptr = str; -} - -/* initialize the history mechanism */ - -void hbegin(void) -{ - firstln = firstch = 1; - histremmed = errflag = hflag = 0; - stophist = isset(NOBANGHIST); - if (interact) - { - inittty(); - dev = cev++; - while (cev-tfev >= tevs) - { - freetable(getnode(histlist),freestr); - tfev++; - } - addnode(histlist,curtab = newtable()); - } -} - -void inittty(void) -{ - attachtty(shpgrp); - settyinfo(&shttyinfo); -} - -/* say we're done using the history mechanism */ - -int hend(void) -{ -char *ptr; -int flag; - - if (!interact) - return 1; - if (!curtab) - return 0; - flag = hflag; - hflag = 0; - if (curtab->first && (*(char *) curtab->last->dat == '\n')) - free(remnode(curtab,curtab->last)); - if (!curtab->first) - { - freetable(remnode(histlist,histlist->last),freestr); - cev--; - flag = 0; - } - if (flag) - { - fprintf(stderr,"%s\n",ptr = makehlist(curtab,0)); - free(ptr); - } - curtab = NULL; - return !(flag & 2 || errflag); -} - -/* remove the current line from the history list */ - -void remhist(void) -{ - if (!interact) - return; - if (!histremmed) - { - histremmed = 1; - freetable(remnode(histlist,histlist->last),freestr); - cev--; - } -} - -/* begin a word */ - -void hwbegin(void) -{ - if (hlastw) - free(hlastw); - hlastw = hlastp = zalloc(hlastsz = 32); -} - -/* add a word to the history list */ - -char *hwadd(void) -{ -char *ret = hlastw; - - if (hlastw) - *hlastp = '\0'; - if (hlastw && lastc != EOF && !errflag) - if (curtab && !alix/* && alstat != ALSTAT_JUNK*/) - { - addnode(curtab,hlastw); - hlastw = NULL; - } - if (alstat == ALSTAT_JUNK) - alstat = 0; - return ret; -} - -/* get an argument specification */ - -int getargspec(int argc,int marg) -{ -int c,ret = -1; - - if ((c = hgetch()) == '0') - return 0; - if (isdigit(c)) - { - ret = 0; - while (isdigit(c)) - { - ret = ret*10+c-'0'; - c = hgetch(); - } - hungetch(c); - } - else if (c == '^') - ret = 1; - else if (c == '$') - ret = argc; - else if (c == '%') - { - if (marg == -1) - { - herrflush(); - zerr("%% with no previous word matched"); - return -2; - } - ret = marg; - } - else - hungetch(c); - return ret; -} - -/* do ?foo? search */ - -int hconsearch(char *str,int *marg) -{ -int t0,t1; -Node node,node2; - - if (cev-tfev < 1) - return -1; - for (t0 = cev-1,node = histlist->last->last; - t0 >= tfev; t0--,node = node->last) - for (t1 = 0,node2 = ((table) node->dat)->first; node2; t1++,node2 = - node2->next) - if (strstr(node2->dat,str)) - { - *marg = t1; - return t0; - } - return -1; -} - -/* do !foo search */ - -int hcomsearch(char *str) -{ -int t0; -Node node,node2; - - if (cev-tfev < 1) - return -1; - for (t0 = cev-1,node = histlist->last->last; t0 >= tfev; - t0--,node = node->last) - if ((node2 = ((table) node->dat)->first)->dat && - strstr(node2->dat,str)) - return t0; - return -1; -} - -/* apply func to a list */ - -int apply1(int gflag,int (*func)(void **),table list) -{ -Node node; -int flag = 0; - - for (node = list->first; node; node = node->next) - if ((flag |= func(&node->dat)) && !gflag) - return 1; - return flag; -} - -/* various utilities for : modifiers */ - -int remtpath(void **junkptr) -{ -char *str = *junkptr,*cut; - - if (cut = strrchr(str,'/')) - { - *cut = NULL; - return 1; - } - return 0; -} - -int remtext(void **junkptr) -{ -char *str = *junkptr,*cut; - - if ((cut = strrchr(str,'.')) && cut != str) - { - *cut = NULL; - return 1; - } - return 0; -} - -int rembutext(void **junkptr) -{ -char *str = *junkptr,*cut; - - if ((cut = strrchr(str,'.')) && cut != str) - { - *junkptr = strdup(cut+1); /* .xx or xx? */ - free(str); - return 1; - } - return 0; -} - -int remlpaths(void **junkptr) -{ -char *str = *junkptr,*cut; - - if (cut = strrchr(str,'/')) - { - *cut = NULL; - *junkptr = strdup(cut+1); - free(str); - return 1; - } - return 0; -} - -int subst(int gbal,table slist,char *ptr1,char *ptr2) -{ -Node node; -int iflag = 0; - - for (node = slist->first; node; ) - if (subststr(&node->dat,ptr1,ptr2,gbal)) - { - iflag = 1; - if (!gbal) - return 0; - } - else - node = node->next; - if (!iflag) - { - herrflush(); - zerr("string not found: %s",ptr1); - return 1; - } - return 0; -} - -int subststr(void **strptr,char *in,char *out,int gbal) -{ -char *str = *strptr,*cut,*sptr,*ss; -int ret = 0; - -maze: - if (cut = (char *) strstr(str,in)) - { - char *incop; - - incop = strdup(in); - *cut = '\0'; - cut += strlen(in); - ss = *strptr; - *strptr = tricat(*strptr,sptr = convamps(out,incop),cut); - free(ss); - free(sptr); - free(incop); - if (gbal) - { - str = (char *) *strptr+(cut-str)+strlen(in); - ret = 1; - goto maze; - } - return 1; - } - return ret; -} - -char *convamps(char *out,char *in) -{ -char *ptr,*ret,*pp; -int slen,inlen = strlen(in); - - for (ptr = out, slen = 0; *ptr; ptr++,slen++) - if (*ptr == '\\') - ptr++; - else if (*ptr == '&') - slen += inlen-1; - ret = pp = zalloc(slen+1); - for (ptr = out; *ptr; ptr++) - if (*ptr == '\\') - *pp++ = *++ptr; - else if (*ptr == '&') - { - strcpy(pp,in); - pp += inlen; - } - else - *pp++ = *ptr; - *pp = '\0'; - return ret; -} - -/* make a string out of a history list */ - -char *makehlist(table tab,int freeit) -{ -int ccnt; -Node node; -char *ret,*ptr; -char sep = *ifs; - - for (ccnt = 0, node = (freeit == 2) ? tab->first->next : tab->first; - node; node = node->next) - ccnt += strlen(node->dat)+1; - if (!ccnt) - return strdup(""); - ptr = ret = zalloc(ccnt); - for (node = (freeit == 2) ? tab->first->next : tab->first; - node; node = node->next) - { - strcpy(ptr,node->dat); - ptr += strlen(node->dat); - if (freeit == 1) - free(node->dat); - *ptr++ = sep; - } - *--ptr = '\0'; - return ret; -} - -table quietgetevent(int ev) -{ -Node node; - - ev -= tfev; - for (node = histlist->first; ev && node; node = node->next, ev--); - if (ev) - return NULL; - return node->dat; -} - -table getevent(int ev) -{ -Node node; -int oev = ev; - - ev -= tfev; - for (node = histlist->first; ev && node; node = node->next, ev--); - if (ev || !node) - { - herrflush(); - zerr("no such event: %d",oev); - return NULL; - } - return node->dat; -} - -int getargc(table tab) -{ -int argc; -Node node; - - for (argc = 0, node = tab->first; node; node = node->next, argc++); - return argc; -} - -table getargs(table elist,int arg1,int arg2) -{ -table ret = newtable(); -Node node; -int oarg1 = arg1,oarg2 = arg2; - - for (node = elist->first; arg1 && node; node = node->next, arg1--,arg2--); - if (!node) - { - herrflush(); - zerr("no such word in event: %d",oarg1); - return NULL; - } - for (arg2++; arg2 && node; node = node->next, arg2--) - addnode(ret,strdup(node->dat)); - if (arg2 && !node) - { - herrflush(); - zerr("no such word in event: %d",oarg2); - return NULL; - } - return ret; -} - -int quote(void **tr) -{ -char *ptr,*rptr,**str = (char **) tr; -int len = 1; - - for (ptr = *str; *ptr; ptr++,len++) - if (*ptr == '\'') - len += 3; - ptr = *str; - *str = rptr = alloc(len); - for (ptr = *str; *ptr; ) - if (*ptr == '\'') - { - *rptr++ = '\''; - *rptr++ = '\\'; - *rptr++ = '\''; - *rptr++ = '\''; - ptr++; - } - else - *rptr++ = *ptr++; - return 0; -} - -int quotebreak(void **tr) -{ -char *ptr,*rptr,**str = (char **) tr; -int len = 1; - - for (ptr = *str; *ptr; ptr++,len++) - if (*ptr == '\'') - len += 3; - else if (znspace(*ptr)) - len += 2; - ptr = *str; - *str = rptr = alloc(len); - for (ptr = *str; *ptr; ) - if (*ptr == '\'') - { - *rptr++ = '\''; - *rptr++ = '\\'; - *rptr++ = '\''; - *rptr++ = '\''; - ptr++; - } - else if (znspace(*ptr)) - { - *rptr++ = '\''; - *rptr++ = *ptr++; - *rptr++ = '\''; - } - else - *rptr++ = *ptr++; - return 0; -} - -void stradd(char **p,char *d) -{ -char *s = *p; - - while (*s++ = *d++); - *p = s-1; -} - -/* get a prompt string */ - -char *putprompt(char *fm) -{ -char *ss,*ttyname(int); -static char buf[256]; -char *bp = buf; -int t0; -struct tm *tm = NULL; -time_t timet; - - clearerr(stdin); - fm = getparm(fm); - for(;*fm;fm++) - { - if (bp-buf >= 220) - break; - if (*fm == '%') - switch (*++fm) - { - case '~': - if (!strncmp(cwd,home,t0 = strlen(home))) - { - *bp++ = '~'; - stradd(&bp,cwd+t0); - break; - } - case 'd': - case '/': - stradd(&bp,cwd); - break; - case 'c': - case '.': - for (ss = cwd+strlen(cwd); ss > cwd; ss--) - if (*ss == '/') - { - ss++; - break; - } - stradd(&bp,ss); - break; - case 'h': - case '!': - sprintf(bp,"%d",cev); - bp += strlen(bp); - break; ---cut here---cut here---cut here---