home *** CD-ROM | disk | FTP | other *** search
- 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 <limits.h>
- -#endif
- -#include <sys/dir.h>
- -#include <sys/errno.h>
- -
- -#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---
-