summaryrefslogtreecommitdiff
path: root/Src/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/builtin.c')
-rw-r--r--Src/builtin.c136
1 files changed, 81 insertions, 55 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index aa5767cf1..8ef678b22 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -71,7 +71,7 @@ static struct builtin builtins[] =
* But that's actually not useful, so it's more consistent to
* cause an error.
*/
- BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W", NULL),
+ BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRst:W", NULL),
BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlp:%rtux", "E"),
BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "ckmMstTuUWx:z", NULL),
@@ -89,7 +89,6 @@ static struct builtin builtins[] =
BUILTIN("kill", BINF_HANDLES_OPTS, bin_kill, 0, -1, 0, NULL, NULL),
BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL),
BUILTIN("local", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%ahi:%lp:%rtux", NULL),
- BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL),
#if defined(ZSH_MEM) & defined(ZSH_MEM_DEBUG)
@@ -841,7 +840,6 @@ int
bin_cd(char *nam, char **argv, Options ops, int func)
{
LinkNode dir;
- struct stat st1, st2;
if (isset(RESTRICTED)) {
zwarnnam(nam, "restricted");
@@ -860,23 +858,6 @@ bin_cd(char *nam, char **argv, Options ops, int func)
}
cd_new_pwd(func, dir, OPT_ISSET(ops, 'q'));
- if (stat(unmeta(pwd), &st1) < 0) {
- setjobpwd();
- zsfree(pwd);
- pwd = NULL;
- pwd = metafy(zgetcwd(), -1, META_DUP);
- } else if (stat(".", &st2) < 0) {
- if (chdir(unmeta(pwd)) < 0)
- zwarn("unable to chdir(%s): %e", pwd, errno);
- } else if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) {
- if (chasinglinks) {
- setjobpwd();
- zsfree(pwd);
- pwd = NULL;
- pwd = metafy(zgetcwd(), -1, META_DUP);
- } else if (chdir(unmeta(pwd)) < 0)
- zwarn("unable to chdir(%s): %e", pwd, errno);
- }
unqueue_signals();
return 0;
}
@@ -1210,6 +1191,7 @@ static void
cd_new_pwd(int func, LinkNode dir, int quiet)
{
char *new_pwd, *s;
+ struct stat st1, st2;
int dirstacksize;
if (func == BIN_PUSHD)
@@ -1239,6 +1221,22 @@ cd_new_pwd(int func, LinkNode dir, int quiet)
}
}
+ if (stat(unmeta(new_pwd), &st1) < 0) {
+ zsfree(new_pwd);
+ new_pwd = NULL;
+ new_pwd = metafy(zgetcwd(), -1, META_DUP);
+ } else if (stat(".", &st2) < 0) {
+ if (chdir(unmeta(new_pwd)) < 0)
+ zwarn("unable to chdir(%s): %e", new_pwd, errno);
+ } else if (st1.st_ino != st2.st_ino || st1.st_dev != st2.st_dev) {
+ if (chasinglinks) {
+ zsfree(new_pwd);
+ new_pwd = NULL;
+ new_pwd = metafy(zgetcwd(), -1, META_DUP);
+ } else if (chdir(unmeta(new_pwd)) < 0)
+ zwarn("unable to chdir(%s): %e", new_pwd, errno);
+ }
+
/* shift around the pwd variables, to make oldpwd and pwd relate to the
current (i.e. new) pwd */
zsfree(oldpwd);
@@ -1600,8 +1598,9 @@ bin_fc(char *nam, char **argv, Options ops, int func)
* command line to avoid giving the user a nasty turn
* if some helpful soul ran "print -s 'rm -rf /'".
*/
- first = OPT_ISSET(ops,'l')? addhistnum(curhist,-16,0)
- : addhistnum(curline.histnum,-1,0);
+ int xflags = OPT_ISSET(ops,'L') ? HIST_FOREIGN : 0;
+ first = OPT_ISSET(ops,'l')? addhistnum(curhist,-16,xflags)
+ : addhistnum(curline.histnum,-1,xflags);
if (first < 1)
first = 1;
if (last < first)
@@ -1644,7 +1643,7 @@ bin_fc(char *nam, char **argv, Options ops, int func)
if (!fclist(out, ops, first, last, asgf, pprog, 1)) {
char *editor;
- if (func == BIN_R)
+ if (func == BIN_R || OPT_ISSET(ops, 's'))
editor = "-";
else if (OPT_HASARG(ops, 'e'))
editor = OPT_ARG(ops, 'e');
@@ -2024,7 +2023,7 @@ typeset_setwidth(const char * name, Param pm, Options ops, int on, int always)
/**/
static Param
-typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
+typeset_single(char *cname, char *pname, Param pm, int func,
int on, int off, int roff, Asgment asg, Param altpm,
Options ops, int joinchar)
{
@@ -2280,7 +2279,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
} else if (asg->flags & ASG_ARRAY) {
int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
if (!(pm = assignaparam(pname, asg->value.array ?
- zlinklist2array(asg->value.array) :
+ zlinklist2array(asg->value.array, 1) :
mkarray(NULL), flags)))
return NULL;
}
@@ -2442,7 +2441,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
} else if (PM_TYPE(on) == PM_ARRAY && ASG_ARRAYP(asg)) {
int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
if (!(pm = assignaparam(pname, asg->value.array ?
- zlinklist2array(asg->value.array) :
+ zlinklist2array(asg->value.array, 1) :
mkarray(NULL), flags)))
return NULL;
dont_set = 1;
@@ -2480,13 +2479,19 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
return NULL;
}
if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
- if (typeset_setwidth(cname, pm, ops, on, 0))
+ if (typeset_setwidth(cname, pm, ops, on, 0)) {
+ unsetparam_pm(pm, 0, 1);
return NULL;
+ }
}
if (on & (PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) {
- if (typeset_setbase(cname, pm, ops, on, 0))
+ if (typeset_setbase(cname, pm, ops, on, 0)) {
+ unsetparam_pm(pm, 0, 1);
return NULL;
+ }
}
+ if (isset(TYPESETTOUNSET))
+ pm->node.flags |= PM_DEFAULTED;
} else {
if (idigit(*pname))
zerrnam(cname, "not an identifier: %s", pname);
@@ -2503,8 +2508,10 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
*/
struct tieddata *tdp = (struct tieddata *)
zalloc(sizeof(struct tieddata));
- if (!tdp)
+ if (!tdp) {
+ unsetparam_pm(pm, 0, 1);
return NULL;
+ }
tdp->joinchar = joinchar;
tdp->arrptr = &altpm->u.arr;
@@ -2536,7 +2543,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
arrayval = mkarray(NULL);
}
} else if (asg->value.array)
- arrayval = zlinklist2array(asg->value.array);
+ arrayval = zlinklist2array(asg->value.array, 1);
else
arrayval = mkarray(NULL);
if (!(pm=assignaparam(pname, arrayval, flags)))
@@ -2597,7 +2604,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
*/
/**/
-int
+mod_export int
bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
{
Param pm;
@@ -2607,7 +2614,12 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
int on = 0, off = 0, roff, bit = PM_ARRAY;
int i;
int returnval = 0, printflags = 0;
- int hasargs;
+ int hasargs = *argv != NULL || (assigns && firstnode(assigns));
+
+ /* POSIXBUILTINS is set for bash/ksh and both ignore -p with args */
+ if ((func == BIN_READONLY || func == BIN_EXPORT) &&
+ isset(POSIXBUILTINS) && hasargs)
+ ops->ind['p'] = 0;
/* hash -f is really the builtin `functions' */
if (OPT_ISSET(ops,'f'))
@@ -2687,7 +2699,6 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
/* -p0 treated as -p for consistency */
}
}
- hasargs = *argv != NULL || (assigns && firstnode(assigns));
if (!hasargs) {
int exclude = 0;
if (!OPT_ISSET(ops,'p')) {
@@ -2830,7 +2841,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
unqueue_signals();
return 1;
} else if (pm) {
- if (!(pm->node.flags & PM_UNSET)
+ if ((!(pm->node.flags & PM_UNSET) || pm->node.flags & PM_DECLARED)
&& (locallevel == pm->level || !(on & PM_LOCAL))) {
if (pm->node.flags & PM_TIED) {
if (PM_TYPE(pm->node.flags) != PM_SCALAR) {
@@ -2883,6 +2894,8 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
*
* Don't attempt to set it yet, it's too early
* to be exported properly.
+ *
+ * This may create the array with PM_DEFAULTED.
*/
asg2.name = asg->name;
asg2.flags = 0;
@@ -2923,9 +2936,13 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
apm->ename = ztrdup(asg0.name);
if (asg->value.array) {
int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
- assignaparam(asg->name, zlinklist2array(asg->value.array), flags);
- } else if (oldval)
- assignsparam(asg0.name, oldval, 0);
+ assignaparam(asg->name, zlinklist2array(asg->value.array, 1), flags);
+ } else if (asg0.value.scalar || oldval) {
+ /* We have to undo what we did wrong with asg2 */
+ apm->node.flags &= ~PM_DEFAULTED;
+ if (oldval)
+ assignsparam(asg0.name, oldval, 0);
+ }
unqueue_signals();
return 0;
@@ -3706,14 +3723,12 @@ bin_unset(char *name, char **argv, Options ops, int func)
while ((s = *argv++)) {
char *ss = strchr(s, '['), *subscript = 0;
if (ss) {
- char *sse;
+ char *sse = ss + strlen(ss)-1;
*ss = 0;
- if ((sse = parse_subscript(ss+1, 1, ']'))) {
+ if (*sse == ']') {
*sse = 0;
subscript = dupstring(ss+1);
*sse = ']';
- remnulargs(subscript);
- untokenize(subscript);
}
}
if ((ss && !subscript) || !isident(s)) {
@@ -3901,7 +3916,7 @@ bin_whence(char *nam, char **argv, Options ops, int func)
}
unqueue_signals();
if (all) {
- allmatched = argv = zlinklist2array(matchednodes);
+ allmatched = argv = zlinklist2array(matchednodes, 1);
matchednodes = NULL;
popheap();
} else
@@ -4817,7 +4832,7 @@ bin_print(char *name, char **args, Options ops, int func)
{
fwrite(args[n], len[n], 1, fout);
l = widths[n];
- if (n < argc)
+ if (n < argc && ic < nc - 1)
for (; l < sc; l++)
fputc(' ', fout);
}
@@ -4857,7 +4872,7 @@ bin_print(char *name, char **args, Options ops, int func)
/* normal output */
if (!fmt) {
- if (OPT_ISSET(ops, 'z') || OPT_ISSET(ops, 'v') ||
+ if (OPT_ISSET(ops, 'z') ||
OPT_ISSET(ops, 's') || OPT_ISSET(ops, 'S')) {
/*
* We don't want the arguments unmetafied after all.
@@ -5550,6 +5565,11 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
/* check for legality */
if(opch == ':' || !(p = memchr(optstr, opch, lenoptstr))) {
p = "?";
+ /* Keep OPTIND correct if the user doesn't return after the error */
+ if (isset(POSIXBUILTINS)) {
+ optcind = 0;
+ zoptind++;
+ }
zsfree(zoptarg);
setsparam(var, ztrdup(p));
if(quiet) {
@@ -5566,6 +5586,11 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
if(p[1] == ':') {
if(optcind == lenstr) {
if(!args[zoptind]) {
+ /* Fix OPTIND as above */
+ if (isset(POSIXBUILTINS)) {
+ optcind = 0;
+ zoptind++;
+ }
zsfree(zoptarg);
if(quiet) {
setsparam(var, ztrdup(":"));
@@ -5607,13 +5632,16 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
*/
/**/
-mod_export int
-exit_pending;
+mod_export volatile int exit_pending;
/* Shell level at which we exit if exit_pending */
/**/
-mod_export int
-exit_level;
+mod_export volatile int exit_level;
+
+/* we have printed a 'you have stopped (running) jobs.' message */
+
+/**/
+mod_export volatile int stopmsg;
/* break, bye, continue, exit, logout, return -- most of these take *
* one numeric argument, and the other (logout) is related to return. *
@@ -5705,11 +5733,6 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
return 0;
}
-/* we have printed a 'you have stopped (running) jobs.' message */
-
-/**/
-mod_export int stopmsg;
-
/* check to see if user has jobs running/stopped */
/**/
@@ -5800,8 +5823,11 @@ zexit(int val, enum zexit_t from_where)
* a later value always overrides an earlier.
*/
exit_val = val;
- if (shell_exiting == -1)
+ if (shell_exiting == -1) {
+ retflag = 1;
+ breaks = loops;
return;
+ }
if (isset(MONITOR) && !stopmsg && from_where != ZEXIT_SIGNAL) {
scanjobs(); /* check if jobs need printing */
@@ -6119,7 +6145,7 @@ bin_emulate(char *nam, char **argv, Options ops, UNUSED(int func))
savehackchar = keyboardhackchar;
emulate(shname, opt_R, &new_emulation, new_opts);
optlist = newlinklist();
- if (parseopts(nam, &argv, new_opts, &cmd, optlist, 0)) {
+ if (parseopts(nam, &argv, new_opts, &cmd, optlist, 0, NULL)) {
ret = 1;
goto restore;
}