home *** CD-ROM | disk | FTP | other *** search
- From: pfalstad@phoenix.Princeton.EDU (Paul John Falstad)
- Newsgroups: alt.sources
- Subject: zsh - ksh/tcsh-like shell (part 4 of 8)
- Message-ID: <4745@idunno.Princeton.EDU>
- Date: 14 Dec 90 23:31:22 GMT
-
- ---cut here---cut here---cut here---
- - case 'M':
- - stradd(&bp,hostM);
- - break;
- - case 'm':
- - stradd(&bp,hostm);
- - break;
- - case 'S':
- - if (tgetstr("so",&bp))
- - bp--;
- - break;
- - case 's':
- - if (tgetstr("se",&bp))
- - bp--;
- - break;
- - case 'B':
- - if (tgetstr("md",&bp))
- - bp--;
- - break;
- - case 'b':
- - if (tgetstr("me",&bp))
- - bp--;
- - break;
- - case 'U':
- - if (tgetstr("us",&bp))
- - bp--;
- - break;
- - case 'u':
- - if (tgetstr("ue",&bp))
- - bp--;
- - break;
- - case 't':
- - case '@':
- - timet = time(NULL);
- - tm = localtime(&timet);
- - strftime(bp,16,"%l:%M%p",tm);
- - if (*bp == ' ')
- - chuck(bp);
- - bp += strlen(bp);
- - break;
- - case 'T':
- - timet = time(NULL);
- - tm = localtime(&timet);
- - strftime(bp,16,"%k:%M",tm);
- - bp += strlen(bp);
- - break;
- - case '*':
- - timet = time(NULL);
- - tm = localtime(&timet);
- - strftime(bp,16,"%k:%M:%S",tm);
- - bp += strlen(bp);
- - break;
- - case 'n':
- - stradd(&bp,username);
- - break;
- - case 'w':
- - timet = time(NULL);
- - tm = localtime(&timet);
- - strftime(bp,16,"%a %e",tm);
- - bp += strlen(bp);
- - break;
- - case 'W':
- - timet = time(NULL);
- - tm = localtime(&timet);
- - strftime(bp,16,"%m/%d/%y",tm);
- - bp += strlen(bp);
- - break;
- - case 'D':
- - timet = time(NULL);
- - tm = localtime(&timet);
- - strftime(bp,16,"%y-%m-%d",tm);
- - bp += strlen(bp);
- - break;
- - case 'l':
- - if (ss = ttyname(SHTTY))
- - stradd(&bp,ss+8);
- - else
- - stradd(&bp,"(none)");
- - break;
- - case '%':
- - *bp++ = '%';
- - break;
- - case '#':
- - *bp++ = (geteuid()) ? '%' : '#';
- - break;
- - default:
- - *bp++ = '%';
- - *bp++ = *fm;
- - break;
- - }
- - else
- - *bp++ = *fm;
- - }
- - *bp = '\0';
- - return buf;
- -}
- -
- -void herrflush(void)
- -{
- - if (strin)
- - hflush();
- - else while (lastc != '\n' && lastc != HERR)
- - hgetch();
- - if (magic)
- - putc('\n',stderr);
- -}
- -
- -/* read an arbitrary amount of data into a buffer until stop is found */
- -
- -char *hdynread(char stop)
- -{
- -int bsiz = 256,ct = 0,c;
- -char *buf = zalloc(bsiz),*ptr;
- -
- - ptr = buf;
- - while ((c = hgetch()) != stop && c != '\n')
- - {
- - if (c == '\\')
- - c = hgetch();
- - *ptr++ = c;
- - if (++ct == bsiz)
- - {
- - buf = realloc(buf,bsiz *= 2);
- - ptr = buf+ct;
- - }
- - }
- - *ptr = 0;
- - if (c == '\n')
- - {
- - hungetch('\n');
- - zerr("delimiter expected");
- - errflag = 1;
- - free(buf);
- - return NULL;
- - }
- - return buf;
- -}
- -
- -char *hdynread2(char stop)
- -{
- -int bsiz = 256,ct = 0,c;
- -char *buf = zalloc(bsiz),*ptr;
- -
- - ptr = buf;
- - while ((c = hgetch()) != stop && c != '\n')
- - {
- - if (c == '\n')
- - {
- - hungetch(c);
- - break;
- - }
- - if (c == '\\')
- - if ((c = hgetch()) == '&')
- - c = '&';
- - *ptr++ = c;
- - if (++ct == bsiz)
- - {
- - buf = realloc(buf,bsiz *= 2);
- - ptr = buf+ct;
- - }
- - }
- - *ptr = 0;
- - if (c == '\n')
- - hungetch('\n');
- - return buf;
- -}
- -
- -/* set cbreak mode, or the equivalent */
- -
- -void setcbreak(void)
- -{
- -struct ttyinfo ti;
- -
- - ti = shttyinfo;
- -#ifdef TERMIOS
- - ti.termios.c_lflag &= ~ICANON;
- - ti.termios.c_cc[VMIN] = 1;
- - ti.termios.c_cc[VTIME] = 0;
- -#else
- - ti.sgttyb.sg_flags |= CBREAK;
- -#endif
- - settyinfo(&ti);
- -}
- -
- -int getlineleng(void)
- -{
- -int z;
- -
- - z = shttyinfo.winsize.ws_col;
- - return (z) ? z : 80;
- -}
- -
- -void unsetcbreak(void)
- -{
- - settyinfo(&shttyinfo);
- -}
- -
- -/* give the tty to some process */
- -
- -void attachtty(long pgrp)
- -{
- -static int ep = 0;
- -
- - if (jobbing)
- -#ifdef BUGGY_GCC
- - if (SHTTY != -1 && ioctl(SHTTY,(0x80000000|((sizeof(int)&0xff)<<16)|
- - ('t'<<8)|118),&pgrp) == -1 && !ep)
- -#else
- - if (SHTTY != -1 && ioctl(SHTTY,TIOCSPGRP,&pgrp) == -1 && !ep)
- -#endif
- - {
- - zerr("can't set tty pgrp: %e",errno);
- - opts[MONITOR] = OPT_UNSET;
- - ep =1;
- - }
- -}
- -
- End of hist.c
- echo hist.pro 1>&2
- sed 's/^-//' >hist.pro <<'End of hist.pro'
- -void hwaddc(int c);
- -int hgetc(void);
- -void strinbeg(void);
- -void strinend(void);
- -int stuff(char *fn);
- -int hgetch(void);
- -void hungetch(int c);
- -void hungetc(int c);
- -void hflush(void);
- -void hungets(char *str);
- -void hbegin(void);
- -void inittty(void);
- -int hend(void);
- -void remhist(void);
- -void hwbegin(void);
- -char *hwadd(void);
- -int getargspec(int argc,int marg);
- -int hconsearch(char *str,int *marg);
- -int hcomsearch(char *str);
- -int apply1(int gflag,int (*func)(void **),table list);
- -int remtpath(void **junkptr);
- -int remtext(void **junkptr);
- -int rembutext(void **junkptr);
- -int remlpaths(void **junkptr);
- -int subst(int gbal,table slist,char *ptr1,char *ptr2);
- -int subststr(void **strptr,char *in,char *out,int gbal);
- -char *convamps(char *out,char *in);
- -char *makehlist(table tab,int freeit);
- -table quietgetevent(int ev);
- -table getevent(int ev);
- -int getargc(table tab);
- -table getargs(table elist,int arg1,int arg2);
- -int quote(void **tr);
- -int quotebreak(void **tr);
- -void stradd(char **p,char *d);
- -char *putprompt(char *fm);
- -void herrflush(void);
- -char *hdynread(char stop);
- -char *hdynread2(char stop);
- -void setcbreak(void);
- -int getlineleng(void);
- -void unsetcbreak(void);
- -void attachtty(long pgrp);
- End of hist.pro
- echo init.c 1>&2
- sed 's/^-//' >init.c <<'End of init.c'
- -/*
- -
- - init.c - initialization, main loop
- -
- - This file is part of zsh, the Z shell.
- -
- - zsh is free software; no one can prevent you from reading the source
- - code, or giving it to someone else.
- - This file is copyrighted under the GNU General Public License, which
- - can be found in the file called COPYING.
- -
- - Copyright (C) 1990 Paul Falstad
- -
- - zsh is distributed in the hope that it will be useful, but
- - WITHOUT ANY WARRANTY. No author or distributor accepts
- - responsibility to anyone for the consequences of using it or for
- - whether it serves any particular purpose or works at all, unless he
- - says so in writing. Refer to the GNU General Public License
- - for full details.
- -
- - Everyone is granted permission to copy, modify and redistribute
- - zsh, but only under the conditions described in the GNU General Public
- - License. A copy of this license is supposed to have been given to you
- - along with zsh so you can know your rights and responsibilities.
- - It should be in a file named COPYING.
- -
- - Among other things, the copyright notice and this notice must be
- - preserved on all copies.
- -
- -*/
- -
- -#include "zsh.h"
- -#include "funcs.h"
- -#include <pwd.h>
- -
- -void main(int argc, char **argv)
- -{
- -int notect = 0;
- -
- - setflags();
- - parseargs(argv);
- - setmoreflags();
- - setupvals();
- - initialize();
- - runscripts();
- - FOREVER
- - {
- - do
- - loop();
- - while (peek != EOF);
- - if (!(isset(IGNOREEOF) && interact))
- - {
- - if (interact)
- - fputs(islogin ? "logout\n" : "exit\n",stderr);
- - zexit(NULL);
- - continue;
- - }
- - zerrnam("\nzsh",(!islogin) ? "use 'exit' to exit."
- - : "use 'logout' to logout.");
- - notect++;
- - if (notect == 10)
- - zexit(NULL);
- - }
- -}
- -
- -/* keep executing lists until EOF found */
- -
- -void loop(void)
- -{
- -list list;
- -
- - FOREVER
- - {
- - peek = EMPTY;
- - if (interact)
- - preprompt();
- - hbegin(); /* init history mech */
- - intr(); /* interrupts on */
- - ainit(); /* init alias mech */
- - if (!(list = parlist1(0)))
- - { /* if we couldn't parse a list */
- - hend();
- - if (!errflag)
- - if (peek == OUTPAR)
- - {
- - errflag = 1;
- - zerr("mismatched parenthesis");
- - }
- - else if (peek == OUTBRACE)
- - {
- - errflag = 1;
- - zerr("mismatched brace");
- - }
- - else if (peek != EOF && peek != EMPTY && peek != NEWLIN)
- - {
- - errflag = 1;
- - zerr("semicolon or newline expected");
- - }
- - if (peek == EOF && !errflag)
- - return;
- - continue;
- - }
- - if (peek != EMPTY && peek != EOF)
- - {
- - if (peek == OUTPAR)
- - zerr("mismatched parenthesis");
- - else if (peek == OUTBRACE)
- - zerr("mismatched brace");
- - else
- - zerr("semicolon or newline expected");
- - hend();
- - errflag = 1;
- - }
- - else if (hend())
- - {
- - if (stopmsg) /* unset 'you have stopped jobs' flag */
- - stopmsg--;
- - execlist(list);
- - }
- - if (ferror(stderr))
- - {
- - zerr("write error");
- - clearerr(stderr);
- - }
- - if (subsh) /* how'd we get this far in a subshell? */
- - exit(lastval);
- - if ((!interact && errflag) || retflag)
- - return;
- - if ((opts['t'] == OPT_SET) || (lastval && opts[ERREXIT] == OPT_SET))
- - {
- - if (sigtrapped[SIGEXIT])
- - dotrap(SIGEXIT);
- - exit(lastval);
- - }
- - }
- -}
- -
- -void setflags(void)
- -{
- -int c;
- -
- - for (c = 0; c != 128; c++)
- - opts[c] = OPT_INVALID;
- - opts['a'] = opts['e'] = opts['f'] = opts['h'] = opts['k'] = opts['n'] =
- - opts['s'] = opts['t'] = opts['u'] = opts['v'] = opts['x'] =
- - opts['c'] = OPT_UNSET;
- - opts['i'] = (isatty(0)) ? OPT_SET : OPT_UNSET;
- - for (c = '0'; c <= '9'; c++)
- - opts[c] = OPT_UNSET;
- - for (c = 'A'; c <= 'K'; c++)
- - opts[c] = OPT_UNSET;
- - opts[BGNICE] = opts[NOTIFY] = OPT_SET;
- -}
- -
- -static char *cmd;
- -
- -void parseargs(char **argv)
- -{
- -char *argv0 = *argv;
- -int bk = 0;
- -
- - islogin = **(argv++) == '-';
- - SHIN = 0;
- - while (!bk && *argv && **argv == '-')
- - {
- - while (*++*argv)
- - {
- - if (opts[**argv] == OPT_INVALID)
- - {
- - zerr("bad option: -%c",**argv);
- - exit(1);
- - }
- - opts[**argv] = OPT_SET;
- - if (bk = **argv == 'b')
- - break;
- - if (**argv == 'c') /* -c command */
- - {
- - argv++;
- - if (!*argv)
- - {
- - zerr("string expected after -c");
- - exit(1);
- - }
- - cmd = strdup(*argv);
- - opts[INTERACTIVE] = OPT_UNSET;
- - break;
- - }
- - }
- - argv++;
- - }
- - pparms = newtable();
- - if (*argv)
- - {
- - if (opts[SHINSTDIN] == OPT_UNSET)
- - {
- - SHIN = movefd(open(argv0 = *argv,O_RDONLY));
- - if (SHIN == -1)
- - {
- - zerr("can't open input file: %s",*argv);
- - exit(1);
- - }
- - opts[INTERACTIVE] = OPT_UNSET;
- - argv++;
- - }
- - addnode(pparms,argv0); /* assign positional parameters */
- - while (*argv)
- - addnode(pparms,strdup(*argv++));
- - }
- - else
- - {
- - addnode(pparms,strdup(argv0));
- - opts[SHINSTDIN] = OPT_SET;
- - }
- -}
- -
- -void setmoreflags(void)
- -{
- - setlinebuf(stderr);
- - setlinebuf(stdout);
- - subsh = 0;
- - opts[MONITOR] = (interact) ? OPT_SET : OPT_UNSET;
- - if (jobbing)
- - {
- - SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty",O_RDWR));
- - if (SHTTY == -1)
- - opts[MONITOR] = OPT_UNSET;
- - else
- - gettyinfo(&shttyinfo); /* get tty state */
- - if ((shpgrp = getpgrp(0)) <= 0)
- - opts[MONITOR] = OPT_UNSET;
- - }
- - else
- - SHTTY = -1;
- -}
- -
- -void setupvals(void)
- -{
- -struct passwd *pwd;
- -char *ptr;
- -
- - shtimer = time(NULL); /* init $SECONDS */
- - /* build various hash tables; argument to newhtable is table size */
- - alhtab = newhtable(37);
- - parmhtab = newhtable(17);
- - shfunchtab = newhtable(17);
- - if (interact)
- - {
- - if (!getparm("PROMPT"))
- - setparm(strdup("PROMPT"),strdup("%M%# "),0,0);
- - if (!getparm("PROMPT2"))
- - setparm(strdup("PROMPT2"),strdup("> "),0,0);
- - if (!getparm("PROMPT3"))
- - setparm(strdup("PROMPT3"),strdup("?# "),0,0);
- - }
- - if (!getparm("PATH"))
- - setparm(strdup("PATH"),strdup("/bin:/usr/bin:/usr/ucb"),1,0);
- - setparm(strdup("VERSION"),strdup(VERSIONSTR),1,0);
- - home = xsymlink(getparm("HOME"));
- - setparm(strdup("HOME"),strdup(home),0,0);
- - setiparm(strdup("UID"),getuid(),1);
- - setiparm(strdup("EUID"),geteuid(),1);
- - setiparm(strdup("PPID"),getppid(),1);
- - lineno = 0;
- - pwd = getpwuid(getuid());
- - setparm(strdup("USERNAME"),strdup(pwd->pw_name),0,0);
- - username = strdup(pwd->pw_name);
- - setparm(strdup("HOSTTYPE"),strdup(HOSTTYP),0,0);
- - cwd = zgetwd();
- - setparm(strdup("PWD"),strdup(cwd),0,0);
- - if (!getparm("IFS"))
- - {
- - ifs = strdup(" \t\n");
- - setparm(strdup("IFS"),strdup(ifs),0,0);
- - }
- - hostM = alloc(512); /* get hostname, with and without .podunk.edu */
- - hostm = hostM+256;
- - gethostname(hostm,256);
- - gethostname(hostM,256);
- - procnum = getpid();
- - for (ptr = hostM; *ptr && *ptr != '.'; ptr++);
- - *ptr = '\0';
- -}
- -
- -void initialize(void)
- -{
- -int t0;
- -
- - breaks = loops = incmd = 0;
- - lastmailcheck = 0;
- - lastmailval = -1;
- - tfev = 1;
- - tevs = DEFAULT_HISTSIZE;
- - histlist = newtable();
- - dirstack = newtable();
- - ungots = ungotptr = NULL;
- - signal(SIGQUIT,SIG_IGN);
- - for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
- - getrlimit(t0,limits+t0);
- - last = rast = NULL;
- - proclast = 0;
- - if (!interact || SHTTY == -1)
- - bshin = fdopen(SHIN,"r");
- - signal(SIGCHLD,handler);
- - addreswords();
- - addhnode(strdup("false"),mkanode(strdup("let 0"),1),alhtab,NULL);
- - addhnode(strdup("history"),mkanode(strdup("fc -l"),1),alhtab,NULL);
- - addhnode(strdup("nohup"),mkanode(strdup("nohup "),1),alhtab,NULL);
- - addhnode(strdup("r"),mkanode(strdup("fc -e -"),1),alhtab,NULL);
- - addhnode(strdup("true"),mkanode(strdup(":"),1),alhtab,NULL);
- - addhnode(strdup("pwd"),mkanode(strdup("echo $PWD"),1),alhtab,NULL);
- - parsepath();
- - parsecdpath();
- - if (jobbing)
- - {
- - signal(SIGTTOU,SIG_IGN);
- - signal(SIGTSTP,SIG_IGN);
- - signal(SIGTTIN,SIG_IGN);
- - signal(SIGPIPE,SIG_IGN);
- - attachtty(shpgrp);
- - }
- - if (interact)
- - {
- - signal(SIGTERM,SIG_IGN);
- - intr();
- - }
- -}
- -
- -void addreswords(void)
- -{
- -char *reswds[] = {
- - "do", "done", "esac", "then", "elif", "else", "fi", "for", "case",
- - "if", "while", "function", "repeat", "time", "until", "exec", "command",
- - "select", "coproc", NULL
- - };
- -int t0;
- -
- - for (t0 = 0; reswds[t0]; t0++)
- - addhnode(strdup(reswds[t0]),mkanode(NULL,-1-t0),alhtab,NULL);
- -}
- -
- -void runscripts(void)
- -{
- - if (interact)
- - checkfirstmail();
- - if (opts[NORCS] == OPT_UNSET)
- - {
- -#ifdef GLOBALZSHRC
- - source(GLOBALZSHRC);
- -#endif
- - sourcehome(".zshrc");
- - if (islogin)
- - {
- -#ifdef GLOBALZLOGIN
- - source(GLOBALZLOGIN);
- -#endif
- - sourcehome(".zlogin");
- - }
- - }
- - if (opts['c'] == OPT_SET)
- - {
- - close(SHIN);
- - SHIN = movefd(open("/dev/null",O_RDONLY));
- - hungets(cmd);
- - strinbeg();
- - }
- -}
- -
- -void ainit(void)
- -{
- - alix = 0; /* reset alias stack */
- - alstat = 0;
- - firstln = 1;
- -}
- End of init.c
- echo init.pro 1>&2
- sed 's/^-//' >init.pro <<'End of init.pro'
- -void main(int argc, char **argv);
- -void loop(void);
- -void setflags(void);
- -void parseargs(char **argv);
- -void setmoreflags(void);
- -void setupvals(void);
- -void initialize(void);
- -void addreswords(void);
- -void runscripts(void);
- -void ainit(void);
- End of init.pro
- echo jobs.c 1>&2
- sed 's/^-//' >jobs.c <<'End of jobs.c'
- -/*
- -
- - jobs.c - job control
- -
- - This file is part of zsh, the Z shell.
- -
- - zsh is free software; no one can prevent you from reading the source
- - code, or giving it to someone else.
- - This file is copyrighted under the GNU General Public License, which
- - can be found in the file called COPYING.
- -
- - Copyright (C) 1990 Paul Falstad
- -
- - zsh is distributed in the hope that it will be useful, but
- - WITHOUT ANY WARRANTY. No author or distributor accepts
- - responsibility to anyone for the consequences of using it or for
- - whether it serves any particular purpose or works at all, unless he
- - says so in writing. Refer to the GNU General Public License
- - for full details.
- -
- - Everyone is granted permission to copy, modify and redistribute
- - zsh, but only under the conditions described in the GNU General Public
- - License. A copy of this license is supposed to have been given to you
- - along with zsh so you can know your rights and responsibilities.
- - It should be in a file named COPYING.
- -
- - Among other things, the copyright notice and this notice must be
- - preserved on all copies.
- -
- -*/
- -
- -#include "zsh.h"
- -#include "funcs.h"
- -#include <sys/errno.h>
- -
- -#define WCOREDUMPED(x) ((x)&0x80)
- -
- -/* != 0 means the handler is active */
- -
- -static int handling = 0;
- -
- -/* != 0 means the shell is waiting for a job to complete */
- -
- -static int waiting = 0;
- -
- -/* != 0 means readline is active */
- -
- -extern int rl_active;
- -
- -/* != 0 means readline is waiting for a keypress */
- -
- -extern int rl_waiting;
- -
- -#ifdef INTHANDTYPE
- -#define RETURN return 0
- -#else
- -#define RETURN return
- -#endif
- -
- -/* the signal handler */
- -
- -HANDTYPE handler(int sig,int code)
- -{
- -long pid;
- -int statusp;
- -struct jobnode *jn;
- -struct procnode *pn;
- -struct rusage ru;
- -
- - if (sig == SIGINT)
- - {
- - if (sigtrapped[SIGINT])
- - dotrap(SIGINT);
- - else
- - errflag = 1;
- - RETURN;
- - }
- - if (sig != SIGCHLD)
- - {
- - dotrap(sig);
- - RETURN;
- - }
- - for (;;)
- - {
- - pid = wait3(&statusp,WNOHANG|WUNTRACED,&ru);
- - if (pid == -1)
- - {
- - if (errno != ECHILD)
- - zerr("%e",errno);
- - RETURN;
- - }
- - if (!pid)
- - RETURN;
- - findproc(pid,&jn,&pn); /* find the procnode of this pid */
- - if (jn)
- - {
- - pn->statusp = statusp;
- - handling = 1;
- - pn->ru_utime = ru.ru_utime;
- - pn->ru_stime = ru.ru_stime;
- - pn->endtime = time(NULL);
- - updatestatus(jn);
- - handling = 0;
- - }
- - else if (WIFSTOPPED(SP(statusp)))
- - kill(pid,SIGKILL); /* kill stopped untraced children */
- - }
- - if (rl_active)
- - rl_prep_terminal();
- - RETURN;
- -}
- -
- -/* change job table entry from stopped to running */
- -
- -void makerunning(struct jobnode *jn)
- -{
- -struct procnode *pn;
- -
- - jn->stat &= ~STAT_STOPPED;
- - for (pn = jn->procs; pn; pn = pn->next)
- - if (WIFSTOPPED(SP(pn->statusp)))
- - pn->statusp = SP_RUNNING;
- -}
- -
- -/* update status of job, possibly printing it */
- -
- -void updatestatus(struct jobnode *jn)
- -{
- -struct procnode *pn;
- -int notrunning = 1,alldone = 1,val,job = jn-jobtab,somestopped = 0;
- -
- - for (pn = jn->procs; pn; pn = pn->next)
- - {
- - if (pn->statusp == SP_RUNNING)
- - notrunning = 0;
- - if (pn->statusp == SP_RUNNING || WIFSTOPPED(SP(pn->statusp)))
- - alldone = 0;
- - if (WIFSTOPPED(SP(pn->statusp)))
- - somestopped = 1;
- - if (!pn->next && jn)
- - val = (WIFSIGNALED(SP(pn->statusp))) ?
- - 0200 | WTERMSIG(SP(pn->statusp)) : WEXITSTATUS(SP(pn->statusp));
- - }
- - if (!notrunning)
- - return;
- - if (somestopped && (jn->stat & STAT_STOPPED))
- - return;
- - jn->stat |= (alldone) ? STAT_CHANGED|STAT_DONE :
- - STAT_CHANGED|STAT_STOPPED;
- - if (!alldone)
- - gettyinfo(&jn->ttyinfo);
- - if (job == curjob)
- - {
- - if (!val)
- - gettyinfo(&shttyinfo);
- - else
- - settyinfo(&shttyinfo);
- - lastval = val;
- - }
- - if (jn->stat & STAT_STOPPED)
- - {
- - prevjob = topjob;
- - topjob = job;
- - }
- - if ((isset(NOTIFY) || job == curjob) && jn->stat & STAT_LOCKED)
- - printjob(jn,0);
- - if (sigtrapped[SIGCHLD] && job != curjob)
- - dotrap(SIGCHLD);
- -}
- -
- -/* find procnode and jobnode associated with pid */
- -
- -void findproc(int pid,struct jobnode **jptr,struct procnode **pptr)
- -{
- -struct procnode *pn;
- -int jn;
- -
- - for (jn = 1; jn != MAXJOB; jn++)
- - for (pn = jobtab[jn].procs; pn; pn = pn->next)
- - if (pn->pid == pid)
- - {
- - *pptr = pn;
- - *jptr = jobtab+jn;
- - return;
- - }
- - *pptr = NULL;
- - *jptr = NULL;
- -}
- -
- -static char *sigmsg[32] = {
- - "done","hangup","interrupt","quit",
- - "illegal instruction","trace trap","IOT instruction","EMT instruction",
- - "floating exception","killed","bus error","segmentation fault",
- - "bad system call","broken pipe","SIGALRM","terminated",
- -#ifdef USE_SUSPENDED
- - "SIGURG","suspended (signal)","suspended","continued",
- - "SIGCHLD","suspended (tty input)","suspended (tty output)","SIGIO",
- -#else
- - "SIGURG","stopped (signal)","stopped","continued",
- - "SIGCHLD","stopped (tty input)","stopped (tty output)","SIGIO",
- -#endif
- - "CPU time limit exceeded","file size limit exceeded","SIGVTALRM","SIGPROF",
- - "window changed","resource lost","SIGUSR1","SIGUSR2"
- - };
- -
- -/* lng = 0 means jobs
- - lng = 1 means jobs -l
- - lng = 2 means jobs -p
- -*/
- -
- -void printjob(struct jobnode *jn,int lng)
- -{
- -int job = jn-jobtab,len = 9,sig = -1,sflag = 0,llen,printed = 0;
- -int conted = 0,lineleng = getlineleng(),doputnl = 0;
- -struct procnode *pn;
- -extern void rl_on_new_line(void);
- -
- - if (lng < 0)
- - {
- - conted = 1;
- - lng = 0;
- - }
- -
- - /* find length of longest signame, check to see if we
- - really need to print this job */
- -
- - for (pn = jn->procs; pn; pn = pn->next)
- - {
- - if (pn->statusp != SP_RUNNING)
- - if (WIFSIGNALED(SP(pn->statusp)))
- - {
- - sig = WTERMSIG(SP(pn->statusp));
- - llen = strlen(sigmsg[sig]);
- - if (WCOREDUMPED(pn->statusp))
- - llen += 14;
- - if (llen > len)
- - len = llen;
- - if (sig != SIGINT && sig != SIGPIPE)
- - sflag = 1;
- - if (sig == SIGINT && job == curjob && interact)
- - doputnl = 1;
- - }
- - else if (WIFSTOPPED(SP(pn->statusp)))
- - {
- - sig = WSTOPSIG(SP(pn->statusp));
- - if (strlen(sigmsg[sig]) > len)
- - len = strlen(sigmsg[sig]);
- - }
- - else if (isset(PRINTEXITVALUE) && WEXITSTATUS(SP(pn->statusp)))
- - sflag = 1;
- - }
- - if (doputnl)
- - putc('\n',stderr);
- -
- - /* print if necessary */
- -
- - if (interact && jobbing && ((jn->stat & STAT_STOPPED) || sflag ||
- - job != curjob))
- - {
- - int len2,fline = 1;
- - struct procnode *qn;
- -
- - if (handling && (!waiting || jn->stat & STAT_STOPPED))
- - putc('\n',stderr);
- - for (pn = jn->procs; pn;)
- - {
- - len2 = ((job == curjob) ? 5 : 10)+len; /* 2 spaces */
- - if (lng)
- - qn = pn->next;
- - else for (qn = pn->next; qn; qn = qn->next)
- - {
- - if (qn->statusp != pn->statusp)
- - break;
- - if (strlen(qn->text)+len2+((qn->next) ? 3 : 0) > lineleng)
- - break;
- - len2 += strlen(qn->text)+2;
- - }
- - if (job != curjob)
- - if (fline)
- - fprintf(stderr,"[%d] %c ",jn-jobtab,(job == topjob) ? '+' :
- - (job == prevjob) ? '-' : ' ');
- - else
- - fprintf(stderr,(job > 9) ? " " : " ");
- - else
- - fprintf(stderr,"zsh: ");
- - if (lng)
- - if (lng == 1)
- - fprintf(stderr,"%d ",pn->pid);
- - else
- - {
- - fprintf(stderr,"%d ",jn->gleader);
- - lng = 0;
- - }
- - if (pn->statusp == SP_RUNNING)
- - if (!conted)
- - fprintf(stderr,"running%*s",len-7+2,"");
- - else
- - fprintf(stderr,"continued%*s",len-9+2,"");
- - else if (WIFEXITED(SP(pn->statusp)))
- - if (WEXITSTATUS(SP(pn->statusp)))
- - fprintf(stderr,"exit %-4d%*s",WEXITSTATUS(SP(pn->statusp)),
- - len-9+2,"");
- - else
- - fprintf(stderr,"done%*s",len-4+2,"");
- - else if (WIFSTOPPED(SP(pn->statusp)))
- - fprintf(stderr,"%-*s",len+2,sigmsg[WSTOPSIG(SP(pn->statusp))]);
- - else if (WCOREDUMPED(pn->statusp))
- - fprintf(stderr,"%s (core dumped)%*s",
- - sigmsg[WTERMSIG(SP(pn->statusp))],
- - len-14+2-strlen(sigmsg[WTERMSIG(SP(pn->statusp))]),"");
- - else
- - fprintf(stderr,"%-*s",len+2,sigmsg[WTERMSIG(SP(pn->statusp))]);
- - for (; pn != qn; pn = pn->next)
- - fprintf(stderr,(pn->next) ? "%s | " : "%s",pn->text);
- - putc('\n',stderr);
- - fline = 0;
- - }
- - printed = 1;
- - }
- -
- - /* print "(pwd now: foo)" messages */
- -
- - if (interact && job==curjob && strcmp(jn->cwd,cwd))
- - {
- - printf("(pwd now: ");
- - printdir(cwd);
- - printf(")\n");
- - fflush(stdout);
- - }
- -
- - /* delete job if done */
- -
- - if (jn->stat & STAT_DONE)
- - {
- - static struct jobnode zero;
- - struct procnode *nx;
- - char *s;
- -
- - if (jn->stat & STAT_TIMED)
- - {
- - dumptime(jn);
- - printed = 1;
- - }
- - for (pn = jn->procs; pn; pn = nx)
- - {
- - nx = pn->next;
- - if (pn->text)
- - free(pn->text);
- - free(pn);
- - }
- - free(jn->cwd);
- - if (jn->filelist)
- - {
- - while (s = getnode(jn->filelist))
- - {
- - unlink(s);
- - free(s);
- - }
- - free(jn->filelist);
- - }
- - *jn = zero;
- - if (job == topjob)
- - {
- - topjob = prevjob;
- - prevjob = job;
- - }
- - if (job == prevjob)
- - setprevjob();
- - }
- - else
- - jn->stat &= ~STAT_CHANGED;
- - if (printed && rl_active)
- - {
- - rl_on_new_line();
- - if (rl_waiting)
- - rl_redisplay();
- - }
- -}
- -
- -/* set the previous job to something reasonable */
- -
- -void setprevjob(void)
- -{
- -int t0;
- -
- - for (t0 = MAXJOB-1; t0; t0--)
- - if (jobtab[t0].stat && jobtab[t0].stat & STAT_STOPPED &&
- - t0 != topjob && t0 != curjob)
- - break;
- - if (!t0)
- - for (t0 = MAXJOB-1; t0; t0--)
- - if (jobtab[t0].stat && t0 != topjob && t0 != curjob)
- - break;
- - prevjob = (t0) ? t0 : -1;
- -}
- -
- -/* initialize a job table entry */
- -
- -void initjob(int flags)
- -{
- - jobtab[curjob].cwd = strdup(cwd);
- - jobtab[curjob].stat = (flags & PFLAG_TIMED) | STAT_INUSE;
- - jobtab[curjob].ttyinfo = shttyinfo;
- - jobtab[curjob].gleader = 0;
- -}
- -
- -/* add a process to the current job */
- -
- -struct procnode *addproc(long pid,char *text)
- -{
- -struct procnode *procnode;
- -
- - if (!jobtab[curjob].gleader)
- - jobtab[curjob].gleader = proclast = pid;
- - proclast = pid;
- - procnode = alloc(sizeof(struct procnode));
- - procnode->pid = pid;
- - procnode->text = text;
- - procnode->next = NULL;
- - procnode->statusp = SP_RUNNING;
- - procnode->bgtime = time(NULL);
- - if (jobtab[curjob].procs)
- - {
- - struct procnode *n;
- -
- - for (n = jobtab[curjob].procs; n->next && !n->next->lastfg; n = n->next);
- - procnode->next = n->next;
- - n->next = procnode;
- - }
- - else
- - jobtab[curjob].procs = procnode;
- - return procnode;
- -}
- -
- -/* determine if it's all right to exec a command without
- - forking in last component of subshells; it's not ok if we have files
- - to delete */
- -
- -int execok(void)
- -{
- -struct jobnode *jn;
- -
- - if (!exiting)
- - return 0;
- - for (jn = jobtab+1; jn != jobtab+MAXJOB; jn++)
- - if (jn->stat && jn->filelist)
- - return 0;
- - return 1;
- -}
- -
- -/* wait for a SIGCHLD, wait for the handler to execute, and return */
- -
- -void chldsuspend(void)
- -{
- -struct sigvec vec = { handler,sigmask(SIGCHLD),SV_INTERRUPT };
- -
- - sigvec(SIGCHLD,&vec,NULL);
- - sigpause(0);
- - signal(SIGCHLD,handler);
- -}
- -
- -/* wait for the current job to finish */
- -
- -void waitjobs(void)
- -{
- -static struct jobnode zero;
- -struct jobnode *jn;
- -
- - if (jobtab[curjob].procs) /* if any forks were done */
- - {
- - jobtab[curjob].stat |= STAT_LOCKED;
- - waiting = 1;
- - if (jobtab[curjob].stat & STAT_CHANGED)
- - printjob(jobtab+curjob,0);
- - while (jobtab[curjob].stat &&
- - !(jobtab[curjob].stat & (STAT_DONE|STAT_STOPPED)))
- - chldsuspend();
- - waiting = 0;
- - }
- - else /* else do what printjob() usually does */
- - {
- - char *s;
- -
- - jn = jobtab+curjob;
- - free(jn->cwd);
- - if (jn->filelist)
- - {
- - while (s = getnode(jn->filelist))
- - {
- - unlink(s);
- - free(s);
- - }
- - free(jn->filelist);
- - }
- - *jn = zero;
- - }
- - curjob = -1;
- -}
- -
- -/* clear jobtab when entering subshells */
- -
- -void clearjobtab(void)
- -{
- -static struct jobnode zero;
- -int t0;
- -
- - for (t0 = 1; t0 != MAXJOB; t0++)
- - jobtab[curjob] = zero;
- -}
- -
- -/* get a free entry in the job table to use */
- -
- -int getfreejob(void)
- -{
- -int mask,t0;
- -
- - FOREVER
- - {
- - mask = sigblock(sigmask(SIGCHLD));
- - for (t0 = 1; t0 != MAXJOB; t0++)
- - if (!jobtab[t0].stat)
- - {
- - sigsetmask(mask);
- - jobtab[t0].stat |= STAT_INUSE;
- - return t0;
- - }
- - sigsetmask(mask);
- - sleep(1);
- - }
- -}
- -
- -/* print pids for & */
- -
- -void spawnjob(void)
- -{
- -struct procnode *pn;
- -
- - if (!subsh)
- - {
- - if (topjob == -1 || !(jobtab[topjob].stat & STAT_STOPPED))
- - {
- - topjob = curjob;
- - setprevjob();
- - }
- - else if (prevjob == -1 || !(jobtab[prevjob].stat & STAT_STOPPED))
- - prevjob = curjob;
- - if (interact && jobbing)
- - {
- - fprintf(stderr,"[%d]",curjob);
- - for (pn = jobtab[curjob].procs; pn; pn = pn->next)
- - fprintf(stderr," %d",pn->pid);
- - fprintf(stderr,"\n");
- - }
- - }
- - jobtab[curjob].stat |= STAT_LOCKED;
- - curjob = -1;
- -}
- -
- -void fixsigs(void)
- -{
- - sigsetmask(0);
- -}
- -
- -/* timing */
- -
- -static void addtimeval(struct timeval *s,struct timeval *t)
- -{
- - s->tv_sec += t->tv_sec+(s->tv_usec+t->tv_usec)/1000000;
- - s->tv_usec = (s->tv_usec+t->tv_usec)%1000000;
- -}
- -
- -static void printtime(time_t real,struct timeval *u,struct timeval *s,char *desc)
- -{
- - if (!desc)
- - desc = "";
- - fprintf(stderr,"real: %lds user: %ld.%03lds sys: %ld.%03lds\n",
- - real,u->tv_sec,u->tv_usec/1000,s->tv_sec,s->tv_usec/1000);
- -}
- -
- -static void printheader(void)
- -{
- - fprintf(stderr," real user system\n");
- -}
- -
- -static void printtimes(time_t real,struct timeval *u,struct timeval *s,char *desc)
- -{
- - if (!desc)
- - desc = "";
- - fprintf(stderr,"% 8lds % 4d.%03lds % 4d.%03lds %s\n",
- - real,u->tv_sec,u->tv_usec/1000,s->tv_sec,s->tv_usec/1000,desc);
- -}
- -
- -void dumptime(struct jobnode *jn)
- -{
- -struct procnode *pn = jn->procs;
- -struct timeval utot = { 0,0 },stot = { 0,0 };
- -time_t maxend,minbeg;
- -
- - if (!jn->procs)
- - return;
- - if (!jn->procs->next)
- - printtime(pn->endtime-pn->bgtime,&pn->ru_utime,&pn->ru_stime,pn->text);
- - else
- - {
- - maxend = jn->procs->endtime;
- - minbeg = jn->procs->bgtime;
- - printheader();
- - for (pn = jn->procs; pn; pn = pn->next)
- - {
- - printtimes(pn->endtime-pn->bgtime,&pn->ru_utime,&pn->ru_stime,pn->text);
- - addtimeval(&utot,&pn->ru_utime);
- - addtimeval(&stot,&pn->ru_stime);
- - if (pn->endtime > maxend)
- - maxend = pn->endtime;
- - if (pn->bgtime < minbeg)
- - minbeg = pn->bgtime;
- - }
- - printtimes(maxend-minbeg,&utot,&stot,"total");
- - }
- -}
- -
- -/* SIGHUP any jobs left running */
- -
- -void killrunjobs(void)
- -{
- -int t0,killed = 0;
- -
- - for (t0 = 1; t0 != MAXJOB; t0++)
- - if (t0 != curjob && jobtab[t0].stat &&
- - !(jobtab[t0].stat & STAT_STOPPED))
- - {
- - killpg(jobtab[t0].gleader,SIGHUP);
- - killed++;
- - }
- - if (killed)
- - zerr("warning: %d jobs SIGHUPed",killed);
- -}
- -
- -/* check to see if user has jobs running/stopped */
- -
- -void checkjobs(void)
- -{
- -int t0;
- -
- - for (t0 = 1; t0 != MAXJOB; t0++)
- - if (t0 != curjob && jobtab[t0].stat)
- - break;
- - if (t0 != MAXJOB)
- - {
- - if (jobtab[t0].stat & STAT_STOPPED)
- - {
- -#ifdef USE_SUSPENDED
- - zerr("you have suspended jobs.");
- -#else
- - zerr("you have stopped jobs.");
- -#endif
- - }
- - else
- - zerr("you have running jobs.");
- - stopmsg = 1;
- - }
- -}
- -
- -/* send a signal to a job (simply involves killpg if monitoring is on) */
- -
- -int killjb(struct jobnode *jn,int sig)
- -{
- -struct procnode *pn;
- -int err;
- -
- - if (jobbing)
- - return(killpg(jn->gleader,sig));
- - for (pn = jn->procs; pn; pn = pn->next)
- - if ((err = kill(pn->pid,sig)) == -1 && errno != ESRCH)
- - return -1;
- - return err;
- -}
- -
- End of jobs.c
- echo jobs.pro 1>&2
- sed 's/^-//' >jobs.pro <<'End of jobs.pro'
- -HANDTYPE handler(int sig,int code);
- -void makerunning(struct jobnode *jn);
- -void updatestatus(struct jobnode *jn);
- -void findproc(int pid,struct jobnode **jptr,struct procnode **pptr);
- -void printjob(struct jobnode *jn,int lng);
- -void setprevjob(void);
- -void initjob(int flags);
- -struct procnode *addproc(long pid,char *text);
- -int execok(void);
- -void chldsuspend(void);
- -void waitjobs(void);
- -void clearjobtab(void);
- -int getfreejob(void);
- -void spawnjob(void);
- -void fixsigs(void);
- -void dumptime(struct jobnode *jn);
- -void killrunjobs(void);
- -void checkjobs(void);
- -int killjb(struct jobnode *jn,int sig);
- End of jobs.pro
- echo lex.c 1>&2
- sed 's/^-//' >lex.c <<'End of lex.c'
- -/*
- -
- - lex.c - lexical analysis
- -
- - 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"
- -
- -/* match the current token and get another
- - (actually just get another) */
- -
- -void matchit(void)
- -{
- - do
- - gettok();
- - while (exalias());
- -}
- -
- -int len = 0,bsiz = 256;
- -char *bptr;
- -
- -/* add a char to the string buffer */
- -
- -void add(int c)
- -{
- - *bptr++ = c;
- - if (bsiz == ++len)
- - bptr = len+(tstr = realloc(tstr,bsiz *= 2));
- -}
- -
- -/* get a token */
- -
- -void gettok(void)
- -{
- -int bct = 0,pct = 0;
- -int c,d,intpos = 1;
- -static int dbparens = 0;
- -
- -beginning:
- - hlastw = NULL;
- - tstr = NULL;
- - while (zspace(c = hgetc()) || c == '\t' || c == ' ');
- - firstln = 0;
- - hwbegin();
- - hwaddc(c);
- - if (dbparens) /* handle ((...)) */
- - {
- - int pct = 2;
- -
- - peek = STRING;
- - len = dbparens = 0;
- - bptr = tstr = zalloc(bsiz = 256);
- - for (;;)
- - {
- - if (c == '(')
- - pct++;
- - else if (c == ')')
- - pct--;
- - else if (c == '\n')
- - {
- - zerr("parse error: )) expected");
- - peek = HERR;
- - free(tstr);
- - return;
- - }
- - else if (c == '$')
- - c = Qstring;
- - if (pct >= 2)
- - add(c);
- - if (pct)
- - c = hgetc();
- - else
- - break;
- - }
- - *bptr = '\0';
- - return;
- - }
- - peekfd = -1;
- - if (isdigit(c)) /* handle 1< foo */
- - {
- - d = hgetc();
- - hungetc(d);
- - if (d == '>' || d == '<')
- - {
- - peekfd = c-'0';
- - c = hgetc();
- - }
- - }
- -
- - /* chars in initial position in word */
- -
- - switch (c)
- - {
- - case '\\':
- - d = hgetc();
- - if (d == '\n')
- - goto beginning;
- - hungetc(d);
- - break;
- - case EOF:
- - peek = EOF;
- - return;
- - case HERR:
- - peek = HERR;
- - return;
- - case '\n':
- - peek = NEWLIN;
- - return;
- - case ';':
- - d = hgetc();
- - if (d != ';')
- - {
- - hungetc(d);
- - peek = SEMI;
- - }
- - else
- - peek = DSEMI;
- - return;
- - case '!':
- - if (!incmd)
- - {
- - peek = BANG;
- - return;
- - }
- - break;
- - case '&':
- - d = hgetc();
- - if (d != '&')
- - {
- - hungetc(d);
- - peek = AMPER;
- - }
- - else
- - peek = DAMPER;
- - return;
- - case '|':
- - d = hgetc();
- - if (d == '|')
- - peek = DBAR;
- - else if (d == '&')
- - peek = BARAMP;
- - else
- - {
- - hungetc(d);
- - peek = BAR;
- - }
- - return;
- - case '(':
- - if (incmd)
- - break;
- - d = hgetc();
- - if (d == '(')
- - {
- - peek = STRING;
- - tstr = strdup("let");
- - dbparens = 1;
- - return;
- - }
- - hungetc(d);
- - peek = INPAR;
- - return;
- - case ')':
- - peek = OUTPAR;
- - return;
- - case '{':
- - if (incmd)
- - break;
- - peek = INBRACE;
- - return;
- - case '}':
- - peek = OUTBRACE;
- - return;
- - case '<':
- - d = hgetc();
- - if (incmd && d == '(')
- - {
- - hungetc(d);
- - break;
- - }
- - else if (d == '<')
- - {
- - int e = hgetc();
- -
- - hungetc(e);
- - if (e == '(')
- - {
- - hungetc(d);
- - peek = INANG;
- - }
- - else
- - peek = DINANG;
- - }
- - else if (d == '&')
- - peek = INANGAMP;
- - else
- - {
- - peek = INANG;
- - hungetc(d);
- - }
- - return;
- - case '>':
- - d = hgetc();
- - if (d == '(')
- - {
- - hungetc(d);
- - break;
- - }
- - else if (d == '&')
- - {
- - d = hgetc();
- - if (d == '!')
- - peek = OUTANGAMPBANG;
- - else
- - {
- - hungetc(d);
- - peek = OUTANGAMP;
- - }
- - }
- - else if (d == '!')
- - peek = OUTANGBANG;
- - else if (d == '>')
- - {
- - d = hgetc();
- - if (d == '&')
- - {
- - d = hgetc();
- - if (d == '!')
- - peek = DOUTANGAMPBANG;
- - else
- - {
- - hungetc(d);
- - peek = DOUTANGAMP;
- - }
- - }
- - else if (d == '!')
- - peek = DOUTANGBANG;
- - else if (d == '(')
- - {
- - hungetc(d);
- - hungetc('>');
- - peek = OUTANG;
- - }
- - else
- - {
- - hungetc(d);
- - peek = DOUTANG;
- - }
- - }
- - else
- - {
- - hungetc(d);
- - peek = OUTANG;
- - }
- - return;
- - case '#':
- -#ifndef INTERACTIVE_COMMENTS
- - if (interact)
- - break;
- -#endif
- - while ((c = hgetch()) != '\n' && !istok(c) && c != EOF);
- - if (c == '\n')
- - peek = NEWLIN;
- - else
- - errflag = 1;
- - return;
- - }
- -
- - /* we've started a string, now get the rest of it, performing
- - tokenization */
- -
- - peek = STRING;
- - len = 0;
- - bptr = tstr = zalloc(bsiz = 256);
- - for(;;)
- - {
- - if (c == ';' || c == '&' || c == EOF ||
- - c == HERR || c == '\03' || c == '\n' ||
- - c == ' ' || c == '\t' || znspace(c))
- - break;
- - if (c == '#')
- - c = Pound;
- - else if (c == ')')
- - {
- - if (!pct)
- - break;
- - pct--;
- - c = Outpar;
- - }
- - else if (c == ',')
- - c = Comma;
- - else if (c == '|')
- - {
- - if (!pct)
- - break;
- - c = Bar;
- - }
- - else if (c == '$')
- - {
- - d = hgetc();
- -
- - c = String;
- - if (d == '[')
- - {
- - add(String);
- - add(Inbrack);
- - while ((c = hgetc()) != ']' && !istok(c) && c != EOF)
- - add(c);
- - c = Outbrack;
- - }
- - else if (d == '(')
- - {
- - add(String);
- - skipcomm();
- - c = Outpar;
- - }
- - else
- - hungetc(d);
- - }
- - else if (c == '^')
- - c = Hat;
- - else if (c == '[')
- - c = Inbrack;
- - else if (c == ']')
- - c = Outbrack;
- - else if (c == '*')
- - c = Star;
- - else if (intpos && c == '~')
- - c = Tilde;
- - else if (c == '?')
- - c = Quest;
- - else if (c == '(')
- - {
- - int d = hgetc();
- -
- - hungetc(d);
- - if (!incmd)
- - break;
- -#if 0
- - if (d != ')' && intpos)
- - {
- - add(Inang);
- - skipcomm();
- - c = Outpar;
- - }
- - else
- -#endif
- - {
- - pct++;
- - c = Inpar;
- - }
- - }
- - else if (c == '{')
- - {
- - c = Inbrace;
- - bct++;
- - }
- - else if (c == '}')
- - {
- - if (!bct)
- - break;
- - c = Outbrace;
- - bct--;
- - }
- - else if (c == '>')
- - {
- - d = hgetc();
- - if (d != '(')
- - {
- - hungetc(d);
- - break;
- - }
- - add(Outang);
- - skipcomm();
- - c = Outpar;
- - }
- - else if (c == '<')
- - {
- - d = hgetc();
- - if (!(isdigit(d) || d == '-' || d == '>' || d == '(' || d == ')'))
- - {
- - hungetc(d);
- - break;
- - }
- - c = Inang;
- - if (d == '(')
- - {
- - add(c);
- - skipcomm();
- - c = Outpar;
- - }
- - else if (d == ')')
- - hungetc(d);
- - else
- - {
- - add(c);
- - c = d;
- - while (c != '>' && !istok(c) && c != EOF)
- - add(c),c = hgetc();
- - if (c == EOF)
- - {
- - errflag = 1;
- - peek = EOF;
- - return;
- - }
- - c = Outang;
- - }
- - }
- - else if (c == '=')
- - {
- - if (intpos)
- - {
- - d = hgetc();
- - if (d != '(')
- - {
- - hungetc(d);
- - c = Equals;
- - }
- - else
- - {
- - add(Equals);
- - skipcomm();
- - c = Outpar;
- - }
- - }
- - else if (peek != ENVSTRING)
- - {
- - peek = ENVSTRING;
- - intpos = 2;
- - }
- - }
- - else if (c == '\\')
- - {
- - c = hgetc();
- -
- - if (c == '\n')
- - {
- - c = hgetc();
- - continue;
- - }
- - add(c);
- - c = hgetc();
- - continue;
- - }
- - else if (c == '\'')
- - {
- - add(Nularg);
- -
- - /* we add the Nularg to prevent this:
- -
- - echo $PA'TH'
- -
- - from printing the path. */
- -
- - while ((c = hgetc()) != '\'' && !istok(c) && c != EOF)
- - add(c);
- - if (c == EOF)
- - {
- - errflag = 1;
- - peek = EOF;
- - return;
- - }
- - c = Nularg;
- - }
- - else if (c == HQUOT)
- - {
- - add(Nularg);
- - while ((c = hgetc()) != HQUOT && !istok(c) && c != EOF)
- - add(c);
- - if (c == EOF)
- - {
- - errflag = 1;
- - peek = EOF;
- - return;
- - }
- - c = Nularg;
- - }
- - else if (c == '\"')
- - {
- - add(Nularg);
- - while ((c = hgetc()) != '\"' && !istok(c) && c != EOF)
- - if (c == '\\')
- - {
- - c = hgetc();
- - if (c != '\n')
- - {
- - if (c != '$' && c != '\\' && c != '\"' && c != '`')
- - add('\\');
- - add(c);
- - }
- - }
- - else
- - {
- - if (c == '$')
- - {
- - int d = hgetc();
- -
- - if (d == '(')
- - {
- - add(Qstring);
- - skipcomm();
- - c = Outpar;
- - }
- - else if (d == '[')
- - {
- - add(String);
- - add(Inbrack);
- - while ((c = hgetc()) != ']' && c != EOF)
- - add(c);
- - c = Outbrack;
- - }
- - else
- - {
- - c = Qstring;
- - hungetc(d);
- - }
- - }
- - else if (c == '`')
- - c = Qtick;
- - add(c);
- - }
- - if (c == EOF)
- - {
- - errflag = 1;
- - peek = EOF;
- - return;
- - }
- - c = Nularg;
- - }
- - else if (c == '`')
- - {
- - add(Tick);
- - while ((c = hgetc()) != '`' && !istok(c) && c != EOF)
- - if (c == '\\')
- - {
- - c = hgetc();
- - if (c != '\n')
- - {
- - if (c != '`' && c != '\\' && c != '$')
- - add('\\');
- - add(c);
- - }
- - }
- - else
- - {
- - if (c == '$')
- - c = String;
- - add(c);
- - }
- - if (c == EOF)
- - {
- - errflag = 1;
- - peek = EOF;
- - return;
- - }
- - c = Tick;
- - }
- - add(c);
- - c = hgetc();
- - if (intpos)
- - intpos--;
- - }
- - if (c == HERR)
- - {
- - free(tstr);
- - peek = HERR;
- - return;
- - }
- - hungetc(c);
- - *bptr = '\0';
- -}
- -
- -/* expand aliases, perhaps */
- -
- -int exalias(void)
- -{
- -struct anode *an;
- -char *s;
- -
- - s = hwadd();
- - if (alix != MAXAL && (an = gethnode(s,alhtab)) && !an->inuse &&
- - !(an->cmd && incmd && alstat != ALSTAT_MORE))
- - {
- - if (an->cmd < 0)
- - {
- - peek = DO-an->cmd-1;
- - return 0;
- - }
- - an->inuse = 1;
- - hungets(strdup(ALPOPS));
- - hungets(strdup((alstack[alix++] = an)->text));
- - alstat = 0;
- - if (tstr)
- - free(tstr);
- - return 1;
- - }
- - return 0;
- -}
- -
- -/* != 0 if c is not a newline, but in IFS */
- -
- -int zspace(int c)
- -{
- - if (c == '\n')
- - return 0;
- - return znspace(c);
- -}
- -
- -/* != 0 if c is in IFS */
- -
- -int znspace(int c)
- -{
- -char *ptr = ifs;
- -
- - while (*ptr)
- - if (*ptr++ == c)
- - return 1;
- - return 0;
- -}
- -
- -/* skip (...) */
- -
- -void skipcomm(void)
- -{
- -int pct = 1,c;
- -
- - c = Inpar;
- - do
- - {
- - add(c);
- -reget:
- - c = hgetc();
- - if (istok(c) || c == EOF)
- - break;
- - else if (c == '(') pct++;
- - else if (c == ')') pct--;
- - else if (c == '\\')
- - {
- - add(c);
- - c = hgetc();
- - }
- - else if (c == '\'')
- - {
- - add(c);
- - while ((c = hgetc()) != '\'' && !istok(c) && c != EOF)
- - add(c);
- - }
- - else if (c == HQUOT)
- - {
- - while ((c = hgetc()) != HQUOT && !istok(c) && c != EOF)
- - add(c);
- - goto reget;
- - }
- - else if (c == '\"')
- - {
- - add(c);
- - while ((c = hgetc()) != '\"' && !istok(c) && c != EOF)
- - if (c == '\\')
- - {
- - add(c);
- - add(hgetc());
- - }
- - else add(c);
- - }
- - else if (c == '`')
- - {
- - add(c);
- - while ((c = hgetc()) != '`' && c != HERR && c != EOF)
- - if (c == '\\') add(c), add(hgetc());
- - else add(c);
- - }
- - }
- - while(pct);
- -}
- -
- End of lex.c
- echo lex.pro 1>&2
- sed 's/^-//' >lex.pro <<'End of lex.pro'
- -void matchit(void);
- -void add(int c);
- -void gettok(void);
- -int exalias(void);
- -int zspace(int c);
- -int znspace(int c);
- -void skipcomm(void);
- End of lex.pro
- echo loop.c 1>&2
- sed 's/^-//' >loop.c <<'End of loop.c'
- -/*
- -
- - loop.c - parsing and executing loop constructs
- -
- - 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"
- -
- -/* parse a for/select loop */
- -
- -int parfor(comm comm,int isfor)
- -{
- -struct fornode *node = alloc(sizeof(struct fornode));
- -char *comnam = (isfor) ? "for" : "select";
- -
- - comm->type = (isfor) ? CFOR : CSELECT;
- - comm->info = node;
- - if (peek != STRING)
- - {
- - zerr("parse error in %s: identifier expected",comnam);
- - errflag = 1;
- - return 0;
- - }
- - node->name = tstr;
- - matchit();
- - node->list = NULL;
- - node->inflag = 0;
- - if (peek == STRING && !strcmp("in",tstr))
- - {
- - node->inflag = 1;
- - free(tstr);
- - matchit();
- - while (peek == STRING)
- - {
- - addnode(comm->args,tstr);
- - matchit();
- - }
- - }
- - if (peek != NEWLIN && peek != SEMI)
- - {
- - zerr("parse error: bad token in '%s' list",comnam);
- - freecmd(comm);
- - return 1;
- - }
- - incmd = 0;
- - matchit();
- - while (peek == NEWLIN)
- - matchit();
- - if (peek != DO)
- - {
- - zerr("parse error: 'do' expected");
- - freecmd(comm);
- - return 1;
- - }
- - matchit();
- - if (!(node->list = parlist(1)))
- - {
- - freecmd(comm);
- - return 1;
- - }
- - if (peek != DONE)
- - {
- - zerr("parse error: 'done' expected");
- - freecmd(comm);
- - return 1;
- - }
- - matchit();
- - return 0;
- -}
- -
- -int parcase(comm comm)
- -{
- -struct casenode *node = alloc(sizeof(struct casenode)),*last = NULL;
- -char *tok; /* add FREES to this function */
- -
- - comm->type = CCASE;
- - comm->info = node;
- - if (peek != STRING)
- - {
- - zerr("parse error in case: identifier expected");
- - errflag = 1;
- - return 0;
- - }
- - addnode(comm->args,tstr);
- - matchit();
- - if (peek != STRING || strcmp(tstr,"in"))
- - {
- - zerr("parse error in case: `in' expected");
- - errflag = 1;
- - return 0;
- - }
- - while (tok = getcasepat())
- - {
- - node = alloc(sizeof(struct casenode));
- - node->pat = tok;
- - if (last)
- - last->next = node;
- - else
- - comm->info = node;
- - (last = node)->list = parlist(1);
- - if (peek != DSEMI)
- - {
- - zerr("parse error: ;; expected");
- - return 1;
- - }
- - }
- - if (!last)
- - {
- - zerr("null case construct");
- - return 1;
- - }
- - return 0;
- -}
- -
- -/* get a case pattern: foo) */
- -
- -char *getcasepat(void)
- -{
- -int c,bsiz = 256,ct = 0,pct = 0,qt = 0;
- -char *buf = zalloc(bsiz),*ptr,*s;
- -
- - peek = EMPTY;
- - while (znspace(c = hgetc()))
- - {
- - if (c == '\n')
- - {
- - hwbegin();
- - hwaddc('\n');
- - hwadd();
- - }
- - }
- - ptr = buf;
- - hwbegin();
- - hwaddc(c);
- - while (c != ')' || pct)
- - {
- - for (s = tokens; *s; s++)
- - if (*s == c)
- - {
- - c = (s-tokens)+Pound;
- - break;
- - }
- - if (qt)
- - {
- - if (c == '\'')
- - {
- - qt = 0;
- - c = hgetc();
- - continue;
- - }
- - if (c == EOF)
- - {
- - qt = 0;
- - continue;
- - }
- - }
- - else
- - {
- - if (c == '\\')
- - c = hgetc();
- - if (c == '\'')
- - {
- - qt = 1;
- - c = hgetc();
- - continue;
- - }
- - if (c == Inpar)
- - pct++;
- - if (c == Outpar)
- - pct--;
- - if (ct == 4 && (znspace(c)||c ==';'||c=='&') && !strncmp(buf,"esac",4))
- - {
- - hungetc(c);
- - hwadd();
- - free(buf);
- - matchit();
- - return NULL;
- - }
- - if (c == '\n' || c == EOF)
- - {
- - free(buf);
- - zerr("parse error: 'esac' expected");
- - return NULL;
- - }
- - }
- - if (c == HERR)
- - {
- - free(buf);
- - return NULL;
- - }
- - *ptr++ = c;
- - if (++ct == bsiz)
- - {
- - ptr = zalloc(bsiz *= 2);
- - memcpy(ptr,buf,ct);
- - free(buf);
- - buf = ptr;
- - ptr = buf+ct;
- - }
- - c = hgetc();
- - }
- - *ptr = 0;
- - hwadd();
- - return buf;
- -}
- -
- -int parif(comm comm)
- -{
- -struct ifnode *node = alloc(sizeof(struct ifnode));
- -
- - comm->type = CIF;
- - comm->info = node;
- -do_then:
- - node->next = NULL;
- - if (!(node->ifl = parlist(1)))
- - {
- - freecmd(comm);
- - return 1;
- - }
- - if (peek != THEN)
- - {
- - zerr("parse error: 'then' expected");
- - freecmd(comm);
- - return 1;
- - }
- - matchit();
- - if (!(node->thenl = parlist(1)))
- - {
- - freecmd(comm);
- - return 1;
- - }
- - if (peek == ELIF)
- - {
- - matchit();
- - node = node->next = alloc(sizeof(struct ifnode));
- - goto do_then;
- - }
- - else if (peek == ELSE)
- - {
- - matchit();
- - node = node->next = alloc(sizeof(struct ifnode));
- - node->next = NULL;
- - node->ifl = NULL;
- - if (!(node->thenl = parlist(1)))
- - {
- - freecmd(comm);
- - return 1;
- - }
- - }
- - if (peek != FI)
- - {
- - zerr("parse error: 'fi' expected");
- - freecmd(comm);
- - return 1;
- - }
- - matchit();
- - return 0;
- -}
- -
- -/* parse while or until */
- -
- -int parwhile(comm comm,int cond)
- -{
- -struct whilenode *node = alloc(sizeof (struct whilenode));
- -
- - comm->type = CWHILE;
- - comm->info = node;
- - node->cond = cond;
- - node->loop = node->cont = NULL;
- - if (!(node->cont = parlist(1)))
- - {
- - freecmd(comm);
- - return NULL;
- - }
- - if (peek != DO)
- - {
- - zerr("parse error: 'do' expected");
- - freecmd(comm);
- - return 1;
- - }
- - matchit();
- - node->loop = parlist(1);
- - if (peek != DONE)
- - {
- - zerr("parse error: 'done' expected");
- - freecmd(comm);
- - return 1;
- - }
- - matchit();
- - return 0;
- -}
- -
- -int parrepeat(comm comm)
- -{
- -struct repeatnode *node = alloc(sizeof (struct repeatnode));
- -
- - comm->type = CREPEAT;
- - comm->info = node;
- - node->list = NULL;
- - if (peek != STRING || !isdigit(*tstr))
- - {
- - zerr("parse error: number expected");
- - freecmd(comm);
- - return 1;
- - }
- - node->count = atoi(tstr);
- - free(tstr);
- - incmd = 0;
- - do
- - matchit();
- - while (peek == NEWLIN);
- - if (peek != DO)
- - {
- - zerr("parse error: 'do' expected");
- - freecmd(comm);
- - return 1;
- - }
- - matchit();
- - node->list = parlist(1);
- - if (peek != DONE)
- - {
- - zerr("parse error: 'done' expected");
- - freecmd(comm);
- - return 1;
- - }
- - matchit();
- - return 0;
- -}
- -
- -void execfor(comm comm)
- -{
- -list list;
- -struct fornode *node;
- -char *str;
- -table args;
- -int cj = curjob;
- -
- - loops++;
- - exiting = 0;
- - node = comm->info;
- - args = comm->args;
- - if (!node->inflag)
- - {
- - args = duptable(pparms,dupstr);
- - freestr(getnode(args));
- - }
- - while (str = getnode(args))
- - {
- - setparm(strdup(node->name),str,0,0);
- - list = duplist(node->list);
- - execlist(list);
- - if (breaks)
- - {
- - breaks--;
- - if (breaks || !contflag)
- - break;
- - contflag = 0;
- - }
- - }
- - curjob = cj;
- -}
- -
- -void execselect(comm comm)
- -{
- -list list;
- -struct fornode *node;
- -char *str,*s;
- -table args;
- -Node n;
- -int cj = curjob,t0;
- -
- - loops++;
- - node = comm->info;
- - args = comm->args;
- - exiting = 0;
- - for (;;)
- - {
- - do
- - {
- - for (t0 = 1,n = args->first; n; n=n->next,t0++)
- - fprintf(stderr,"%d %s\n",t0,n->dat);
- - if (interact && SHTTY != -1)
- - {
- - inittty();
- - str = readline(putprompt("PROMPT3"));
- - }
- - else
- - str = fgets(zalloc(256),256,bshin);
- - if (!str || errflag)
- - {
- - fprintf(stderr,"\n");
- - goto done;
- - }
- - if (s = strchr(str,'\n'))
- - *s = '\0';
- - }
- - while (!*str);
- - setparm(strdup("REPLY"),str,0,0);
- - t0 = atoi(str);
- - if (!t0)
- - str = "";
- - else
- - {
- - for (t0--,n = args->first; n && t0; n=n->next,t0--);
- - if (n)
- - str = n->dat;
- - else
- - str = "";
- - }
- - setparm(strdup(node->name),strdup(str),0,0);
- - list = duplist(node->list);
- - execlist(list);
- - if (breaks)
- - {
- - breaks--;
- - if (breaks || !contflag)
- - break;
- - contflag = 0;
- - }
- - if (errflag)
- - break;
- - }
- -done:
- - curjob = cj;
- -}
- -
- -void execwhile(comm comm)
- -{
- -list list;
- -struct whilenode *node;
- -int cj = curjob;
- -
- - loops++;
- - node = comm->info;
- - exiting = 0;
- - FOREVER
- - {
- - list = duplist(node->cont);
- - execlist(list);
- - if (!((lastval == 0) ^ node->cond))
- - break;
- - if (breaks)
- - {
- - breaks--;
- - if (breaks || !contflag)
- - break;
- - contflag = 0;
- - }
- - list = duplist(node->loop);
- - execlist(list);
- - }
- - curjob = cj;
- -}
- -
- -void execrepeat(comm comm)
- -{
- -list list;
- -struct repeatnode *node;
- -int cj = curjob;
- -
- - loops++;
- - node = comm->info;
- - exiting = 0;
- - while (node->count--)
- - {
- - list = duplist(node->list);
- - execlist(list);
- - if (breaks)
- - {
- - breaks--;
- - if (breaks || !contflag)
- - break;
- - contflag = 0;
- - }
- - if (lastval)
- - break;
- - }
- - curjob = cj;
- -}
- -
- -void execif(comm comm)
- -{
- -list list;
- -struct ifnode *node;
- -int cj = curjob;
- -
- - node = comm->info;
- - exiting = 0;
- - while (node)
- - {
- - if (node->ifl)
- - {
- - list = duplist(node->ifl);
- - execlist(list);
- - if (lastval)
- - {
- - node = node->next;
- - continue;
- - }
- - }
- - list = duplist(node->thenl);
- - execlist(list);
- - break;
- - }
- - curjob = cj;
- -}
- -
- -void execcase(comm comm)
- -{
- -list list;
- -struct casenode *node;
- -char *word;
- -table args;
- -int cj = curjob;
- -
- - node = comm->info;
- - args = comm->args;
- - exiting = 0;
- - if (!args->first || args->first->next)
- - {
- - zerr("bad case statement");
- - errflag = 1;
- - return;
- - }
- - word = args->first->dat;
- - while (node)
- - if (matchpat(word,node->pat))
- - break;
- - else
- - node = node->next;
- - if (node)
- - {
- - list = duplist(node->list);
- - execlist(list);
- - }
- - curjob = cj;
- -}
- -
- -list duplist(list xlist)
- -{
- -list nlist;
- -
- - if (!xlist)
- - return NULL;
- - nlist = alloc(sizeof(struct lnode));
- - nlist->left = duplist2(xlist->left);
- - nlist->right = duplist(xlist->right);
- - nlist->type = xlist->type;
- - return nlist;
- -}
- -
- -void freelist(list xlist)
- -{
- - if (xlist)
- - {
- - freelist2(xlist->left);
- - freelist(xlist->right);
- - free(xlist);
- - }
- -}
- -
- -list2 duplist2(list2 x)
- -{
- -list2 y;
- -
- - if (!x)
- - return NULL;
- - y = alloc(sizeof(struct l2node));
- - *y = *x;
- - y->left = duppline(x->left);
- - y->right = duplist2(x->right);
- - return y;
- -}
- -
- -void freelist2(list2 x)
- -{
- - if (x)
- - {
- - freepline(x->left);
- - freelist2(x->right);
- - free(x);
- - }
- -}
- -
- -pline duppline(pline xpline)
- -{
- -pline npline;
- -
- - if (!xpline)
- - return NULL;
- - npline = alloc(sizeof(struct pnode));
- - npline->left = dupcomm(xpline->left);
- - npline->right = duppline(xpline->right);
- - npline->type = xpline->type;
- - return npline;
- -}
- -
- -void freepline(pline x)
- -{
- - if (x)
- - {
- - freecmd(x->left);
- - freepline(x->right);
- - free(x);
- - }
- -}
- -
- -comm dupcomm(comm xcomm)
- -{
- -comm ncomm;
- -void *(*duprs[])(void *) = {dupfor,dupwhile,duprepeat,dupif,dupcase};
- -int type;
- -
- - if (!xcomm)
- - return NULL;
- - ncomm = alloc(sizeof(struct cnode));
- - ncomm->left = duplist(xcomm->left);
- - ncomm->cmd = dupstr(xcomm->cmd);
- - ncomm->args = duptable(xcomm->args,dupstr);
- - ncomm->redir = duptable(xcomm->redir,dupfnode);
- - ncomm->vars = (xcomm->vars) ? duptable(xcomm->vars,dupstr) : NULL;
- - ncomm->type = type = xcomm->type;
- - if (type >= CFOR && type <= CCASE)
- - ncomm->info = (duprs[type-CFOR])(xcomm->info);
- - return ncomm;
- -}
- -
- -void freecmd(comm x)
- -{
- - if (x)
- - {
- - freelist(x->left);
- - if (x->cmd)
- - free(x->cmd);
- - if (x->args)
- - freetable(x->args,freestr);
- - if (x->redir)
- - freetable(x->redir,freeredir);
- - if (x->vars)
- - freetable(x->vars,freestr);
- -/* if (x->info)
- - freeinfo(x->info);*/
- - free(x);
- - }
- -}
- -
- -void *dupstr(void *str)
- -{
- - if (!str)
- - return NULL;
- - return strdup(str);
- -}
- -
- -void *dupfnode(void *i)
- -{
- -struct fnode *fn = i,*nfn = alloc(sizeof(struct fnode));
- -
- - if (!i)
- - return NULL;
- - *nfn = *fn;
- - if (nfn->type < HEREDOC)
- - nfn->u.name = strdup(fn->u.name);
- - return nfn;
- -}
- -
- -void *dupfor(void *i)
- -{
- -struct fornode *nnode,*node = i;
- -
- - nnode = alloc(sizeof(struct fornode));
- - *nnode = *(struct fornode *) i;
- - nnode->name = strdup(node->name);
- - nnode->list = duplist(node->list);
- - return nnode;
- -}
- -
- -void *dupcase(void *i)
- -{
- -struct casenode *nnode,*node = i;
- -
- - if (!i)
- - return NULL;
- - nnode = alloc(sizeof(struct casenode));
- - nnode->next = dupcase(node->next);
- - nnode->list = duplist(node->list);
- - nnode->pat = strdup(node->pat);
- - return nnode;
- -}
- -
- -void *dupif(void *i)
- -{
- -struct ifnode *nnode,*node = i;
- -
- - if (!i)
- - return NULL;
- - nnode = alloc(sizeof(struct ifnode));
- - nnode->next = dupif(node->next);
- - nnode->ifl = duplist(node->ifl);
- - nnode->thenl = duplist(node->thenl);
- - return nnode;
- -}
- -
- -void *dupwhile(void *i)
- -{
- -struct whilenode *nnode,*node = i;
- -
- - if (!i)
- - return NULL;
- - nnode = alloc(sizeof(struct whilenode));
- - nnode->cond = node->cond;
- - nnode->cont = duplist(node->cont);
- - nnode->loop = duplist(node->loop);
- - return nnode;
- -}
- -
- -void *duprepeat(void *i)
- -{
- -struct repeatnode *nnode,*node = i;
- -
- - if (!i)
- - return NULL;
- - nnode = alloc(sizeof(struct repeatnode));
- - nnode->count = node->count;
- - nnode->list = duplist(node->list);
- - return nnode;
- -}
- -
- -table duptable(table tab,void *(*func)(void *))
- -{
- -table ret;
- -Node node;
- -
- - ret = newtable();
- - for (node = tab->first; node; node = node->next)
- - addnode(ret,func(node->dat));
- - return ret;
- -}
- End of loop.c
- echo loop.pro 1>&2
- sed 's/^-//' >loop.pro <<'End of loop.pro'
- -int parfor(comm comm,int isfor);
- -int parcase(comm comm);
- -char *getcasepat(void);
- -int parif(comm comm);
- -int parwhile(comm comm,int cond);
- -int parrepeat(comm comm);
- -void execfor(comm comm);
- -void execselect(comm comm);
- -void execwhile(comm comm);
- -void execrepeat(comm comm);
- -void execif(comm comm);
- -void execcase(comm comm);
- -list duplist(list xlist);
- -void freelist(list xlist);
- -list2 duplist2(list2 x);
- -void freelist2(list2 x);
- -pline duppline(pline xpline);
- -void freepline(pline x);
- -comm dupcomm(comm xcomm);
- -void freecmd(comm x);
- -void *dupstr(void *str);
- -void *dupfnode(void *i);
- -void *dupfor(void *i);
- -void *dupcase(void *i);
- -void *dupif(void *i);
- -void *dupwhile(void *i);
- -void *duprepeat(void *i);
- -table duptable(table tab,void *(*func)(void *));
- End of loop.pro
- echo math.c 1>&2
- sed 's/^-//' >math.c <<'End of math.c'
- -/*
- -
- - math.c - evaluating arithmetic expressions
- -
- - 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 <stdio.h>
- -#include <ctype.h>
- -#include <string.h>
- -#include <math.h>
- -#include <assert.h>
- -
- -extern int errflag;
- -extern char *setiparm(char *,long,int);
- -extern long getiparm(char *);
- -extern void zerr(char *,...);
- -extern char *strdup(char *);
- -
- -char *ptr;
- -
- -typedef int LV;
- -
- -long yyval;
- -LV yylval;
- -
- -/* nonzero means we are not evaluating, just parsing */
- -
- -int noeval = 0;
- -
- -/* != 0 means recognize unary plus, minus, etc.
- - The parser was originally written in lex, hence the name. */
- -
- -int initial = 1;
- -
- -void mathparse(int);
- -
- -/* LR = left-to-right associativity
- - RL = right-to-left associativity
- - BOO = short-circuiting boolean */
- -
- -enum xtyp { LR,RL,BOO };
- -
- -enum xtok {
- -INPAR, OUTPAR, NOT, COMP, POSTPLUS,
- -POSTMINUS, UPLUS, UMINUS, AND, XOR,
- -OR, MUL, DIV, MOD, PLUS,
- -MINUS, SHLEFT, SHRIGHT, LES, LEQ,
- -GRE, GEQ, DEQ, NEQ, DAND,
- -DOR, DXOR, QUEST, COLON, EQ,
- -PLUSEQ, MINUSEQ, MULEQ, DIVEQ, MODEQ,
- -ANDEQ, XOREQ, OREQ, SHLEFTEQ, SHRIGHTEQ,
- -DANDEQ, DOREQ, DXOREQ, COMMA, EOI,
- -PREPLUS, PREMINUS, NUM, ID, TOKCOUNT
- -};
- -
- -/* precedences */
- -
- -int prec[TOKCOUNT] = {
- -1,200,2,2,2,
- -2,2,2,3,4,
- -5,6,6,6,7,
- -7,8,8,9,9,
- -9,9,10,10,11,
- -12,12,13,13,14,
- -14,14,14,14,14,
- -14,14,14,14,14,
- -14,14,14,15,200,
- -2,2,0,0,
- -};
- -
- -#define TOPPREC 15
- -
- -int type[TOKCOUNT] = {
- -LR,LR,RL,RL,RL,
- -RL,RL,RL,LR,LR,
- -LR,LR,LR,LR,LR,
- -LR,LR,LR,LR,LR,
- -LR,LR,LR,LR,BOO,
- -BOO,LR,RL,RL,RL,
- -RL,RL,RL,RL,RL,
- -RL,RL,RL,RL,RL,
- -BOO,BOO,RL,RL,RL,
- -RL,RL,LR,LR,
- -};
- -
- -#define LVCOUNT 32
- -
- -/* table of lvalues (variables) */
- -
- -int lvc;
- -char *lvals[LVCOUNT];
- -
- -int yylex(void)
- -{
- - for(;;)
- - switch (*ptr++)
- - {
- - case '+':
- - if (*ptr == '+' && (initial || !isalnum(*ptr)))
- - {
- - ptr++;
- - return (initial) ? PREPLUS : POSTPLUS;
- - }
- - if (*ptr == '=') { initial = 1; ptr++; return PLUSEQ; }
- - return (initial) ? UPLUS : PLUS;
- - case '-':
- - if (*ptr == '-' && (initial || !isalnum(*ptr)))
- - {
- - ptr++;
- - return (initial) ? PREMINUS : POSTMINUS;
- - }
- - if (*ptr == '=') { initial = 1; ptr++; return MINUSEQ; }
- - return (initial) ? UMINUS : MINUS;
- - case '(': initial = 1; return INPAR;
- - case ')': return OUTPAR;
- - case '!': if (*ptr == '=')
- - { initial = 1; ptr++; return NEQ; }
- - return NOT;
- - case '~': return COMP;
- - case '&': initial = 1;
- - if (*ptr == '&') { if (*++ptr == '=')
- - { ptr++; return DANDEQ; } return DAND; }
- - else if (*ptr == '=') { ptr++; return ANDEQ; } return AND;
- - case '|': initial = 1;
- - if (*ptr == '|') { if (*++ptr == '=')
- - { ptr++; return DOREQ; } return DOR; }
- - else if (*ptr == '=') { ptr++; return OREQ; } return OR;
- - case '^': initial = 1;
- - if (*ptr == '^') { if (*++ptr == '=')
- - { ptr++; return DXOREQ; } return DXOR; }
- - else if (*ptr == '=') { ptr++; return XOREQ; } return XOR;
- - case '*': initial = 1;
- - if (*ptr == '=') { ptr++; return MULEQ; } return MUL;
- - case '/': initial = 1;
- - if (*ptr == '=') { ptr++; return DIVEQ; } return DIV;
- - case '%': initial = 1;
- - if (*ptr == '=') { ptr++; return MODEQ; } return MOD;
- - case '<': initial = 1; if (*ptr == '<')
- - { if (*++ptr == '=') { ptr++; return SHLEFTEQ; } return SHLEFT; }
- - else if (*ptr == '=') { ptr++; return LEQ; } return LES;
- - case '>': initial = 1; if (*ptr == '>')
- - { if (*++ptr == '=') { ptr++; return SHRIGHTEQ; } return SHRIGHT; }
- - else if (*ptr == '=') { ptr++; return GEQ; } return GRE;
- - case '=': initial = 1; if (*ptr == '=') { ptr++; return DEQ; }
- - return EQ;
- - case '?': initial = 1; return QUEST;
- - case ':': initial = 1; return COLON;
- - case ',': initial = 1; return COMMA;
- - case '\0': initial = 1; ptr--; return EOI;
- - case '[': initial = 0;
- - { int base = strtol(ptr,&ptr,10);
- - yyval = strtol(ptr+1,&ptr,base); return NUM; }
- - case ' ': case '\t':
- - break;
- - default:
- - if (isdigit(*--ptr))
- - { initial = 0; yyval = strtol(ptr,&ptr,10); return NUM; }
- - if (isalpha(*ptr) || *ptr == '$')
- - {
- - char *p,q;
- -
- - if (*ptr == '$')
- - ptr++;
- - p = ptr;
- - if (lvc == LVCOUNT)
- - {
- - zerr("too many identifiers in expression");
- - errflag = 1;
- - return EOI;
- - }
- - initial = 0;
- - while(isalpha(*++ptr));
- - q = *ptr;
- - *ptr = '\0';
- - lvals[yylval = lvc++] = strdup(p);
- - *ptr = q;
- - return ID;
- - }
- - zerr("illegal character: %c",*ptr);
- - errflag = 1;
- - return EOI;
- - }
- -}
- -
- -/* the value stack */
- -
- -#define STACKSZ 1000
- -int tok; /* last token */
- -int sp = -1; /* stack pointer */
- -struct value {
- - LV lval;
- - long val;
- - } stack[STACKSZ];
- -
- -void push(long val,LV lval)
- -{
- - sp++;
- - stack[sp].val = val;
- - stack[sp].lval = lval;
- -}
- -
- -long getvar(LV s)
- -{
- -long t;
- -
- - if (!(t = getiparm(lvals[s])))
- - return 0;
- - return t;
- -}
- -
- -long setvar(LV s,long v)
- -{
- - if (s == -1)
- - {
- - zerr("lvalue required");
- - errflag = 1;
- - return 0;
- - }
- - if (noeval)
- - return v;
- - setiparm(strdup(lvals[s]),v,0);
- - return v;
- -}
- -
- -int notzero(int a)
- -{
- - if (a == 0)
- - {
- - errflag = 1;
- - zerr("division by zero");
- - return 0;
- - }
- - return 1;
- -}
- -
- -#define pop2() { b = stack[sp--].val; a = stack[sp--].val; }
- -#define pop3() {c=stack[sp--].val;b=stack[sp--].val;a=stack[sp--].val;}
- -#define nolval() {stack[sp].lval=-1;}
- -#define pushv(X) { push(X,-1); }
- -#define pop2lv() { pop2() lv = stack[sp+1].lval; }
- -#define set(X) { push(setvar(lv,X),lv); }
- -
- -void op(int what)
- -{
- -long a,b,c;
- -LV lv;
- -
- - switch(what) {
- - case NOT: stack[sp].val = !stack[sp].val; nolval(); break;
- - case COMP: stack[sp].val = ~stack[sp].val; nolval(); break;
- - case POSTPLUS: (void) setvar(stack[sp].lval,stack[sp].val+1); break;
- - case POSTMINUS: (void) setvar(stack[sp].lval,stack[sp].val-1); break;
- - case UPLUS: nolval(); break;
- - case UMINUS: stack[sp].val = -stack[sp].val; nolval(); break;
- - case AND: pop2(); pushv(a&b); break;
- - case XOR: pop2(); pushv(a^b); break;
- - case OR: pop2(); pushv(a|b); break;
- - case MUL: pop2(); pushv(a*b); break;
- - case DIV: pop2(); if (notzero(b)) pushv(a/b); break;
- - case MOD: pop2(); if (notzero(b)) pushv(a%b); break;
- - case PLUS: pop2(); pushv(a+b); break;
- - case MINUS: pop2(); pushv(a-b); break;
- - case SHLEFT: pop2(); pushv(a<<b); break;
- - case SHRIGHT: pop2(); pushv(a>>b); break;
- - case LES: pop2(); pushv(a<b); break;
- - case LEQ: pop2(); pushv(a<=b); break;
- - case GRE: pop2(); pushv(a>b); break;
- - case GEQ: pop2(); pushv(a>=b); break;
- - case DEQ: pop2(); pushv(a==b); break;
- - case NEQ: pop2(); pushv(a!=b); break;
- - case DAND: pop2(); pushv(a&&b); break;
- - case DOR: pop2(); pushv(a||b); break;
- - case DXOR: pop2(); pushv(a&&!b||!a&&b); break;
- - case QUEST: pop3(); pushv((a)?b:c); break;
- - case COLON: break;
- - case EQ: pop2lv(); set(b); break;
- - case PLUSEQ: pop2lv(); set(a+b); break;
- - case MINUSEQ: pop2lv(); set(a-b); break;
- - case MULEQ: pop2lv(); set(a*b); break;
- - case DIVEQ: pop2lv(); if (notzero(b)) set(a/b); break;
- - case MODEQ: pop2lv(); if (notzero(b)) set(a%b); break;
- - case ANDEQ: pop2lv(); set(a&b); break;
- - case XOREQ: pop2lv(); set(a^b); break;
- - case OREQ: pop2lv(); set(a|b); break;
- - case SHLEFTEQ: pop2lv(); set(a<<b); break;
- - case SHRIGHTEQ: pop2lv(); set(a>>b); break;
- - case DANDEQ: pop2lv(); set(a&&b); break;
- - case DOREQ: pop2lv(); set(a||b); break;
- - case DXOREQ: pop2lv(); set(a&&!b||!a&&b); break;
- - case COMMA: pop2(); pushv(b); break;
- - case PREPLUS: stack[sp].val = setvar(stack[sp].lval,
- - stack[sp].val+1); break;
- - case PREMINUS: stack[sp].val = setvar(stack[sp].lval,
- - stack[sp].val-1); break;
- - default: fprintf(stderr,"whoops.\n"); exit(1);
- - }
- -}
- -
- -void bop(int tok)
- -{
- - switch (tok) {
- - case DAND: case DANDEQ: if (!stack[sp].val) noeval++; break;
- - case DOR: case DOREQ: if (stack[sp].val) noeval++; break;
- - };
- -}
- -
- -long matheval(char *s)
- -{
- -int t0;
- -
- - for (t0 = 0; t0 != LVCOUNT; t0++)
- - lvals[t0] = NULL;
- - lvc = 0;
- - ptr = s;
- - sp = -1;
- - mathparse(TOPPREC);
- - if (!errflag && sp)
- - zerr("arithmetic error: unbalanced stack");
- - for (t0 = 0; t0 != lvc; t0++)
- - free(lvals[t0]);
- - return stack[0].val;
- -}
- -
- -/* operator-precedence parse the string and execute */
- -
- -void mathparse(int pc)
- -{
- - if (errflag)
- - return;
- - tok = yylex();
- - while (prec[tok] <= pc)
- - {
- - if (errflag)
- - return;
- - if (tok == NUM)
- - push(yyval,-1);
- - else if (tok == ID)
- - push(getvar(yylval),yylval);
- - else if (tok == INPAR)
- - {
- - mathparse(TOPPREC);
- - if (tok != OUTPAR)
- - exit(1);
- - }
- - else if (tok == QUEST)
- - {
- - int q = stack[sp].val;
- - if (!q) noeval++;
- - mathparse(prec[QUEST]-1);
- - if (!q) noeval--; else noeval++;
- - mathparse(prec[QUEST]);
- - if (q) noeval--;
- - op(QUEST);
- - continue;
- - }
- - else
- - {
- - int otok = tok,onoeval = noeval;
- -
- - if (type[otok] == BOO)
- - bop(otok);
- - mathparse(prec[otok]-(type[otok] != RL));
- - noeval = onoeval;
- - op(otok);
- - continue;
- - }
- - tok = yylex();
- - }
- -}
- -
- End of math.c
- echo math.pro 1>&2
- sed 's/^-//' >math.pro <<'End of math.pro'
- -INPAR, OUTPAR, NOT, COMP, POSTPLUS,;
- -POSTMINUS, UPLUS, UMINUS, AND, XOR,;
- -OR, MUL, DIV, MOD, PLUS,;
- -MINUS, SHLEFT, SHRIGHT, LES, LEQ,;
- -GRE, GEQ, DEQ, NEQ, DAND,;
- -DOR, DXOR, QUEST, COLON, EQ,;
- -PLUSEQ, MINUSEQ, MULEQ, DIVEQ, MODEQ,;
- -ANDEQ, XOREQ, OREQ, SHLEFTEQ, SHRIGHTEQ,;
- -DANDEQ, DOREQ, DXOREQ, COMMA, EOI,;
- -PREPLUS, PREMINUS, NUM, ID, TOKCOUNT;
- -LR,LR,RL,RL,RL,;
- -RL,RL,RL,LR,LR,;
- -LR,LR,LR,LR,LR,;
- -LR,LR,LR,LR,LR,;
- -LR,LR,LR,LR,BOO,;
- -BOO,LR,RL,RL,RL,;
- -RL,RL,RL,RL,RL,;
- -RL,RL,RL,RL,RL,;
- -BOO,BOO,RL,RL,RL,;
- -RL,RL,LR,LR,;
- -int yylex(void);
- -void push(long val,LV lval);
- -long getvar(LV s);
- -long setvar(LV s,long v);
- -int notzero(int a);
- -void op(int what);
- -void bop(int tok);
- -long matheval(char *s);
- -void mathparse(int pc);
- End of math.pro
- echo parse.c 1>&2
- sed 's/^-//' >parse.c <<'End of parse.c'
- -/*
- -
- - parse.c - parsing
- -
- - 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"
- -
- -/* parse a list, but return : instead of NULL */
- -
- -list parlist(int nest)
- -{
- -list l1;
- -list2 l2;
- -pline p;
- -comm c;
- -
- - if (l1 = parlist1(nest))
- - return l1;
- - if (errflag)
- - return NULL;
- - c = alloc(sizeof *c);
- - c->cmd = strdup("");
- - c->args = newtable();
- - c->redir = newtable();
- - c->type = SIMPLE;
- - p = alloc(sizeof *p);
- - p->left = c;
- - p->type = END;
- - l2 = alloc(sizeof *l2);
- - l2->left = p;
- - l2->type = END;
- - l1 = alloc(sizeof *l1);
- - l1->left = l2;
- - l1->type = SYNC;
- - return l1;
- -}
- -
- -/* parse a list */
- -
- -list parlist1(int nest)
- -{
- -list l1 = (list) alloc(sizeof *l1);
- -int isnl;
- -
- - incmd = 0;
- - if (peek == EMPTY)
- - matchit();
- - if (nest)
- - while (peek == NEWLIN || peek == SEMI)
- - matchit();
- - if (!(l1->left = parlist2()))
- - {
- - free(l1);
- - return NULL;
- - }
- - l1->type = (peek == AMPER) ? ASYNC : SYNC;
- - if ((isnl = peek == NEWLIN) || peek == SEMI || peek == AMPER)
- - peek = EMPTY;
- - if ((nest || !isnl) && peek == EMPTY)
- - {
- - if (!(l1->right = parlist1(nest)))
- - {
- - if (!errflag)
- - {
- - if (peek == NEWLIN)
- - peek = EMPTY;
- - return l1;
- - }
- - freelist2(l1->left);
- - free(l1);
- - return NULL;
- - }
- - }
- - else
- - l1->right = NULL;
- - return l1;
- -}
- -
- -/* parse a sublist */
- -
- -list2 parlist2(void)
- ---cut here---cut here---cut here---
-