mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-14 11:41:07 +02:00
21078: parse errors didn't cause non-zero exit status
This commit is contained in:
parent
6f8b647733
commit
e43b2acd67
3 changed files with 767 additions and 95 deletions
|
@ -1,3 +1,8 @@
|
|||
2005-04-01 Peter Stephenson <pws@csr.com>
|
||||
|
||||
* 21078: Src/init.c, Test/A01grammar.ztst: parse errors didn't
|
||||
cause non-zero exit status.
|
||||
|
||||
2005-03-27 Clint Adams <clint@zsh.org>
|
||||
|
||||
* 21075: Completion/Unix/Command/_baz: update baz completion
|
||||
|
|
407
Src/init.c
407
Src/init.c
|
@ -34,6 +34,8 @@
|
|||
|
||||
#include "init.pro"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
/**/
|
||||
int noexitct = 0;
|
||||
|
||||
|
@ -105,7 +107,8 @@ loop(int toplevel, int justonce)
|
|||
pushheap();
|
||||
for (;;) {
|
||||
freeheap();
|
||||
errflag = 0;
|
||||
if (stophist == 3) /* re-entry via preprompt() */
|
||||
hend(NULL);
|
||||
hbegin(1); /* init history mech */
|
||||
if (isset(SHINSTDIN)) {
|
||||
setblock_stdin();
|
||||
|
@ -113,43 +116,55 @@ loop(int toplevel, int justonce)
|
|||
int hstop = stophist;
|
||||
stophist = 3;
|
||||
preprompt();
|
||||
stophist = hstop;
|
||||
if (stophist != 3)
|
||||
hbegin(1);
|
||||
else
|
||||
stophist = hstop;
|
||||
errflag = 0;
|
||||
}
|
||||
}
|
||||
intr(); /* interrupts on */
|
||||
lexinit(); /* initialize lexical state */
|
||||
if (!(prog = parse_event())) { /* if we couldn't parse a list */
|
||||
hend();
|
||||
hend(NULL);
|
||||
if ((tok == ENDINPUT && !errflag) ||
|
||||
(tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) ||
|
||||
justonce)
|
||||
break;
|
||||
if (tok == LEXERR && !lastval)
|
||||
lastval = 1;
|
||||
continue;
|
||||
}
|
||||
if (hend()) {
|
||||
if (hend(prog)) {
|
||||
int toksav = tok;
|
||||
Eprog preprog;
|
||||
|
||||
if (toplevel && (preprog = getshfunc("preexec")) != &dummy_eprog) {
|
||||
LinkList args;
|
||||
int osc = sfcontext;
|
||||
char *cmdstr;
|
||||
|
||||
args = znewlinklist();
|
||||
zaddlinknode(args, "preexec");
|
||||
if (hist_ring)
|
||||
/* If curline got dumped from the history, we don't know
|
||||
* what the user typed. */
|
||||
if (hist_ring && curline.histnum == curhist)
|
||||
zaddlinknode(args, hist_ring->text);
|
||||
else
|
||||
zaddlinknode(args, "");
|
||||
zaddlinknode(args, getjobtext(prog, NULL));
|
||||
zaddlinknode(args, cmdstr = getpermtext(prog, NULL));
|
||||
|
||||
sfcontext = SFC_HOOK;
|
||||
doshfunc("preexec", preprog, args, 0, 1);
|
||||
sfcontext = osc;
|
||||
zsfree(cmdstr);
|
||||
freelinklist(args, (FreeFunc) NULL);
|
||||
errflag = 0;
|
||||
}
|
||||
if (stopmsg) /* unset 'you have stopped jobs' flag */
|
||||
stopmsg--;
|
||||
execode(prog, 0, 0);
|
||||
if (toplevel)
|
||||
freeeprogs();
|
||||
tok = toksav;
|
||||
if (toplevel)
|
||||
noexitct = 0;
|
||||
|
@ -184,10 +199,10 @@ static int restricted;
|
|||
void
|
||||
parseargs(char **argv)
|
||||
{
|
||||
int optionbreak = 0;
|
||||
char **x;
|
||||
int action, optno;
|
||||
LinkList paramlist;
|
||||
int bourne = (emulation == EMULATE_KSH || emulation == EMULATE_SH);
|
||||
|
||||
argzero = *argv++;
|
||||
SHIN = 0;
|
||||
|
@ -204,24 +219,47 @@ parseargs(char **argv)
|
|||
opts[SINGLECOMMAND] = 0;
|
||||
|
||||
/* loop through command line options (begins with "-" or "+") */
|
||||
while (*argv && (**argv == '-' || **argv == '+')) {
|
||||
while (!optionbreak && *argv && (**argv == '-' || **argv == '+')) {
|
||||
char *args = *argv;
|
||||
action = (**argv == '-');
|
||||
if(!argv[0][1])
|
||||
if (!argv[0][1])
|
||||
*argv = "--";
|
||||
while (*++*argv) {
|
||||
/* The pseudo-option `--' signifies the end of options. *
|
||||
* `-b' does too, csh-style, unless we're emulating a *
|
||||
* Bourne style shell. */
|
||||
if (**argv == '-' || (!bourne && **argv == 'b')) {
|
||||
argv++;
|
||||
goto doneoptions;
|
||||
if (**argv == '-') {
|
||||
if(!argv[0][1]) {
|
||||
/* The pseudo-option `--' signifies the end of options. */
|
||||
argv++;
|
||||
goto doneoptions;
|
||||
}
|
||||
if(*argv != args+1 || **argv != '-')
|
||||
goto badoptionstring;
|
||||
/* GNU-style long options */
|
||||
++*argv;
|
||||
if (!strcmp(*argv, "version")) {
|
||||
printf("zsh %s (%s-%s-%s)\n",
|
||||
ZSH_VERSION, MACHTYPE, VENDOR, OSTYPE);
|
||||
exit(0);
|
||||
}
|
||||
if (!strcmp(*argv, "help")) {
|
||||
printhelp();
|
||||
exit(0);
|
||||
}
|
||||
/* `-' characters are allowed in long options */
|
||||
for(args = *argv; *args; args++)
|
||||
if(*args == '-')
|
||||
*args = '_';
|
||||
goto longoptions;
|
||||
}
|
||||
|
||||
if (**argv == 'c') { /* -c command */
|
||||
if (unset(SHOPTIONLETTERS) && **argv == 'b') {
|
||||
/* -b ends options at the end of this argument */
|
||||
optionbreak = 1;
|
||||
} else if (**argv == 'c') {
|
||||
/* -c command */
|
||||
cmd = *argv;
|
||||
opts[INTERACTIVE] &= 1;
|
||||
opts[SHINSTDIN] = 0;
|
||||
scriptname = ztrdup("zsh");
|
||||
} else if (**argv == 'o') {
|
||||
if (!*++*argv)
|
||||
argv++;
|
||||
|
@ -229,9 +267,11 @@ parseargs(char **argv)
|
|||
zerr("string expected after -o", NULL, 0);
|
||||
exit(1);
|
||||
}
|
||||
if(!(optno = optlookup(*argv)))
|
||||
longoptions:
|
||||
if (!(optno = optlookup(*argv))) {
|
||||
zerr("no such option: %s", *argv, 0);
|
||||
else if (optno == RESTRICTED)
|
||||
exit(1);
|
||||
} else if (optno == RESTRICTED)
|
||||
restricted = action;
|
||||
else
|
||||
dosetopt(optno, action, 1);
|
||||
|
@ -240,6 +280,7 @@ parseargs(char **argv)
|
|||
/* zsh's typtab not yet set, have to use ctype */
|
||||
while (*++*argv)
|
||||
if (!isspace(STOUC(**argv))) {
|
||||
badoptionstring:
|
||||
zerr("bad option string: `%s'", args, 0);
|
||||
exit(1);
|
||||
}
|
||||
|
@ -284,19 +325,37 @@ parseargs(char **argv)
|
|||
if(isset(SINGLECOMMAND))
|
||||
opts[INTERACTIVE] &= 1;
|
||||
opts[INTERACTIVE] = !!opts[INTERACTIVE];
|
||||
pparams = x = (char **) zcalloc((countlinknodes(paramlist) + 1) * sizeof(char *));
|
||||
pparams = x = (char **) zshcalloc((countlinknodes(paramlist) + 1) * sizeof(char *));
|
||||
|
||||
while ((*x++ = (char *)getlinknode(paramlist)));
|
||||
free(paramlist);
|
||||
argzero = ztrdup(argzero);
|
||||
}
|
||||
|
||||
/**/
|
||||
static void
|
||||
printhelp(void)
|
||||
{
|
||||
printf("Usage: %s [<options>] [<argument> ...]\n", argzero);
|
||||
printf("\nSpecial options:\n");
|
||||
printf(" --help show this message, then exit\n");
|
||||
printf(" --version show zsh version number, then exit\n");
|
||||
if(unset(SHOPTIONLETTERS))
|
||||
printf(" -b end option processing, like --\n");
|
||||
printf(" -c take first argument as a command to execute\n");
|
||||
printf(" -o OPTION set an option by name (see below)\n");
|
||||
printf("\nNormal options are named. An option may be turned on by\n");
|
||||
printf("`-o OPTION', `--OPTION', `+o no_OPTION' or `+-no-OPTION'. An\n");
|
||||
printf("option may be turned off by `-o no_OPTION', `--no-OPTION',\n");
|
||||
printf("`+o OPTION' or `+-OPTION'. Options are listed below only in\n");
|
||||
printf("`--OPTION' or `--no-OPTION' form.\n");
|
||||
printoptionlist();
|
||||
}
|
||||
|
||||
/**/
|
||||
mod_export void
|
||||
init_io(void)
|
||||
{
|
||||
long ttpgrp;
|
||||
static char outbuf[BUFSIZ], errbuf[BUFSIZ];
|
||||
|
||||
#ifdef RSH_BUG_WORKAROUND
|
||||
|
@ -322,7 +381,13 @@ init_io(void)
|
|||
#endif
|
||||
|
||||
if (shout) {
|
||||
fclose(shout);
|
||||
/*
|
||||
* Check if shout was set to stderr, if so don't close it.
|
||||
* We do this if we are interactive but don't have a
|
||||
* terminal.
|
||||
*/
|
||||
if (shout != stderr)
|
||||
fclose(shout);
|
||||
shout = 0;
|
||||
}
|
||||
if (SHTTY != -1) {
|
||||
|
@ -391,29 +456,21 @@ init_io(void)
|
|||
|
||||
/* We will only use zle if shell is interactive, *
|
||||
* SHTTY != -1, and shout != 0 */
|
||||
if (interact && SHTTY != -1) {
|
||||
if (interact) {
|
||||
init_shout();
|
||||
if(!shout)
|
||||
if(!SHTTY || !shout)
|
||||
opts[USEZLE] = 0;
|
||||
} else
|
||||
opts[USEZLE] = 0;
|
||||
|
||||
#ifdef JOB_CONTROL
|
||||
/* If interactive, make the shell the foreground process */
|
||||
/* If interactive, make sure the shell is in the foreground and is the
|
||||
* process group leader.
|
||||
*/
|
||||
mypid = (zlong)getpid();
|
||||
if (opts[MONITOR] && interact && (SHTTY != -1)) {
|
||||
if ((mypgrp = GETPGRP()) > 0) {
|
||||
while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) {
|
||||
sleep(1); /* give parent time to change pgrp */
|
||||
mypgrp = GETPGRP();
|
||||
if (mypgrp == mypid)
|
||||
attachtty(mypgrp);
|
||||
if (mypgrp == gettygrp())
|
||||
break;
|
||||
killpg(mypgrp, SIGTTIN);
|
||||
mypgrp = GETPGRP();
|
||||
}
|
||||
} else
|
||||
opts[MONITOR] = 0;
|
||||
origpgrp = GETPGRP();
|
||||
acquire_pgrp(); /* might also clear opts[MONITOR] */
|
||||
} else
|
||||
opts[MONITOR] = 0;
|
||||
#else
|
||||
|
@ -427,8 +484,18 @@ init_shout(void)
|
|||
{
|
||||
static char shoutbuf[BUFSIZ];
|
||||
#if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC)
|
||||
int ldisc = NTTYDISC;
|
||||
int ldisc;
|
||||
#endif
|
||||
|
||||
if (SHTTY == -1)
|
||||
{
|
||||
/* Since we're interative, it's nice to have somewhere to write. */
|
||||
shout = stderr;
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC)
|
||||
ldisc = NTTYDISC;
|
||||
ioctl(SHTTY, TIOCSETD, (char *)&ldisc);
|
||||
#endif
|
||||
|
||||
|
@ -450,7 +517,8 @@ init_shout(void)
|
|||
static char *tccapnams[TC_COUNT] = {
|
||||
"cl", "le", "LE", "nd", "RI", "up", "UP", "do",
|
||||
"DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta",
|
||||
"md", "so", "us", "me", "se", "ue", "ch"
|
||||
"md", "so", "us", "me", "se", "ue", "ch",
|
||||
"ku", "kd", "kl", "kr"
|
||||
};
|
||||
|
||||
/* Initialise termcap */
|
||||
|
@ -474,13 +542,13 @@ init_term(void)
|
|||
|
||||
#ifdef TGETENT_ACCEPTS_NULL
|
||||
/* If possible, we let tgetent allocate its own termcap buffer */
|
||||
if (tgetent(NULL, term) != 1) {
|
||||
if (tgetent(NULL, term) != TGETENT_SUCCESS)
|
||||
#else
|
||||
if (tgetent(termbuf, term) != 1) {
|
||||
if (tgetent(termbuf, term) != TGETENT_SUCCESS)
|
||||
#endif
|
||||
|
||||
{
|
||||
if (isset(INTERACTIVE))
|
||||
zerr("can't find termcap info for %s", term, 0);
|
||||
zerr("can't find terminal definition for %s", term, 0);
|
||||
errflag = 0;
|
||||
termflags |= TERM_BAD;
|
||||
return 0;
|
||||
|
@ -552,14 +620,11 @@ setupvals(void)
|
|||
#endif
|
||||
struct timezone dummy_tz;
|
||||
char *ptr;
|
||||
#ifdef HAVE_GETRLIMIT
|
||||
int i;
|
||||
#endif
|
||||
int i, j;
|
||||
#if defined(SITEFPATH_DIR) || defined(FPATH_DIR)
|
||||
char **fpathptr;
|
||||
# if defined(FPATH_DIR) && defined(FPATH_SUBDIRS)
|
||||
char *fpath_subdirs[] = FPATH_SUBDIRS;
|
||||
int j;
|
||||
# endif
|
||||
# ifdef SITEFPATH_DIR
|
||||
int fpathlen = 1;
|
||||
|
@ -567,6 +632,47 @@ setupvals(void)
|
|||
int fpathlen = 0;
|
||||
# endif
|
||||
#endif
|
||||
int close_fds[10], tmppipe[2];
|
||||
|
||||
/*
|
||||
* Workaround a problem with NIS (in one guise or another) which
|
||||
* grabs file descriptors and keeps them for future reference.
|
||||
* We don't want these to be in the range where the user can
|
||||
* open fd's, i.e. 0 to 9 inclusive. So we make sure all
|
||||
* fd's in that range are in use.
|
||||
*/
|
||||
memset(close_fds, 0, 10*sizeof(int));
|
||||
if (pipe(tmppipe) == 0) {
|
||||
/*
|
||||
* Strategy: Make sure we have at least fd 0 open (hence
|
||||
* the pipe). From then on, keep dup'ing until we are
|
||||
* up to 9. If we go over the top, close immediately, else
|
||||
* mark for later closure.
|
||||
*/
|
||||
i = -1; /* max fd we have checked */
|
||||
while (i < 9) {
|
||||
/* j is current fd */
|
||||
if (i < tmppipe[0])
|
||||
j = tmppipe[0];
|
||||
else if (i < tmppipe[1])
|
||||
j = tmppipe[1];
|
||||
else {
|
||||
j = dup(0);
|
||||
if (j == -1)
|
||||
break;
|
||||
}
|
||||
if (j < 10)
|
||||
close_fds[j] = 1;
|
||||
else
|
||||
close(j);
|
||||
if (i < j)
|
||||
i = j;
|
||||
}
|
||||
if (i < tmppipe[0])
|
||||
close(tmppipe[0]);
|
||||
if (i < tmppipe[1])
|
||||
close(tmppipe[1]);
|
||||
}
|
||||
|
||||
addhookdefs(argzero, zshhooks, sizeof(zshhooks)/sizeof(*zshhooks));
|
||||
|
||||
|
@ -594,9 +700,6 @@ setupvals(void)
|
|||
gettimeofday(&shtimer, &dummy_tz); /* init $SECONDS */
|
||||
srand((unsigned int)(shtimer.tv_sec + shtimer.tv_usec)); /* seed $RANDOM */
|
||||
|
||||
hostnam = (char *) zalloc(256);
|
||||
gethostname(hostnam, 256);
|
||||
|
||||
/* Set default path */
|
||||
path = (char **) zalloc(sizeof(*path) * 5);
|
||||
path[0] = ztrdup("/bin");
|
||||
|
@ -695,7 +798,8 @@ setupvals(void)
|
|||
* initialize `PWD' from `HOME' */
|
||||
if (ispwd(home))
|
||||
pwd = ztrdup(home);
|
||||
else if ((ptr = zgetenv("PWD")) && ispwd(ptr))
|
||||
else if ((ptr = zgetenv("PWD")) && (strlen(ptr) < PATH_MAX) &&
|
||||
(ptr = metafy(ptr, -1, META_STATIC), ispwd(ptr)))
|
||||
pwd = ztrdup(ptr);
|
||||
else
|
||||
pwd = metafy(zgetcwd(), -1, META_DUP);
|
||||
|
@ -706,12 +810,12 @@ setupvals(void)
|
|||
initlextabs(); /* initialize lexing tables */
|
||||
|
||||
createreswdtable(); /* create hash table for reserved words */
|
||||
createaliastable(); /* create hash table for aliases */
|
||||
createaliastables(); /* create hash tables for aliases */
|
||||
createcmdnamtable(); /* create hash table for external commands */
|
||||
createshfunctable(); /* create hash table for shell functions */
|
||||
createbuiltintable(); /* create hash table for builtin commands */
|
||||
createnameddirtable(); /* create hash table for named directories */
|
||||
createparamtable(); /* create paramater hash table */
|
||||
createparamtable(); /* create parameter hash table */
|
||||
|
||||
condtab = NULL;
|
||||
wrappers = NULL;
|
||||
|
@ -754,7 +858,12 @@ setupvals(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
times(&shtms);
|
||||
get_usage();
|
||||
|
||||
/* Close the file descriptors we opened to block off 0 to 9 */
|
||||
for (i = 0; i < 10; i++)
|
||||
if (close_fds[i])
|
||||
close(i);
|
||||
}
|
||||
|
||||
/* Initialize signal handling */
|
||||
|
@ -763,6 +872,12 @@ setupvals(void)
|
|||
void
|
||||
init_signals(void)
|
||||
{
|
||||
if (interact) {
|
||||
int i;
|
||||
signal_setmask(signal_mask(0));
|
||||
for (i=0; i<NSIG; ++i)
|
||||
signal_default(i);
|
||||
}
|
||||
sigchld_mask = signal_mask(SIGCHLD);
|
||||
|
||||
intr();
|
||||
|
@ -771,7 +886,10 @@ init_signals(void)
|
|||
signal_ignore(SIGQUIT);
|
||||
#endif
|
||||
|
||||
install_handler(SIGHUP);
|
||||
if (signal_ignore(SIGHUP) == SIG_IGN)
|
||||
opts[HUP] = 0;
|
||||
else
|
||||
install_handler(SIGHUP);
|
||||
install_handler(SIGCHLD);
|
||||
#ifdef SIGWINCH
|
||||
install_handler(SIGWINCH);
|
||||
|
@ -781,28 +899,9 @@ init_signals(void)
|
|||
signal_ignore(SIGTERM);
|
||||
}
|
||||
if (jobbing) {
|
||||
long ttypgrp;
|
||||
|
||||
while ((ttypgrp = gettygrp()) != -1 && ttypgrp != mypgrp)
|
||||
kill(0, SIGTTIN);
|
||||
if (ttypgrp == -1) {
|
||||
opts[MONITOR] = 0;
|
||||
} else {
|
||||
signal_ignore(SIGTTOU);
|
||||
signal_ignore(SIGTSTP);
|
||||
signal_ignore(SIGTTIN);
|
||||
attachtty(mypgrp);
|
||||
}
|
||||
}
|
||||
if (islogin) {
|
||||
signal_setmask(signal_mask(0));
|
||||
} else if (interact) {
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGINT);
|
||||
sigaddset(&set, SIGQUIT);
|
||||
signal_unblock(set);
|
||||
signal_ignore(SIGTTOU);
|
||||
signal_ignore(SIGTSTP);
|
||||
signal_ignore(SIGTTIN);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -904,7 +1003,7 @@ source(char *s)
|
|||
int oldshst, osubsh, oloops;
|
||||
FILE *obshin;
|
||||
char *old_scriptname = scriptname, *us;
|
||||
char *ocs;
|
||||
unsigned char *ocs;
|
||||
int ocsp;
|
||||
|
||||
if (!s ||
|
||||
|
@ -943,7 +1042,7 @@ source(char *s)
|
|||
execode(prog, 1, 0);
|
||||
popheap();
|
||||
} else
|
||||
loop(0, 0); /* loop through the file to be sourced */
|
||||
loop(0, 0); /* loop through the file to be sourced */
|
||||
sourcelevel--;
|
||||
|
||||
/* restore the current shell state */
|
||||
|
@ -976,18 +1075,20 @@ source(char *s)
|
|||
void
|
||||
sourcehome(char *s)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
char *h;
|
||||
|
||||
queue_signals();
|
||||
if (emulation == EMULATE_SH || emulation == EMULATE_KSH ||
|
||||
!(h = getsparam("ZDOTDIR")))
|
||||
h = home;
|
||||
if (strlen(h) + strlen(s) + 1 >= PATH_MAX) {
|
||||
zerr("path too long: %s", s, 0);
|
||||
return;
|
||||
|
||||
{
|
||||
/* Let source() complain if path is too long */
|
||||
VARARR(char, buf, strlen(h) + strlen(s) + 2);
|
||||
sprintf(buf, "%s/%s", h, s);
|
||||
unqueue_signals();
|
||||
source(buf);
|
||||
}
|
||||
sprintf(buf, "%s/%s", h, s);
|
||||
source(buf);
|
||||
}
|
||||
|
||||
/**/
|
||||
|
@ -1009,7 +1110,7 @@ noop_function(void)
|
|||
|
||||
/**/
|
||||
mod_export void
|
||||
noop_function_int(int nothing)
|
||||
noop_function_int(UNUSED(int nothing))
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
@ -1024,51 +1125,63 @@ noop_function_int(int nothing)
|
|||
/**/
|
||||
mod_export ZleVoidFn trashzleptr = noop_function;
|
||||
/**/
|
||||
mod_export ZleVoidFn gotwordptr = noop_function;
|
||||
/**/
|
||||
mod_export ZleVoidFn refreshptr = noop_function;
|
||||
/**/
|
||||
mod_export ZleVoidIntFn spaceinlineptr = noop_function_int;
|
||||
/**/
|
||||
mod_export ZleReadFn zlereadptr = autoload_zleread;
|
||||
/**/
|
||||
mod_export ZleVoidIntFn zlesetkeymapptr = noop_function_int;
|
||||
|
||||
#else /* !LINKED_XMOD_zshQszle */
|
||||
|
||||
mod_export ZleVoidFn trashzleptr = noop_function;
|
||||
mod_export ZleVoidFn gotwordptr = noop_function;
|
||||
mod_export ZleVoidFn refreshptr = noop_function;
|
||||
mod_export ZleVoidIntFn spaceinlineptr = noop_function_int;
|
||||
# ifdef UNLINKED_XMOD_zshQszle
|
||||
mod_export ZleReadFn zlereadptr = autoload_zleread;
|
||||
mod_export ZleVoidIntFn zlesetkeymapptr = autoload_zlesetkeymap;
|
||||
# else /* !UNLINKED_XMOD_zshQszle */
|
||||
mod_export ZleReadFn zlereadptr = fallback_zleread;
|
||||
mod_export ZleVoidIntFn zlesetkeymapptr = noop_function_int;
|
||||
# endif /* !UNLINKED_XMOD_zshQszle */
|
||||
|
||||
#endif /* !LINKED_XMOD_zshQszle */
|
||||
|
||||
/**/
|
||||
unsigned char *
|
||||
autoload_zleread(char *lp, char *rp, int ha)
|
||||
autoload_zleread(char **lp, char **rp, int ha, int con)
|
||||
{
|
||||
zlereadptr = fallback_zleread;
|
||||
if (load_module("zsh/zle"))
|
||||
load_module("zsh/compctl");
|
||||
return zleread(lp, rp, ha);
|
||||
return zleread(lp, rp, ha, con);
|
||||
}
|
||||
|
||||
/**/
|
||||
mod_export unsigned char *
|
||||
fallback_zleread(char *lp, char *rp, int ha)
|
||||
fallback_zleread(char **lp, UNUSED(char **rp), UNUSED(int ha), UNUSED(int con))
|
||||
{
|
||||
char *pptbuf;
|
||||
int pptlen;
|
||||
|
||||
pptbuf = unmetafy(promptexpand(lp, 0, NULL, NULL), &pptlen);
|
||||
pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL), &pptlen);
|
||||
write(2, (WRITE_ARG_2_T)pptbuf, pptlen);
|
||||
free(pptbuf);
|
||||
|
||||
return (unsigned char *)shingetline();
|
||||
}
|
||||
|
||||
/**/
|
||||
static void
|
||||
autoload_zlesetkeymap(int mode)
|
||||
{
|
||||
zlesetkeymapptr = noop_function_int;
|
||||
load_module("zsh/zle");
|
||||
(*zlesetkeymapptr)(mode);
|
||||
}
|
||||
|
||||
|
||||
/* compctl entry point pointers. Similar to the ZLE ones. */
|
||||
|
||||
/**/
|
||||
|
@ -1076,9 +1189,113 @@ mod_export CompctlReadFn compctlreadptr = fallback_compctlread;
|
|||
|
||||
/**/
|
||||
mod_export int
|
||||
fallback_compctlread(char *name, char **args, char *ops, char *reply)
|
||||
fallback_compctlread(char *name, UNUSED(char **args), UNUSED(Options ops), UNUSED(char *reply))
|
||||
{
|
||||
zwarnnam(name, "option valid only in functions called from completion",
|
||||
NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is real main entry point. This has to be mod_export'ed
|
||||
* so zsh.exe can found it on Cygwin
|
||||
*/
|
||||
|
||||
/**/
|
||||
mod_export int
|
||||
zsh_main(UNUSED(int argc), char **argv)
|
||||
{
|
||||
char **t;
|
||||
int t0;
|
||||
#ifdef USE_LOCALE
|
||||
setlocale(LC_ALL, "");
|
||||
#endif
|
||||
|
||||
init_jobs(argv, environ);
|
||||
|
||||
/*
|
||||
* Provisionally set up the type table to allow metafication.
|
||||
* This will be done properly when we have decided if we are
|
||||
* interactive
|
||||
*/
|
||||
typtab['\0'] |= IMETA;
|
||||
typtab[STOUC(Meta) ] |= IMETA;
|
||||
typtab[STOUC(Marker)] |= IMETA;
|
||||
for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(Nularg); t0++)
|
||||
typtab[t0] |= ITOK | IMETA;
|
||||
|
||||
for (t = argv; *t; *t = metafy(*t, -1, META_ALLOC), t++);
|
||||
|
||||
zsh_name = argv[0];
|
||||
do {
|
||||
char *arg0 = zsh_name;
|
||||
if (!(zsh_name = strrchr(arg0, '/')))
|
||||
zsh_name = arg0;
|
||||
else
|
||||
zsh_name++;
|
||||
if (*zsh_name == '-')
|
||||
zsh_name++;
|
||||
if (strcmp(zsh_name, "su") == 0) {
|
||||
char *sh = zgetenv("SHELL");
|
||||
if (sh && *sh && arg0 != sh)
|
||||
zsh_name = sh;
|
||||
else
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
} while (zsh_name);
|
||||
|
||||
fdtable_size = zopenmax();
|
||||
fdtable = zshcalloc(fdtable_size);
|
||||
|
||||
createoptiontable();
|
||||
emulate(zsh_name, 1); /* initialises most options */
|
||||
opts[LOGINSHELL] = (**argv == '-');
|
||||
opts[MONITOR] = 1; /* may be unset in init_io() */
|
||||
opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid());
|
||||
opts[USEZLE] = 1; /* may be unset in init_io() */
|
||||
parseargs(argv); /* sets INTERACTIVE, SHINSTDIN and SINGLECOMMAND */
|
||||
|
||||
SHTTY = -1;
|
||||
init_io();
|
||||
setupvals();
|
||||
init_signals();
|
||||
init_bltinmods();
|
||||
run_init_scripts();
|
||||
init_misc();
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* See if we can free up some of jobtab.
|
||||
* We only do this at top level, because if we are
|
||||
* executing stuff we may refer to them by job pointer.
|
||||
*/
|
||||
maybeshrinkjobtab();
|
||||
|
||||
do
|
||||
loop(1,0);
|
||||
while (tok != ENDINPUT && (tok != LEXERR || isset(SHINSTDIN)));
|
||||
if (tok == LEXERR) {
|
||||
/* Make sure a parse error exits with non-zero status */
|
||||
if (!lastval)
|
||||
lastval = 1;
|
||||
stopmsg = 1;
|
||||
zexit(lastval, 0);
|
||||
}
|
||||
if (!(isset(IGNOREEOF) && interact)) {
|
||||
#if 0
|
||||
if (interact)
|
||||
fputs(islogin ? "logout\n" : "exit\n", shout);
|
||||
#endif
|
||||
zexit(lastval, 0);
|
||||
continue;
|
||||
}
|
||||
noexitct++;
|
||||
if (noexitct >= 10) {
|
||||
stopmsg = 1;
|
||||
zexit(lastval, 0);
|
||||
}
|
||||
zerrnam("zsh", (!islogin) ? "use 'exit' to exit."
|
||||
: "use 'logout' to logout.", NULL, 0);
|
||||
}
|
||||
}
|
||||
|
|
450
Test/A01grammar.ztst
Normal file
450
Test/A01grammar.ztst
Normal file
|
@ -0,0 +1,450 @@
|
|||
#
|
||||
# This file contains tests corresponding to the `Shell Grammar' texinfo node.
|
||||
#
|
||||
|
||||
%prep
|
||||
|
||||
mkdir basic.tmp && cd basic.tmp
|
||||
|
||||
touch foo bar
|
||||
echo "'" >unmatched_quote.txt
|
||||
|
||||
%test
|
||||
#
|
||||
# Tests for `Simple Commands and Pipelines'
|
||||
#
|
||||
echo foo | cat | sed 's/foo/bar/'
|
||||
0:Basic pipeline handling
|
||||
>bar
|
||||
|
||||
false | true
|
||||
0:Exit status of pipeline with builtins (true)
|
||||
|
||||
true | false
|
||||
1:Exit status of pipeline with builtins (false)
|
||||
|
||||
fn() { local foo; read foo; print $foo; }
|
||||
coproc fn
|
||||
print -p coproc test output
|
||||
read -p bar
|
||||
print $bar
|
||||
0:Basic coprocess handling
|
||||
>coproc test output
|
||||
|
||||
true | false && print true || print false
|
||||
0:Basic sublist (i)
|
||||
>false
|
||||
|
||||
false | true && print true || print false
|
||||
0:Basic sublist (ii)
|
||||
>true
|
||||
|
||||
(cd /NonExistentDirectory >&/dev/null) || print false
|
||||
0:Basic subshell list with error
|
||||
>false
|
||||
|
||||
{ cd /NonExistentDirectory >&/dev/null } || print false
|
||||
0:Basic current shell list with error
|
||||
>false
|
||||
|
||||
#
|
||||
# Tests for `Precommand Modifiers'
|
||||
#
|
||||
- $ZTST_testdir/../Src/zsh -fc "[[ \$0 = \"-$ZTST_testdir/../Src/zsh\" ]]"
|
||||
0:`-' precommand modifier
|
||||
|
||||
echo f*
|
||||
noglob echo f*
|
||||
0:`noglob' precommand modifier
|
||||
>foo
|
||||
>f*
|
||||
|
||||
(exec /bin/sh; echo bar)
|
||||
0:`exec' precommand modifier
|
||||
|
||||
cat() { echo Function cat executed; }
|
||||
command cat && unfunction cat
|
||||
0:`command' precommand modifier
|
||||
<External command cat executed
|
||||
>External command cat executed
|
||||
|
||||
cd() { echo Not cd at all; }
|
||||
builtin cd . && unfunction cd
|
||||
0:`builtin' precommand modifier
|
||||
|
||||
#
|
||||
# Tests for `Complex Commands'
|
||||
#
|
||||
|
||||
if true; then
|
||||
print true-1
|
||||
elif true; then
|
||||
print true-2
|
||||
else
|
||||
print false
|
||||
fi
|
||||
0:`if ...' (i)
|
||||
>true-1
|
||||
|
||||
if false; then
|
||||
print true-1
|
||||
elif true; then
|
||||
print true-2
|
||||
else
|
||||
print false
|
||||
fi
|
||||
0:`if ...' (ii)
|
||||
>true-2
|
||||
|
||||
if false; then
|
||||
print true-1
|
||||
elif false; then
|
||||
print true-2
|
||||
else
|
||||
print false
|
||||
fi
|
||||
0:`if ...' (iii)
|
||||
>false
|
||||
|
||||
if true;
|
||||
:
|
||||
fi
|
||||
1d:`if ...' (iv)
|
||||
?(eval):3: parse error near `fi'
|
||||
|
||||
for name in word to term; do
|
||||
print $name
|
||||
done
|
||||
0:`for' loop
|
||||
>word
|
||||
>to
|
||||
>term
|
||||
|
||||
for name
|
||||
in word to term; do
|
||||
print $name
|
||||
done
|
||||
0:`for' loop with newline before in keyword
|
||||
>word
|
||||
>to
|
||||
>term
|
||||
|
||||
for (( name = 0; name < 3; name++ )); do
|
||||
print $name
|
||||
done
|
||||
0:arithmetic `for' loop
|
||||
>0
|
||||
>1
|
||||
>2
|
||||
|
||||
for keyvar valvar in key1 val1 key2 val2; do
|
||||
print key=$keyvar val=$valvar
|
||||
done
|
||||
0:enhanced `for' syntax with two loop variables
|
||||
>key=key1 val=val1
|
||||
>key=key2 val=val2
|
||||
|
||||
for keyvar valvar stuffvar in keyA valA stuffA keyB valB stuffB; do
|
||||
print key=$keyvar val=$valvar stuff=$stuffvar
|
||||
done
|
||||
0:enhanced `for' syntax with three loop variables
|
||||
>key=keyA val=valA stuff=stuffA
|
||||
>key=keyB val=valB stuff=stuffB
|
||||
|
||||
for in in in in in stop; do
|
||||
print in=$in
|
||||
done
|
||||
0:compatibility of enhanced `for' syntax with standard syntax
|
||||
>in=in
|
||||
>in=in
|
||||
>in=in
|
||||
>in=stop
|
||||
|
||||
name=0
|
||||
while (( name < 3 )); do
|
||||
print $name
|
||||
(( name++ ))
|
||||
done
|
||||
0:`while' loop
|
||||
>0
|
||||
>1
|
||||
>2
|
||||
|
||||
name=0
|
||||
until (( name == 3 )); do
|
||||
print $name
|
||||
(( name++ ))
|
||||
done
|
||||
0:`until' loop
|
||||
>0
|
||||
>1
|
||||
>2
|
||||
|
||||
repeat 3 do
|
||||
echo over and over
|
||||
done
|
||||
0:`repeat' loop
|
||||
>over and over
|
||||
>over and over
|
||||
>over and over
|
||||
|
||||
word=Trinity
|
||||
case $word in
|
||||
Michaelmas) print 0
|
||||
;;
|
||||
Hilary) print 1
|
||||
;;
|
||||
Trinity) print 2
|
||||
;;
|
||||
*) print 3
|
||||
;;
|
||||
esac
|
||||
0:`case', old syntax
|
||||
>2
|
||||
|
||||
word=Trinity
|
||||
case $word in
|
||||
(Michaelmas) print 0
|
||||
;;
|
||||
(Hilary) print 1
|
||||
;;
|
||||
(Trinity) print 2
|
||||
;;
|
||||
(*) print 3
|
||||
;;
|
||||
esac
|
||||
0:`case', new syntax
|
||||
>2
|
||||
|
||||
word=Hilary
|
||||
case $word in
|
||||
(Michaelmas) print 0
|
||||
;;
|
||||
(Hilary) print 1
|
||||
;&
|
||||
(Trinity) print 2
|
||||
;&
|
||||
(*) print 3
|
||||
;;
|
||||
esac
|
||||
0:`case', new syntax, cascaded
|
||||
>1
|
||||
>2
|
||||
>3
|
||||
|
||||
## Select now reads from stdin if the shell is not interactive.
|
||||
## Its own output goes to stderr.
|
||||
(COLUMNS=80
|
||||
PS3="input> "
|
||||
select name in one two three; do
|
||||
print $name
|
||||
done)
|
||||
0:`select' loop
|
||||
<2
|
||||
?1) one 2) two 3) three
|
||||
?input> input>
|
||||
>two
|
||||
|
||||
function name1 name2 () { print This is $0; }
|
||||
name2
|
||||
name1 name2() { print This is still $0; }
|
||||
name2
|
||||
0:`function' keyword
|
||||
>This is name2
|
||||
>This is still name2
|
||||
|
||||
(time cat) >&/dev/null
|
||||
0:`time' keyword (status only)
|
||||
|
||||
if [[ -f foo && -d . && -n $ZTST_testdir ]]; then
|
||||
true
|
||||
else
|
||||
false
|
||||
fi
|
||||
0:basic [[ ... ]] test
|
||||
|
||||
#
|
||||
# Current shell execution with try/always form.
|
||||
# We put those with errors in subshells so that any unhandled error doesn't
|
||||
# propagate.
|
||||
#
|
||||
|
||||
{
|
||||
print The try block.
|
||||
} always {
|
||||
print The always block.
|
||||
}
|
||||
print After the always block.
|
||||
0:Basic `always' syntax
|
||||
>The try block.
|
||||
>The always block.
|
||||
>After the always block.
|
||||
|
||||
({
|
||||
print Position one.
|
||||
print ${*this is an error*}
|
||||
print Position two.
|
||||
} always {
|
||||
if (( TRY_BLOCK_ERROR )); then
|
||||
print An error occurred.
|
||||
else
|
||||
print No error occurred.
|
||||
fi
|
||||
}
|
||||
print Position three)
|
||||
1:Always block with error not reset
|
||||
>Position one.
|
||||
>An error occurred.
|
||||
?(eval):3: bad substitution
|
||||
|
||||
({
|
||||
print Stelle eins.
|
||||
print ${*voici une erreur}
|
||||
print Posizione due.
|
||||
} always {
|
||||
if (( TRY_BLOCK_ERROR )); then
|
||||
print Erratum factum est. Retro ponetur.
|
||||
(( TRY_BLOCK_ERROR = 0 ))
|
||||
else
|
||||
print unray touay foay anguageslay
|
||||
fi
|
||||
}
|
||||
print Status after always block is $?.)
|
||||
0:Always block with error reset
|
||||
>Stelle eins.
|
||||
>Erratum factum est. Retro ponetur.
|
||||
>Status after always block is 1.
|
||||
?(eval):3: bad substitution
|
||||
|
||||
# Outputting of structures from the wordcode is distinctly non-trivial,
|
||||
# we probably ought to have more like the following...
|
||||
fn1() { { echo foo; } }
|
||||
fn2() { { echo foo; } always { echo bar; } }
|
||||
fn3() { ( echo foo; ) }
|
||||
functions fn1 fn2 fn3
|
||||
0:Output of syntactic structures with and without always blocks
|
||||
>fn1 () {
|
||||
> {
|
||||
> echo foo
|
||||
> }
|
||||
>}
|
||||
>fn2 () {
|
||||
> {
|
||||
> echo foo
|
||||
> } always {
|
||||
> echo bar
|
||||
> }
|
||||
>}
|
||||
>fn3 () {
|
||||
> (
|
||||
> echo foo
|
||||
> )
|
||||
>}
|
||||
|
||||
|
||||
#
|
||||
# Tests for `Alternate Forms For Complex Commands'
|
||||
#
|
||||
|
||||
if (true) { print true-1 } elif (true) { print true-2 } else { print false }
|
||||
if (false) { print true-1 } elif (true) { print true-2 } else { print false }
|
||||
if (false) { print true-1 } elif (false) { print true-2 } else { print false }
|
||||
0:Alternate `if' with braces
|
||||
>true-1
|
||||
>true-2
|
||||
>false
|
||||
|
||||
if true; print true
|
||||
0:Short form of `if'
|
||||
>true
|
||||
|
||||
for name ( word1 word2 word3 ) print $name
|
||||
0:Form of `for' with parentheses.
|
||||
>word1
|
||||
>word2
|
||||
>word3
|
||||
|
||||
for name in alpha beta gamma; print $name
|
||||
0:Short form of `for'
|
||||
>alpha
|
||||
>beta
|
||||
>gamma
|
||||
|
||||
for (( val = 2; val < 10; val *= val )) print $val
|
||||
0:Short arithmetic `for'
|
||||
>2
|
||||
>4
|
||||
|
||||
foreach name ( verbiage words periphrasis )
|
||||
print $name
|
||||
end
|
||||
0:Csh-like `for'
|
||||
>verbiage
|
||||
>words
|
||||
>periphrasis
|
||||
|
||||
# see comment with braces used in if loops
|
||||
val=0;
|
||||
while (( val < 2 )) { print $((val++)); }
|
||||
0:Alternative `while'
|
||||
>0
|
||||
>1
|
||||
|
||||
val=2;
|
||||
until (( val == 0 )) { print $((val--)); }
|
||||
0:Alternative `until'
|
||||
>2
|
||||
>1
|
||||
|
||||
repeat 3 print Hip hip hooray
|
||||
0:Short `repeat'
|
||||
>Hip hip hooray
|
||||
>Hip hip hooray
|
||||
>Hip hip hooray
|
||||
|
||||
case bravo {
|
||||
(alpha) print schmalpha
|
||||
;;
|
||||
(bravo) print schmavo
|
||||
;;
|
||||
(charlie) print schmarlie
|
||||
;;
|
||||
}
|
||||
0:`case' with braces
|
||||
>schmavo
|
||||
|
||||
print 'This test hangs the shell when it fails...' >&8
|
||||
name=0
|
||||
# The number 4375 here is chosen to produce more than 16384 bytes of output
|
||||
while (( name < 4375 )); do
|
||||
print -n $name
|
||||
(( name++ ))
|
||||
done < /dev/null | { read name; print done }
|
||||
0:Bug regression: `while' loop with redirection and pipeline
|
||||
>done
|
||||
|
||||
# This used to be buggy and print X at the end of each iteration.
|
||||
for f in 1 2 3 4; do
|
||||
print $f || break
|
||||
done && print X
|
||||
0:Handling of ||'s and &&'s with a for loop in between
|
||||
>1
|
||||
>2
|
||||
>3
|
||||
>4
|
||||
>X
|
||||
|
||||
# Same bug for &&, used to print `no' at the end of each iteration
|
||||
for f in 1 2 3 4; do
|
||||
false && print strange
|
||||
done || print no
|
||||
0:Handling of &&'s and ||'s with a for loop in between
|
||||
>no
|
||||
|
||||
$ZTST_testdir/../Src/zsh -f unmatched_quote.txt
|
||||
1:Parse error with file causes non-zero exit status
|
||||
?unmatched_quote.txt:2: unmatched '
|
||||
|
||||
$ZTST_testdir/../Src/zsh -f <unmatched_quote.txt
|
||||
1:Parse error on standard input causes non-zero exit status
|
||||
?zsh: unmatched '
|
Loading…
Reference in a new issue