1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-11-25 14:20:53 +01:00

21078: parse errors didn't cause non-zero exit status

This commit is contained in:
Peter Stephenson 2005-04-01 10:30:08 +00:00
parent 6f8b647733
commit e43b2acd67
3 changed files with 767 additions and 95 deletions

View file

@ -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);
}
}