summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/clone.c3
-rw-r--r--Src/Modules/datetime.c64
-rw-r--r--Src/Modules/db_gdbm.c2
-rw-r--r--Src/Modules/nearcolor.c210
-rw-r--r--Src/Modules/nearcolor.mdd5
-rw-r--r--Src/Modules/parameter.c44
-rw-r--r--Src/Modules/stat.c4
-rw-r--r--Src/Zle/compcore.c4
-rw-r--r--Src/Zle/complist.c9
-rw-r--r--Src/Zle/computil.c4
-rw-r--r--Src/Zle/zle.h4
-rw-r--r--Src/Zle/zle_refresh.c31
-rw-r--r--Src/Zle/zle_tricky.c9
-rw-r--r--Src/builtin.c207
-rw-r--r--Src/exec.c70
-rw-r--r--Src/hashtable.h1
-rw-r--r--Src/init.c9
-rw-r--r--Src/input.c2
-rw-r--r--Src/jobs.c131
-rw-r--r--Src/lex.c9
-rw-r--r--Src/module.c2
-rw-r--r--Src/params.c165
-rw-r--r--Src/prompt.c137
-rw-r--r--Src/signals.c27
-rw-r--r--Src/subst.c6
-rw-r--r--Src/utils.c28
-rw-r--r--Src/zsh.h82
-rw-r--r--Src/zsh_system.h4
28 files changed, 940 insertions, 333 deletions
diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c
index ef6275dcf..4b2655505 100644
--- a/Src/Modules/clone.c
+++ b/Src/Modules/clone.c
@@ -96,7 +96,8 @@ bin_clone(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
init_io(NULL);
setsparam("TTY", ztrdup(ttystrname));
}
- close(ttyfd);
+ else
+ close(ttyfd);
if (pid < 0) {
zerrnam(nam, "fork failed: %e", errno);
return 1;
diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c
index be378b347..18c7fb58e 100644
--- a/Src/Modules/datetime.c
+++ b/Src/Modules/datetime.c
@@ -100,8 +100,8 @@ output_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
{
int bufsize, x, len;
char *endptr = NULL, *scalar = NULL, *buffer;
- time_t secs;
- struct tm *t;
+ struct tm *tm;
+ struct timespec ts;
if (OPT_ISSET(ops,'s')) {
scalar = OPT_ARG(ops, 's');
@@ -110,30 +110,58 @@ output_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
return 1;
}
}
- if (OPT_ISSET(ops, 'r'))
+ if (OPT_ISSET(ops, 'r')) {
+ if (!argv[1]) {
+ zwarnnam(nam, "timestring expected");
+ return 1;
+ }
return reverse_strftime(nam, argv, scalar, OPT_ISSET(ops, 'q'));
-
- errno = 0;
- secs = (time_t)strtoul(argv[1], &endptr, 10);
- if (errno != 0) {
- zwarnnam(nam, "%s: %e", argv[1], errno);
- return 1;
- } else if (*endptr != '\0') {
- zwarnnam(nam, "%s: invalid decimal number", argv[1]);
- return 1;
}
- t = localtime(&secs);
- if (!t) {
- zwarnnam(nam, "%s: unable to convert to time", argv[1]);
- return 1;
+ if (!argv[1]) {
+ zgettime(&ts);
+ tm = localtime(&ts.tv_sec);
+ } else {
+ errno = 0;
+
+ ts.tv_sec = (time_t)strtoul(argv[1], &endptr, 10);
+ if (errno != 0) {
+ zwarnnam(nam, "%s: %e", argv[1], errno);
+ return 1;
+ } else if (*argv[1] == '\0' || *endptr != '\0') {
+ zwarnnam(nam, "%s: invalid decimal number", argv[1]);
+ return 1;
+ }
+
+ tm = localtime(&ts.tv_sec);
+ if (!tm) {
+ zwarnnam(nam, "%s: unable to convert to time", argv[1]);
+ return 1;
+ }
+
+ ts.tv_nsec = 0L;
+ if (argv[2]) {
+ ts.tv_nsec = (long)zstrtol(argv[2], &endptr, 10);
+ if (errno != 0) {
+ zwarnnam(nam, "%s: %e", argv[2], errno);
+ return 1;
+ } else if (*argv[2] == '\0' || *endptr != '\0') {
+ zwarnnam(nam, "%s: invalid decimal number", argv[2]);
+ return 1;
+ } else if (ts.tv_nsec < 0) {
+ zwarnnam(nam, "%s: invalid nanosecond value", argv[2]);
+ return 1;
+ }
+ }
}
+
bufsize = strlen(argv[0]) * 8;
buffer = zalloc(bufsize);
len = 0;
for (x=0; x < 4; x++) {
- if ((len = ztrftime(buffer, bufsize, argv[0], t, 0L)) >= 0 || x==3)
+ if ((len = ztrftime(buffer, bufsize, argv[0], tm, ts.tv_nsec)) >= 0 ||
+ x==3)
break;
buffer = zrealloc(buffer, bufsize *= 2);
}
@@ -207,7 +235,7 @@ getcurrenttime(UNUSED(Param pm))
}
static struct builtin bintab[] = {
- BUILTIN("strftime", 0, bin_strftime, 2, 2, 0, "qrs:", NULL),
+ BUILTIN("strftime", 0, bin_strftime, 1, 3, 0, "qrs:", NULL),
};
static const struct gsu_integer epochseconds_gsu =
diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c
index ed702b912..12dd839cf 100644
--- a/Src/Modules/db_gdbm.c
+++ b/Src/Modules/db_gdbm.c
@@ -809,7 +809,7 @@ myfreeparamnode(HashNode hn)
zsfree(pm->node.nam);
/* If this variable was tied by the user, ename was ztrdup'd */
- if (pm->node.flags & PM_TIED && pm->ename) {
+ if (!(pm->node.flags & PM_SPECIAL) && pm->ename) {
zsfree(pm->ename);
pm->ename = NULL;
}
diff --git a/Src/Modules/nearcolor.c b/Src/Modules/nearcolor.c
new file mode 100644
index 000000000..b49ee9afb
--- /dev/null
+++ b/Src/Modules/nearcolor.c
@@ -0,0 +1,210 @@
+/*
+ * nearcolor.c - map colours to nearest match in 88 or 256 colour palette
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 2018 Oliver Kiddle
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Oliver Kiddle or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Oliver Kiddle and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Oliver Kiddle and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Oliver Kiddle and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "nearcolor.mdh"
+#include "nearcolor.pro"
+
+#include <math.h>
+
+struct cielab {
+ double L, a, b;
+};
+typedef struct cielab *Cielab;
+
+static double
+deltae(Cielab lab1, Cielab lab2)
+{
+ /* taking square root unnecessary as we're just comparing values */
+ return pow(lab1->L - lab2->L, 2) +
+ pow(lab1->a - lab2->a, 2) +
+ pow(lab1->b - lab2->b, 2);
+}
+
+static void
+RGBtoLAB(int red, int green, int blue, Cielab lab)
+{
+ double R = red / 255.0;
+ double G = green / 255.0;
+ double B = blue / 255.0;
+ R = 100.0 * (R > 0.04045 ? pow((R + 0.055) / 1.055, 2.4) : R / 12.92);
+ G = 100.0 * (G > 0.04045 ? pow((G + 0.055) / 1.055, 2.4) : G / 12.92);
+ B = 100.0 * (B > 0.04045 ? pow((B + 0.055) / 1.055, 2.4) : B / 12.92);
+
+ /* Observer. = 2 degrees, Illuminant = D65 */
+ double X = (R * 0.4124 + G * 0.3576 + B * 0.1805) / 95.047;
+ double Y = (R * 0.2126 + G * 0.7152 + B * 0.0722) / 100.0;
+ double Z = (R * 0.0193 + G * 0.1192 + B * 0.9505) / 108.883;
+
+ X = (X > 0.008856) ? pow(X, 1.0/3.0) : (7.787 * X) + (16.0 / 116.0);
+ Y = (Y > 0.008856) ? pow(Y, 1.0/3.0) : (7.787 * Y) + (16.0 / 116.0);
+ Z = (Z > 0.008856) ? pow(Z, 1.0/3.0) : (7.787 * Z) + (16.0 / 116.0);
+
+ lab->L = (116.0 * Y) - 16.0;
+ lab->a = 500.0 * (X - Y);
+ lab->b = 200.0 * (Y - Z);
+}
+
+static int
+mapRGBto88(int red, int green, int blue)
+{
+ int component[] = { 0, 0x8b, 0xcd, 0xff, 0x2e, 0x5c, 0x8b, 0xa2, 0xb9, 0xd0, 0xe7 };
+ struct cielab orig, next;
+ double nextl, bestl = -1;
+ int r, g, b;
+ int comp_r = 0, comp_g = 0, comp_b = 0;
+
+ /* Get original value */
+ RGBtoLAB(red, green, blue, &orig);
+
+ /* try every one of the 72 colours */
+ for (r = 0; r < 11; r++) {
+ for (g = 0; g <= 3; g++) {
+ for (b = 0; b <= 3; b++) {
+ if (r > 3) g = b = r; /* advance inner loops to the block of greys */
+ RGBtoLAB(component[r], component[g], component[b], &next);
+ nextl = deltae(&orig, &next);
+ if (nextl < bestl || bestl < 0) {
+ bestl = nextl;
+ comp_r = r;
+ comp_g = g;
+ comp_b = b;
+ }
+ }
+ }
+ }
+
+ return (comp_r > 3) ? 77 + comp_r :
+ 16 + (comp_r * 16) + (comp_g * 4) + comp_b;
+}
+
+/*
+ * Convert RGB to nearest colour in the 256 colour range
+ */
+static int
+mapRGBto256(int red, int green, int blue)
+{
+ int component[] = {
+ 0, 0x5f, 0x87, 0xaf, 0xd7, 0xff,
+ 0x8, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e,
+ 0x58, 0x62, 0x6c, 0x76, 0x80, 0x8a, 0x94, 0x9e,
+ 0xa8, 0xb2, 0xbc, 0xc6, 0xd0, 0xda, 0xe4, 0xee
+ };
+ struct cielab orig, next;
+ double nextl, bestl = -1;
+ int r, g, b;
+ int comp_r = 0, comp_g = 0, comp_b = 0;
+
+ /* Get original value */
+ RGBtoLAB(red, green, blue, &orig);
+
+ for (r = 0; r < sizeof(component)/sizeof(*component); r++) {
+ for (g = 0; g <= 5; g++) {
+ for (b = 0; b <= 5; b++) {
+ if (r > 5) g = b = r; /* advance inner loops to the block of greys */
+ RGBtoLAB(component[r], component[g], component[b], &next);
+ nextl = deltae(&orig, &next);
+ if (nextl < bestl || bestl < 0) {
+ bestl = nextl;
+ comp_r = r;
+ comp_g = g;
+ comp_b = b;
+ }
+ }
+ }
+ }
+
+ return (comp_r > 5) ? 226 + comp_r :
+ 16 + (comp_r * 36) + (comp_g * 6) + comp_b;
+}
+
+static int
+getnearestcolor(UNUSED(Hookdef dummy), Color_rgb col)
+{
+ /* we add 1 to the colours so that colour 0 (black) is
+ * distinguished from runhookdef() indicating that no
+ * hook function is registered */
+ if (tccolours == 256)
+ return mapRGBto256(col->red, col->green, col->blue) + 1;
+ if (tccolours == 88)
+ return mapRGBto88(col->red, col->green, col->blue) + 1;
+ return -1;
+}
+
+static struct features module_features = {
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ NULL, 0,
+ 0
+};
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+ return 0;
+}
+
+/**/
+int
+features_(Module m, char ***features)
+{
+ *features = featuresarray(m, &module_features);
+ return 0;
+}
+
+/**/
+int
+enables_(Module m, int **enables)
+{
+ return handlefeatures(m, &module_features, enables);
+}
+
+/**/
+int
+boot_(Module m)
+{
+ addhookfunc("get_color_attr", (Hookfn) getnearestcolor);
+ return 0;
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+ deletehookfunc("get_color_attr", (Hookfn) getnearestcolor);
+ return setfeatureenables(m, &module_features, NULL);
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+ return 0;
+}
diff --git a/Src/Modules/nearcolor.mdd b/Src/Modules/nearcolor.mdd
new file mode 100644
index 000000000..2fcdaf04e
--- /dev/null
+++ b/Src/Modules/nearcolor.mdd
@@ -0,0 +1,5 @@
+name=zsh/nearcolor
+link=dynamic
+load=no
+
+objects="nearcolor.o"
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 783c36df3..76824cf58 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -75,6 +75,8 @@ paramtypestr(Param pm)
val = dyncat(val, "-readonly");
if (f & PM_TAGGED)
val = dyncat(val, "-tag");
+ if (f & PM_TIED)
+ val = dyncat(val, "-tied");
if (f & PM_EXPORTED)
val = dyncat(val, "-export");
if (f & PM_UNIQUE)
@@ -2194,67 +2196,67 @@ static const struct gsu_array historywords_gsu =
static struct paramdef partab[] = {
SPECIALPMDEF("aliases", 0,
&pmraliases_gsu, getpmralias, scanpmraliases),
- SPECIALPMDEF("builtins", PM_READONLY, NULL, getpmbuiltin, scanpmbuiltins),
+ SPECIALPMDEF("builtins", PM_READONLY_SPECIAL, NULL, getpmbuiltin, scanpmbuiltins),
SPECIALPMDEF("commands", 0, &pmcommands_gsu, getpmcommand, scanpmcommands),
SPECIALPMDEF("dirstack", PM_ARRAY,
&dirs_gsu, NULL, NULL),
SPECIALPMDEF("dis_aliases", 0,
&pmdisraliases_gsu, getpmdisralias, scanpmdisraliases),
- SPECIALPMDEF("dis_builtins", PM_READONLY,
+ SPECIALPMDEF("dis_builtins", PM_READONLY_SPECIAL,
NULL, getpmdisbuiltin, scanpmdisbuiltins),
SPECIALPMDEF("dis_functions", 0,
&pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions),
- SPECIALPMDEF("dis_functions_source", PM_READONLY, NULL,
+ SPECIALPMDEF("dis_functions_source", PM_READONLY_SPECIAL, NULL,
getpmdisfunction_source, scanpmdisfunction_source),
SPECIALPMDEF("dis_galiases", 0,
&pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases),
- SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY_SPECIAL,
&dispatchars_gsu, NULL, NULL),
- SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY_SPECIAL,
&disreswords_gsu, NULL, NULL),
SPECIALPMDEF("dis_saliases", 0,
&pmdissaliases_gsu, getpmdissalias, scanpmdissaliases),
- SPECIALPMDEF("funcfiletrace", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("funcfiletrace", PM_ARRAY|PM_READONLY_SPECIAL,
&funcfiletrace_gsu, NULL, NULL),
- SPECIALPMDEF("funcsourcetrace", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("funcsourcetrace", PM_ARRAY|PM_READONLY_SPECIAL,
&funcsourcetrace_gsu, NULL, NULL),
- SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY_SPECIAL,
&funcstack_gsu, NULL, NULL),
SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction,
scanpmfunctions),
- SPECIALPMDEF("functions_source", PM_READONLY, NULL,
+ SPECIALPMDEF("functions_source", PM_READONLY_SPECIAL, NULL,
getpmfunction_source, scanpmfunction_source),
- SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY_SPECIAL,
&functrace_gsu, NULL, NULL),
SPECIALPMDEF("galiases", 0,
&pmgaliases_gsu, getpmgalias, scanpmgaliases),
- SPECIALPMDEF("history", PM_READONLY,
+ SPECIALPMDEF("history", PM_READONLY_SPECIAL,
NULL, getpmhistory, scanpmhistory),
- SPECIALPMDEF("historywords", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("historywords", PM_ARRAY|PM_READONLY_SPECIAL,
&historywords_gsu, NULL, NULL),
- SPECIALPMDEF("jobdirs", PM_READONLY,
+ SPECIALPMDEF("jobdirs", PM_READONLY_SPECIAL,
NULL, getpmjobdir, scanpmjobdirs),
- SPECIALPMDEF("jobstates", PM_READONLY,
+ SPECIALPMDEF("jobstates", PM_READONLY_SPECIAL,
NULL, getpmjobstate, scanpmjobstates),
- SPECIALPMDEF("jobtexts", PM_READONLY,
+ SPECIALPMDEF("jobtexts", PM_READONLY_SPECIAL,
NULL, getpmjobtext, scanpmjobtexts),
- SPECIALPMDEF("modules", PM_READONLY,
+ SPECIALPMDEF("modules", PM_READONLY_SPECIAL,
NULL, getpmmodule, scanpmmodules),
SPECIALPMDEF("nameddirs", 0,
&pmnameddirs_gsu, getpmnameddir, scanpmnameddirs),
SPECIALPMDEF("options", 0,
&pmoptions_gsu, getpmoption, scanpmoptions),
- SPECIALPMDEF("parameters", PM_READONLY,
+ SPECIALPMDEF("parameters", PM_READONLY_SPECIAL,
NULL, getpmparameter, scanpmparameters),
- SPECIALPMDEF("patchars", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("patchars", PM_ARRAY|PM_READONLY_SPECIAL,
&patchars_gsu, NULL, NULL),
- SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY_SPECIAL,
&reswords_gsu, NULL, NULL),
SPECIALPMDEF("saliases", 0,
&pmsaliases_gsu, getpmsalias, scanpmsaliases),
- SPECIALPMDEF("userdirs", PM_READONLY,
+ SPECIALPMDEF("userdirs", PM_READONLY_SPECIAL,
NULL, getpmuserdir, scanpmuserdirs),
- SPECIALPMDEF("usergroups", PM_READONLY,
+ SPECIALPMDEF("usergroups", PM_READONLY_SPECIAL,
NULL, getpmusergroups, scanpmusergroups)
};
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index 50a6a9bb2..7c736072b 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -198,10 +198,8 @@ stattimeprint(time_t tim, long nsecs, char *outbuf, int flags)
if (flags & STF_STRING) {
char *oend = outbuf + strlen(outbuf);
/* Where the heck does "40" come from? */
- int len = ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) :
+ ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) :
localtime(&tim), nsecs);
- if (len > 0)
- metafy(oend, len, META_NOALLOC);
if (flags & STF_RAW)
strcat(oend, ")");
}
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 8eca39447..0a454ad5f 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -3160,9 +3160,7 @@ matcheq(Cmatch a, Cmatch b)
matchstreq(a->ppre, b->ppre) &&
matchstreq(a->psuf, b->psuf) &&
matchstreq(a->suf, b->suf) &&
- ((!a->disp && !b->disp && matchstreq(a->str, b->str)) ||
- (a->disp && b->disp && !strcmp(a->disp, b->disp) &&
- matchstreq(a->str, b->str)));
+ matchstreq(a->str, b->str);
}
/* Make an array from a linked list. The second argument says whether *
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index e768aee5d..429c8159f 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -1096,6 +1096,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop)
p += len;
if (*p) {
int arg = 0, is_fg;
+ zattr atr;
if (idigit(*p))
arg = zstrtol(p, &p, 10);
@@ -1159,13 +1160,13 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop)
/* colours must be ASCII */
if (*p == '{') {
p++;
- arg = match_colour((const char **)&p, is_fg, 0);
+ atr = match_colour((const char **)&p, is_fg, 0);
if (*p == '}')
p++;
} else
- arg = match_colour(NULL, is_fg, arg);
- if (arg >= 0 && dopr)
- set_colour_attribute(arg, is_fg ? COL_SEQ_FG :
+ atr = match_colour(NULL, is_fg, arg);
+ if (atr != TXT_ERROR && dopr)
+ set_colour_attribute(atr, is_fg ? COL_SEQ_FG :
COL_SEQ_BG, 0);
break;
case ZWC('f'):
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 5526e0ad0..cb1c01042 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -561,9 +561,9 @@ cd_init(char *nam, char *hide, char *mlen, char *sep,
if (str->str == str->match)
str->str = ztrdup(str->str);
if (hide[1] && str->str[0] == '-' && str->str[1] == '-')
- strcpy(str->str, str->str + 2);
+ memmove(str->str, str->str + 2, strlen(str->str) - 1);
else if (str->str[0] == '-' || str->str[0] == '+')
- strcpy(str->str, str->str + 1);
+ memmove(str->str, str->str + 1, strlen(str->str));
}
}
for (ap = args; *args &&
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 8261da92b..f06c56483 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -430,7 +430,7 @@ enum {
*/
struct region_highlight {
/* Attributes turned on in the region */
- int atr;
+ zattr atr;
/* Start of the region */
int start;
/* Start of the region in metafied ZLE line */
@@ -488,7 +488,7 @@ typedef struct {
* need the effect; 'off' attributes are only present for the
* last character in the sequence.
*/
- int atr;
+ zattr atr;
} REFRESH_ELEMENT;
/* A string of screen cells */
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index d0dd1ef06..1f293845f 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -149,7 +149,7 @@ char *lpromptbuf, *rpromptbuf;
/* Text attributes after displaying prompts */
/**/
-unsigned pmpt_attr, rpmpt_attr;
+zattr pmpt_attr, rpmpt_attr;
/* number of lines displayed */
@@ -208,7 +208,7 @@ int predisplaylen, postdisplaylen;
* displayed on screen.
*/
-static int default_atr_on, special_atr_on;
+static zattr default_atr_on, special_atr_on;
/*
* Array of region highlights, no special termination.
@@ -521,7 +521,7 @@ unset_region_highlight(Param pm, int exp)
/* The last attributes that were on. */
-static int lastatr;
+static zattr lastatr;
/*
* Clear the last attributes that we set: used when we're going
@@ -560,7 +560,7 @@ tcoutclear(int cap)
/**/
void
-zwcputc(const REFRESH_ELEMENT *c, int *curatrp)
+zwcputc(const REFRESH_ELEMENT *c, zattr *curatrp)
{
/*
* Safety: turn attributes off if last heard of turned on.
@@ -638,7 +638,7 @@ static int
zwcwrite(const REFRESH_STRING s, size_t i)
{
size_t j;
- int curatr = 0;
+ zattr curatr = 0;
for (j = 0; j < i; j++)
zwcputc(s + j, &curatr);
@@ -891,7 +891,7 @@ snextline(Rparams rpms)
/**/
static void
-settextattributes(int atr)
+settextattributes(zattr atr)
{
if (txtchangeisset(atr, TXTNOBOLDFACE))
tsetcap(TCALLATTRSOFF, 0);
@@ -992,7 +992,7 @@ zrefresh(void)
int tmppos; /* t - tmpline */
int tmpalloced; /* flag to free tmpline when finished */
int remetafy; /* flag that zle line is metafied */
- int txtchange; /* attributes set after prompts */
+ zattr txtchange; /* attributes set after prompts */
int rprompt_off = 1; /* Offset of rprompt from right of screen */
struct rparams rpms;
#ifdef MULTIBYTE_SUPPORT
@@ -1212,8 +1212,9 @@ zrefresh(void)
rpms.s = nbuf[rpms.ln = 0] + lpromptw;
rpms.sen = *nbuf + winw;
for (t = tmpline, tmppos = 0; tmppos < tmpll; t++, tmppos++) {
- int base_atr_on = default_atr_on, base_atr_off = 0, ireg;
- int all_atr_on, all_atr_off;
+ unsigned ireg;
+ zattr base_atr_on = default_atr_on, base_atr_off = 0;
+ zattr all_atr_on, all_atr_off;
struct region_highlight *rhp;
/*
* Calculate attribute based on region.
@@ -1446,7 +1447,8 @@ zrefresh(void)
more_end = 1;
if (statusline) {
- int outll, outsz, all_atr_on, all_atr_off;
+ int outll, outsz;
+ zattr all_atr_on, all_atr_off;
char *statusdup = ztrdup(statusline);
ZLE_STRING_T outputline =
stringaszleline(statusdup, 0, &outll, &outsz, NULL);
@@ -1672,7 +1674,7 @@ zrefresh(void)
/* output the right-prompt if appropriate */
if (put_rpmpt && !iln && !oput_rpmpt) {
- int attrchange;
+ zattr attrchange;
moveto(0, winw - rprompt_off - rpromptw);
zputs(rpromptbuf, shout);
@@ -1926,7 +1928,7 @@ refreshline(int ln)
/* 3: main display loop - write out the buffer using whatever tricks we can */
for (;;) {
- int now_off;
+ zattr now_off;
#ifdef MULTIBYTE_SUPPORT
if ((!nl->chr || nl->chr != WEOF) && (!ol->chr || ol->chr != WEOF)) {
@@ -2506,8 +2508,9 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
*vp = zr_zr;
for (t0 = 0; t0 < tmpll; t0++) {
- int base_atr_on = 0, base_atr_off = 0, ireg;
- int all_atr_on, all_atr_off;
+ unsigned ireg;
+ zattr base_atr_on = 0, base_atr_off = 0;
+ zattr all_atr_on, all_atr_off;
struct region_highlight *rhp;
/*
* Calculate attribute based on region.
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 22c381237..2b25d6b2e 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -2431,6 +2431,7 @@ printfmt(char *fmt, int n, int dopr, int doesc)
/* Handle the `%' stuff (%% == %, %n == <number of matches>). */
if (doesc && *p == '%') {
int arg = 0, is_fg;
+ zattr atr;
if (idigit(*++p))
arg = zstrtol(p, &p, 10);
if (*p) {
@@ -2482,13 +2483,13 @@ printfmt(char *fmt, int n, int dopr, int doesc)
is_fg = (*p == 'F');
if (p[1] == '{') {
p += 2;
- arg = match_colour((const char **)&p, is_fg, 0);
+ atr = match_colour((const char **)&p, is_fg, 0);
if (*p != '}')
p--;
} else
- arg = match_colour(NULL, is_fg, arg);
- if (arg >= 0)
- set_colour_attribute(arg, is_fg ? COL_SEQ_FG :
+ atr = match_colour(NULL, is_fg, arg);
+ if (atr != TXT_ERROR)
+ set_colour_attribute(atr, is_fg ? COL_SEQ_FG :
COL_SEQ_BG, 0);
break;
case 'f':
diff --git a/Src/builtin.c b/Src/builtin.c
index 4abc7da35..8dcdcc024 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -64,7 +64,7 @@ static struct builtin builtins[] =
BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmprs", NULL),
BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
- BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%TUZ:%afhi:%lp:%rtu", "xg"),
+ BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lp:%rtu", "xg"),
BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL),
/*
* We used to behave as if the argument to -e was optional.
@@ -2258,6 +2258,22 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
} else if (pm->env && !(pm->node.flags & PM_HASHELEM))
delenv(pm);
DPUTS(ASG_ARRAYP(asg), "BUG: typeset got array value where scalar expected");
+ if (altpm && !(pm->node.flags & PM_SPECIAL)) {
+ struct tieddata* tdp = (struct tieddata *) pm->u.data;
+ if (tdp) {
+ if (tdp->joinchar != joinchar && !asg->value.scalar) {
+ /*
+ * Reassign the scalar to itself to do the splitting with
+ * the new joinchar
+ */
+ tdp->joinchar = joinchar;
+ if (!(pm = assignsparam(pname, ztrdup(getsparam(pname)), 0)))
+ return NULL;
+ }
+ }
+ else
+ DPUTS(!tdp, "BUG: no join character to update");
+ }
if (asg->value.scalar &&
!(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0)))
return NULL;
@@ -2325,6 +2341,9 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
zerrnam(cname, "%s: can only have a single instance", pname);
return pm;
}
+
+ on |= pm->node.flags & PM_TIED;
+
/*
* For specials, we keep the same struct but zero everything.
* Maybe it would be easier to create a new struct but copy
@@ -2476,7 +2495,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
return NULL;
}
- if (altpm && PM_TYPE(pm->node.flags) == PM_SCALAR) {
+ if (altpm && PM_TYPE(pm->node.flags) == PM_SCALAR && !(pm->node.flags & PM_SPECIAL)) {
/*
* It seems safer to set this here than in createparam(),
* to make sure we only ever use the colonarr functions
@@ -2646,7 +2665,17 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
/* Given no arguments, list whatever the options specify. */
if (OPT_ISSET(ops,'p')) {
- printflags |= PRINT_TYPESET;
+
+ if (isset(POSIXBUILTINS) && SHELL_EMULATION() != EMULATE_KSH) {
+ if (func == BIN_EXPORT)
+ printflags |= PRINT_POSIX_EXPORT;
+ else if (func == BIN_READONLY)
+ printflags |= PRINT_POSIX_READONLY;
+ else
+ printflags |= PRINT_TYPESET;
+ } else
+ printflags |= PRINT_TYPESET;
+
if (OPT_HASARG(ops,'p')) {
char *eptr;
int pflag = (int)zstrtol(OPT_ARG(ops,'p'), &eptr, 10);
@@ -2662,13 +2691,20 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
}
hasargs = *argv != NULL || (assigns && firstnode(assigns));
if (!hasargs) {
+ int exclude = 0;
if (!OPT_ISSET(ops,'p')) {
if (!(on|roff))
printflags |= PRINT_TYPE;
if (roff || OPT_ISSET(ops,'+'))
printflags |= PRINT_NAMEONLY;
+ } else if (printflags & (PRINT_POSIX_EXPORT|PRINT_POSIX_READONLY)) {
+ /*
+ * For POSIX export/readonly, exclude non-scalars unless
+ * explicitly requested.
+ */
+ exclude = (PM_ARRAY|PM_HASHED) & ~(on|roff);
}
- scanhashtable(paramtab, 1, on|roff, 0, paramtab->printnode, printflags);
+ scanhashtable(paramtab, 1, on|roff, exclude, paramtab->printnode, printflags);
unqueue_signals();
return 0;
}
@@ -2683,6 +2719,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
struct asgment asg0, asg2;
char *oldval = NULL, *joinstr;
int joinchar, nargs;
+ int already_tied = 0;
if (OPT_ISSET(ops,'m')) {
zwarnnam(name, "incompatible options for -T");
@@ -2765,47 +2802,81 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
joinchar = joinstr[1] ^ 32;
else
joinchar = *joinstr;
- /*
- * Keep the old value of the scalar. We need to do this
- * here as if it is already tied to the same array it
- * will be unset when we retie the array. This is all
- * so that typeset -T is idempotent.
- *
- * We also need to remember here whether the damn thing is
- * exported and pass that along. Isn't the world complicated?
- */
- if ((pm = (Param) paramtab->getnode(paramtab, asg0.name))
- && !(pm->node.flags & PM_UNSET)
- && (locallevel == pm->level || !(on & PM_LOCAL))) {
- if (pm->node.flags & PM_TIED) {
+
+ pm = (Param) paramtab->getnode(paramtab, asg0.name);
+ apm = (Param) paramtab->getnode(paramtab, asg->name);
+
+ if (pm && (pm->node.flags & (PM_SPECIAL|PM_TIED)) == (PM_SPECIAL|PM_TIED)) {
+ /*
+ * Only allow typeset -T on special tied parameters if the tied
+ * parameter and join char are the same
+ */
+ if (strcmp(pm->ename, asg->name) || !(apm->node.flags & PM_SPECIAL)) {
+ zwarnnam(name, "%s special parameter can only be tied to special parameter %s", asg0.name, pm->ename);
+ unqueue_signals();
+ return 1;
+ }
+ if (joinchar != ':') {
+ zwarnnam(name, "cannot change the join character of special tied parameters");
unqueue_signals();
- if (PM_TYPE(pm->node.flags) != PM_SCALAR) {
- zwarnnam(name, "already tied as non-scalar: %s", asg0.name);
- } else if (!strcmp(asg->name, pm->ename)) {
+ return 1;
+ }
+ already_tied = 1;
+ } else if (apm && (apm->node.flags & (PM_SPECIAL|PM_TIED)) == (PM_SPECIAL|PM_TIED)) {
+ /*
+ * For the array variable, this covers attempts to tie the
+ * array to a different scalar or to the scalar after it has
+ * been made non-special
+ */
+ zwarnnam(name, "%s special parameter can only be tied to special parameter %s", asg->name, apm->ename);
+ unqueue_signals();
+ return 1;
+ } else if (pm) {
+ if (!(pm->node.flags & PM_UNSET)
+ && (locallevel == pm->level || !(on & PM_LOCAL))) {
+ if (pm->node.flags & PM_TIED) {
+ if (PM_TYPE(pm->node.flags) != PM_SCALAR) {
+ zwarnnam(name, "already tied as non-scalar: %s", asg0.name);
+ unqueue_signals();
+ return 1;
+ } else if (!strcmp(asg->name, pm->ename)) {
+ already_tied = 1;
+ } else {
+ zwarnnam(name, "can't tie already tied scalar: %s",
+ asg0.name);
+ unqueue_signals();
+ return 1;
+ }
+ } else {
/*
- * Already tied in the fashion requested.
+ * Variable already exists in the current scope but is not tied.
+ * We're preserving its value and export attribute but no other
+ * attributes upon converting to "tied".
*/
- struct tieddata *tdp = (struct tieddata*)pm->u.data;
- int flags = (asg->flags & ASG_KEY_VALUE) ?
- ASSPM_KEY_VALUE : 0;
- /* Update join character */
- tdp->joinchar = joinchar;
- if (asg0.value.scalar)
- assignsparam(asg0.name, ztrdup(asg0.value.scalar), 0);
- else if (asg->value.array)
- assignaparam(
- asg->name, zlinklist2array(asg->value.array),flags);
- return 0;
- } else {
- zwarnnam(name, "can't tie already tied scalar: %s",
- asg0.name);
+ if (!asg0.value.scalar && !asg->value.array &&
+ !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)))
+ oldval = ztrdup(getsparam(asg0.name));
+ on |= (pm->node.flags & ~roff) & PM_EXPORTED;
}
- return 1;
}
- if (!asg0.value.scalar && !asg->value.array &&
- !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)))
- oldval = ztrdup(getsparam(asg0.name));
- on |= (pm->node.flags & PM_EXPORTED);
+ }
+ if (already_tied) {
+ int ret;
+ /*
+ * If already tied, we still need to call typeset_single on
+ * both the array and colonarray, if only to update the attributes
+ * of both, and of course to set the new value if one is provided
+ * for either of them.
+ */
+ ret = !(typeset_single(name, asg0.name, pm,
+ func, on, off, roff, &asg0, apm,
+ ops, joinchar) &&
+ typeset_single(name, asg->name, apm,
+ func, (on | PM_ARRAY) & ~PM_EXPORTED,
+ off & ~PM_ARRAY, roff, asg, NULL, ops, 0)
+ );
+ unqueue_signals();
+ return ret;
}
/*
* Create the tied array; this is normal except that
@@ -2832,9 +2903,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
* Create the tied colonarray. We make it as a normal scalar
* and fix up the oddities later.
*/
- if (!(pm=typeset_single(name, asg0.name,
- (Param)paramtab->getnode(paramtab,
- asg0.name),
+ if (!(pm=typeset_single(name, asg0.name, pm,
func, on, off, roff, &asg0, apm,
ops, joinchar))) {
if (oldval)
@@ -5578,8 +5647,9 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
if (stopmsg || (zexit(0,2), !stopmsg)) {
retflag = 1;
breaks = loops;
- exit_pending = (num << 1) | 1;
+ exit_pending = 1;
exit_level = locallevel;
+ exit_val = num;
}
} else
zexit(num, 0);
@@ -5629,6 +5699,42 @@ checkjobs(void)
/**/
int shell_exiting;
+/*
+ * Exit status if explicitly set by an exit command.
+ * This is complicated by the fact the exit command may be within
+ * a function whose state we need to unwind (exit_pending set
+ * and the exit will happen up the stack), or we may need to execute
+ * additional code such as a trap after we are committed to exiting
+ * (shell_exiting and the exit will happen down the stack).
+ *
+ * It's lucky this is all so obvious there is no possibility of any
+ * bugs. (C.f. the entire rest of the shell.)
+ */
+/**/
+int exit_val;
+
+/*
+ * Actually exit the shell, working out the status locally.
+ * This is exit_val if "exit" has explicitly been called in the shell,
+ * else lastval.
+ */
+
+/**/
+void
+realexit(void)
+{
+ exit((shell_exiting || exit_pending) ? exit_val : lastval);
+}
+
+/* As realexit(), but call _exit instead */
+
+/**/
+void
+_realexit(void)
+{
+ _exit((shell_exiting || exit_pending) ? exit_val : lastval);
+}
+
/* exit the shell. val is the return value of the shell. *
* from_where is
* 1 if zexit is called because of a signal
@@ -5640,7 +5746,12 @@ int shell_exiting;
mod_export void
zexit(int val, int from_where)
{
- /* Don't do anything recursively: see below */
+ /*
+ * Don't do anything recursively: see below.
+ * Do, however, update exit status --- there's no nesting,
+ * a later value always overrides an earlier.
+ */
+ exit_val = val;
if (shell_exiting == -1)
return;
@@ -5688,7 +5799,7 @@ zexit(int val, int from_where)
#endif
}
}
- lastval = val;
+ lastval = exit_val;
/*
* Now we are committed to exiting any previous state
* is irrelevant. Ensure trap can run.
@@ -5702,9 +5813,9 @@ zexit(int val, int from_where)
release_pgrp();
}
if (mypid != getpid())
- _exit(val);
+ _exit(exit_val);
else
- exit(val);
+ exit(exit_val);
}
/* . (dot), source */
diff --git a/Src/exec.c b/Src/exec.c
index b9af9ea63..042ba065a 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -738,7 +738,7 @@ execute(LinkList args, int flags, int defpath)
if (!search_defpath(arg0, pbuf, PATH_MAX)) {
if (commandnotfound(arg0, args) == 0)
- _exit(lastval);
+ _realexit();
zerr("command not found: %s", arg0);
_exit(127);
}
@@ -802,7 +802,7 @@ execute(LinkList args, int flags, int defpath)
if (eno)
zerr("%e: %s", eno, arg0);
else if (commandnotfound(arg0, args) == 0)
- _exit(lastval);
+ _realexit();
else
zerr("command not found: %s", arg0);
_exit((eno == EACCES || eno == ENOEXEC) ? 126 : 127);
@@ -1012,6 +1012,7 @@ entersubsh(int flags, struct entersubsh_ret *retp)
unsettrap(sig);
monitor = isset(MONITOR);
job_control_ok = monitor && (flags & ESUB_JOB_CONTROL) && isset(POSIXJOBS);
+ exit_val = 0; /* parent exit status is irrelevant */
if (flags & ESUB_NOMONITOR)
opts[MONITOR] = 0;
if (!isset(MONITOR)) {
@@ -1036,7 +1037,7 @@ entersubsh(int flags, struct entersubsh_ret *retp)
if (!(flags & ESUB_ASYNC))
attachtty(jobtab[thisjob].gleader);
}
- if (retp) {
+ if (retp && !(flags & ESUB_ASYNC)) {
retp->gleader = jobtab[list_pipe_job].gleader;
retp->list_pipe_job = list_pipe_job;
}
@@ -1058,12 +1059,13 @@ entersubsh(int flags, struct entersubsh_ret *retp)
!jobtab[list_pipe_job].gleader)
jobtab[list_pipe_job].gleader = jobtab[thisjob].gleader;
setpgrp(0L, jobtab[thisjob].gleader);
- if (!(flags & ESUB_ASYNC))
+ if (!(flags & ESUB_ASYNC)) {
attachtty(jobtab[thisjob].gleader);
- if (retp) {
- retp->gleader = jobtab[thisjob].gleader;
- if (list_pipe_job != thisjob)
- retp->list_pipe_job = list_pipe_job;
+ if (retp) {
+ retp->gleader = jobtab[thisjob].gleader;
+ if (list_pipe_job != thisjob)
+ retp->list_pipe_job = list_pipe_job;
+ }
}
}
}
@@ -1534,9 +1536,9 @@ sublist_done:
if (sigtrapped[SIGEXIT])
dotrap(SIGEXIT);
if (mypid != getpid())
- _exit(lastval);
+ _realexit();
else
- exit(lastval);
+ realexit();
}
if (errreturn) {
retflag = 1;
@@ -2744,7 +2746,10 @@ execcmd_fork(Estate state, int how, int type, Wordcode varspc,
flags |= ESUB_JOB_CONTROL;
*filelistp = jobtab[thisjob].filelist;
entersubsh(flags, &esret);
- write(synch[1], &esret, sizeof(esret));
+ if (write_loop(synch[1], (const void *) &esret, sizeof(esret)) != sizeof(esret)) {
+ zerr("Failed to send entersubsh_ret report: %e", errno);
+ return -1;
+ }
close(synch[1]);
zclose(close_if_forked);
@@ -2930,7 +2935,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
/* autoload the builtin if necessary */
if (!(hn = resolvebuiltin(cmdarg, hn))) {
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
if (type != WC_TYPESET)
@@ -3111,7 +3116,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
errflag |= ERRFLAG_ERROR;
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
}
@@ -3206,7 +3211,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
errflag |= ERRFLAG_ERROR;
if (forked)
- _exit(lastval);
+ _realexit();
return;
} else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) {
if (!args)
@@ -3226,7 +3231,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
} else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) {
lastval = 0;
if (forked)
- _exit(lastval);
+ _realexit();
return;
} else {
/*
@@ -3238,7 +3243,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
zerr("no match");
lastval = 1;
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
cmdoutval = use_cmdoutval ? lastval : 0;
@@ -3256,7 +3261,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
fflush(xtrerr);
}
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
} else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && do_exec) {
@@ -3264,7 +3269,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
(char *) getdata(firstnode(args)));
lastval = 1;
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
@@ -3300,7 +3305,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
break;
@@ -3311,7 +3316,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
/* autoload the builtin if necessary */
if (!(hn = resolvebuiltin(cmdarg, hn))) {
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
break;
@@ -3329,7 +3334,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
@@ -3408,7 +3413,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
}
@@ -3438,7 +3443,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
if (forked)
- _exit(lastval);
+ _realexit();
return;
}
@@ -4114,13 +4119,13 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (do_exec) {
if (subsh)
- _exit(lastval);
+ _realexit();
/* If we are exec'ing a command, and we are not in a subshell, *
* then check if we should save the history file. */
if (isset(RCS) && interact && !nohistsave)
savehistfile(NULL, 1, HFILE_USE_OPTIONS);
- exit(lastval);
+ realexit();
}
if (restorelist)
restore_params(restorelist, removelist);
@@ -4211,7 +4216,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
closem(FDT_UNUSED, 1);
if (thisjob != -1)
waitjobs();
- _exit(lastval);
+ _realexit();
}
fixfds(save);
@@ -4627,7 +4632,7 @@ getoutput(char *cmd, int qt)
execode(prog, 0, 1, "cmdsubst");
cmdpop();
close(1);
- _exit(lastval);
+ _realexit();
zerr("exit returned in child!!");
kill(getpid(), SIGKILL);
return NULL;
@@ -4800,7 +4805,8 @@ getoutputfile(char *cmd, char **eptr)
}
if ((cmdoutpid = pid = zfork(NULL)) == -1) {
- /* fork or open error */
+ /* fork error */
+ close(fd);
child_unblock();
return nam;
} else if (pid) {
@@ -4821,7 +4827,7 @@ getoutputfile(char *cmd, char **eptr)
execode(prog, 0, 1, "equalsubst");
cmdpop();
close(1);
- _exit(lastval);
+ _realexit();
zerr("exit returned in child!!");
kill(getpid(), SIGKILL);
return NULL;
@@ -4934,7 +4940,7 @@ getproc(char *cmd, char **eptr)
execode(prog, 0, 1, out ? "outsubst" : "insubst");
cmdpop();
zclose(out);
- _exit(lastval);
+ _realexit();
return NULL;
#endif /* HAVE_FIFOS and PATH_DEV_FD not defined */
}
@@ -4982,7 +4988,7 @@ getpipe(char *cmd, int nullexec)
cmdpush(CS_CMDSUBST);
execode(prog, 0, 1, out ? "outsubst" : "insubst");
cmdpop();
- _exit(lastval);
+ _realexit();
return 0;
}
@@ -5923,7 +5929,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
* exit command was handled.
*/
stopmsg = 1;
- zexit(exit_pending >> 1, 0);
+ zexit(exit_val, 0);
}
}
diff --git a/Src/hashtable.h b/Src/hashtable.h
index 21398e17c..f6778664e 100644
--- a/Src/hashtable.h
+++ b/Src/hashtable.h
@@ -63,6 +63,7 @@
#define BIN_UNALIAS 29
#define BIN_UNFUNCTION 30
#define BIN_UNSET 31
+#define BIN_EXPORT 32
/* These currently depend on being 0 and 1. */
#define BIN_SETOPT 0
diff --git a/Src/init.c b/Src/init.c
index e9e6be9b4..e7e62e2f7 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -94,6 +94,7 @@ mod_export struct hookdef zshhooks[] = {
HOOKDEF("exit", NULL, HOOKF_ALL),
HOOKDEF("before_trap", NULL, HOOKF_ALL),
HOOKDEF("after_trap", NULL, HOOKF_ALL),
+ HOOKDEF("get_color_attr", NULL, HOOKF_ALL),
};
/* keep executing lists until EOF found */
@@ -157,7 +158,7 @@ loop(int toplevel, int justonce)
* Handle that now.
*/
stopmsg = 1;
- zexit(exit_pending >> 1, 0);
+ zexit(exit_val, 0);
}
if (tok == LEXERR && !lastval)
lastval = 1;
@@ -215,14 +216,14 @@ loop(int toplevel, int justonce)
clearerr(stderr);
}
if (subsh) /* how'd we get this far in a subshell? */
- exit(lastval);
+ realexit();
if (((!interact || sourcelevel) && errflag) || retflag)
break;
if (isset(SINGLECOMMAND) && toplevel) {
dont_queue_signals();
if (sigtrapped[SIGEXIT])
dotrap(SIGEXIT);
- exit(lastval);
+ realexit();
}
if (justonce)
break;
@@ -1358,7 +1359,7 @@ init_misc(char *cmd, char *zsh_name)
bshin = fdopen(SHIN, "r");
execstring(cmd, 0, 1, "cmdarg");
stopmsg = 1;
- zexit(lastval, 0);
+ zexit((exit_pending || shell_exiting) ? exit_val : lastval, 0);
}
if (interact && isset(RCS))
diff --git a/Src/input.c b/Src/input.c
index 9787dedf6..e9989ffe4 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -555,6 +555,7 @@ inpush(char *str, int flags, Alias inalias)
if ((instacktop->alias = inalias))
inalias->inuse = 1;
} else {
+ instacktop->alias = NULL;
/* If we are continuing an alias expansion, record the alias
* expansion in new set of flags (do we need this?)
*/
@@ -691,6 +692,7 @@ char *input_hasalias(void)
{
if (!(flags & INP_CONT))
break;
+ DPUTS(instackptr == instack, "BUG: continuation at bottom of instack");
instackptr--;
if (instackptr->alias)
return instackptr->alias->node.nam;
diff --git a/Src/jobs.c b/Src/jobs.c
index db2e87ec1..ed9f81f26 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -30,6 +30,27 @@
#include "zsh.mdh"
#include "jobs.pro"
+/*
+ * Job control in zsh
+ * ==================
+ *
+ * A 'job' represents a pipeline; see the section JOBS in zshmisc(1)) for an
+ * introduction. The 'struct job's are allocated in the array 'jobtab' which
+ * has 'jobtabsize' elements. The job whose processes we are currently
+ * preparing to execute is identified by the global variable 'thisjob'.
+ *
+ * A 'superjob' is a job that represents a complex shell construct that has been
+ * backgrounded. For example, if one runs '() { vi; echo }', a job is created
+ * for the pipeline 'vi'. If one then backgrounds vi (with ^Z / SIGTSTP),
+ * the shell forks; the parent shell returns to the interactive prompt and
+ * the child shell becomes a new job in the parent shell. The job representing
+ * the child shell to the parent shell is a superjob (STAT_SUPERJOB); the 'vi'
+ * job is marked as a subjob (STAT_SUBJOB) in the parent shell. When the child
+ * shell is resumed (with fg / SIGCONT), it forwards the signal to vi and,
+ * after vi exits, continues executing the remainder of the function.
+ * (See workers/43565.)
+ */
+
/* the process group of the shell at startup (equal to mypgprp, except
when we started without being process group leader */
@@ -40,18 +61,23 @@ mod_export pid_t origpgrp;
/**/
mod_export pid_t mypgrp;
+
+/* the last process group to attach to the terminal */
+
+/**/
+pid_t last_attached_pgrp;
-/* the job we are working on */
+/* the job we are working on, or -1 if none */
/**/
mod_export int thisjob;
-/* the current job (+) */
+/* the current job (%+) */
/**/
mod_export int curjob;
-/* the previous job (-) */
+/* the previous job (%-) */
/**/
mod_export int prevjob;
@@ -454,19 +480,42 @@ update_job(Job jn)
jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo));
gettyinfo(jn->ty);
}
- if (jn->stat & STAT_STOPPED) {
- if (jn->stat & STAT_SUBJOB) {
- /* If we have `cat foo|while read a; grep $a bar;done'
- * and have hit ^Z, the sub-job is stopped, but the
- * super-job may still be running, waiting to be stopped
- * or to exit. So we have to send it a SIGTSTP. */
- int i;
-
- if ((i = super_job(job)))
- killpg(jobtab[i].gleader, SIGTSTP);
+ if (jn->stat & STAT_SUBJOB) {
+ /* If we have `cat foo|while read a; grep $a bar;done'
+ * and have hit ^Z, the sub-job is stopped, but the
+ * super-job may still be running, waiting to be stopped
+ * or to exit. So we have to send it a SIGTSTP. */
+ int i;
+
+ jn->stat |= STAT_CHANGED | STAT_STOPPED;
+ if ((i = super_job(job))) {
+ Job sjn = &jobtab[i];
+ killpg(sjn->gleader, SIGTSTP);
+ /*
+ * Job may already be stopped if it consists of only the
+ * forked shell waiting for the subjob -- so mark as
+ * stopped immediately. This ensures we send it (and,
+ * crucially, the subjob, as the visible job used with
+ * fg/bg is the superjob) a SIGCONT if we need it.
+ */
+ sjn->stat |= STAT_CHANGED | STAT_STOPPED;
+ if (isset(NOTIFY) && (sjn->stat & STAT_LOCKED) &&
+ !(sjn->stat & STAT_NOPRINT)) {
+ /*
+ * Print the subjob state, which we don't usually
+ * do, so the user knows something has stopped.
+ * So as not to be confusing, we actually output
+ * the user-visible superjob.
+ */
+ if (printjob(sjn, !!isset(LONGLISTJOBS), 0) &&
+ zleactive)
+ zleentry(ZLE_CMD_REFRESH);
+ }
}
return;
}
+ if (jn->stat & STAT_STOPPED)
+ return;
}
{ /* job is done or stopped, remember return value */
lastval2 = val;
@@ -1020,15 +1069,30 @@ printjob(Job jn, int lng, int synch)
"bogus job number, jn = %L, jobtab = %L, oldjobtab = %L",
(long)jn, (long)jobtab, (long)oldjobtab);
- if (jn->stat & STAT_NOPRINT) {
+ if (jn->stat & STAT_NOPRINT)
skip_print = 1;
- }
if (lng < 0) {
conted = 1;
lng = !!isset(LONGLISTJOBS);
}
+ if (jn->stat & STAT_SUPERJOB &&
+ jn->other)
+ {
+ Job sjn = &jobtab[jn->other];
+ if (sjn->procs || sjn->auxprocs)
+ {
+ /*
+ * A subjob still has process, which must finish before
+ * further excution of the superjob, which the user wants to
+ * know about. So report the status of the subjob as if it
+ * were the user-visible superjob.
+ */
+ jn = sjn;
+ }
+ }
+
/* find length of longest signame, check to see */
/* if we really need to print this job */
@@ -1405,6 +1469,11 @@ addproc(pid_t pid, char *text, int aux, struct timeval *bgtime,
jobtab[thisjob].gleader = gleader;
if (list_pipe_job_used != -1)
jobtab[list_pipe_job_used].gleader = gleader;
+ /*
+ * Record here this is the latest process group to grab the
+ * terminal as attachtty() was run in the subshell.
+ */
+ last_attached_pgrp = gleader;
} else if (!jobtab[thisjob].gleader)
jobtab[thisjob].gleader = pid;
/* attach this process to end of process list of current job */
@@ -1559,10 +1628,8 @@ zwaitjob(int job, int wait_cmd)
errflag = 0; */
- if (subsh) {
+ if (subsh)
killjb(jn, SIGCONT);
- jn->stat &= ~STAT_STOPPED;
- }
if (jn->stat & STAT_SUPERJOB)
if (handle_sub(jn - jobtab, 1))
break;
@@ -1580,6 +1647,17 @@ zwaitjob(int job, int wait_cmd)
return 0;
}
+static void waitonejob(Job jn)
+{
+ if (jn->procs || jn->auxprocs)
+ zwaitjob(jn - jobtab, 0);
+ else {
+ deletejob(jn, 0);
+ pipestats[0] = lastval;
+ numpipestats = 1;
+ }
+}
+
/* wait for running job to finish */
/**/
@@ -1589,13 +1667,11 @@ waitjobs(void)
Job jn = jobtab + thisjob;
DPUTS(thisjob == -1, "No valid job in waitjobs.");
- if (jn->procs || jn->auxprocs)
- zwaitjob(thisjob, 0);
- else {
- deletejob(jn, 0);
- pipestats[0] = lastval;
- numpipestats = 1;
- }
+ /* If there's a subjob, it should finish first. */
+ if (jn->stat & STAT_SUPERJOB)
+ waitonejob(jobtab + jn->other);
+ waitonejob(jn);
+
thisjob = -1;
}
@@ -2284,11 +2360,8 @@ bin_fg(char *name, char **argv, Options ops, int func)
Process p;
if (findproc(pid, &j, &p, 0)) {
- if (j->stat & STAT_STOPPED) {
+ if (j->stat & STAT_STOPPED)
retval = (killjb(j, SIGCONT) != 0);
- if (retval == 0)
- makerunning(j);
- }
if (retval == 0) {
/*
* returns 0 for normal exit, else signal+128
diff --git a/Src/lex.c b/Src/lex.c
index 44ad88043..f43bcc7db 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -1613,6 +1613,7 @@ parsestr(char **s)
zerr("parse error near `%c'", err);
else
zerr("parse error");
+ tok = LEXERR;
}
}
return err;
@@ -1626,7 +1627,7 @@ parsestrnoerr(char **s)
zcontext_save();
untokenize(*s);
- inpush(dupstring(*s), 0, NULL);
+ inpush(dupstring_wlen(*s, l), 0, NULL);
strinbeg(0);
lexbuf.len = 0;
lexbuf.ptr = tokstr = *s;
@@ -1658,7 +1659,7 @@ parse_subscript(char *s, int sub, int endchar)
if (!*s || *s == endchar)
return 0;
zcontext_save();
- untokenize(t = dupstring(s));
+ untokenize(t = dupstring_wlen(s, l));
inpush(t, 0, NULL);
strinbeg(0);
/*
@@ -1674,7 +1675,7 @@ parse_subscript(char *s, int sub, int endchar)
* length preservation.
*/
lexbuf.len = 0;
- lexbuf.ptr = tokstr = dupstring(s);
+ lexbuf.ptr = tokstr = dupstring_wlen(s, l);
lexbuf.siz = l + 1;
err = dquote_parse(endchar, sub);
toklen = (int)(lexbuf.ptr - tokstr);
@@ -1713,7 +1714,7 @@ parse_subst_string(char *s)
return 0;
zcontext_save();
untokenize(s);
- inpush(dupstring(s), 0, NULL);
+ inpush(dupstring_wlen(s, l), 0, NULL);
strinbeg(0);
lexbuf.len = 0;
lexbuf.ptr = tokstr = s;
diff --git a/Src/module.c b/Src/module.c
index 4ae78310f..33d75ebbd 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -1390,8 +1390,6 @@ setmathfuncs(char const *nam, MathFunc f, int size, int *e)
if (deletemathfunc(f)) {
zwarnnam(nam, "math function `%s' already deleted", f->name);
ret = 1;
- } else {
- f->flags &= ~MFF_ADDED;
}
}
f++;
diff --git a/Src/params.c b/Src/params.c
index a1c299f60..089a958ae 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -290,7 +290,7 @@ static initparam special_params[] ={
#define GSU(X) BR((GsuScalar)(void *)(&(X)))
#define NULL_GSU BR((GsuScalar)(void *)NULL)
#define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
-IPDEF1("#", pound_gsu, PM_READONLY),
+IPDEF1("#", pound_gsu, PM_READONLY_SPECIAL),
IPDEF1("ERRNO", errno_gsu, PM_UNSET),
IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
IPDEF1("EGID", egid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
@@ -300,11 +300,11 @@ IPDEF1("SAVEHIST", savehist_gsu, PM_RESTRICTED),
IPDEF1("SECONDS", intseconds_gsu, 0),
IPDEF1("UID", uid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
IPDEF1("EUID", euid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY),
+IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY_SPECIAL),
#define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED),
-IPDEF2("-", dash_gsu, PM_READONLY),
+IPDEF2("-", dash_gsu, PM_READONLY_SPECIAL),
IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT),
IPDEF2("HOME", home_gsu, PM_UNSET),
IPDEF2("TERM", term_gsu, PM_UNSET),
@@ -337,7 +337,7 @@ LCIPDEF("LC_TIME"),
# endif
#endif /* USE_LOCALE */
-#define IPDEF4(A,B) {{NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL},BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0}
+#define IPDEF4(A,B) {{NULL,A,PM_INTEGER|PM_READONLY_SPECIAL},BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0}
IPDEF4("!", &lastpid),
IPDEF4("$", &mypid),
IPDEF4("?", &lastval),
@@ -377,10 +377,9 @@ IPDEF7("PS3", &prompt3),
IPDEF7R("PS4", &prompt4),
IPDEF7("SPROMPT", &sprompt),
-#define IPDEF9F(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0}
-#define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
-IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
-IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
+#define IPDEF9(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0}
+IPDEF9("*", &pparams, NULL, PM_ARRAY|PM_READONLY_SPECIAL|PM_DONTIMPORT),
+IPDEF9("@", &pparams, NULL, PM_ARRAY|PM_READONLY_SPECIAL|PM_DONTIMPORT),
/*
* This empty row indicates the end of parameters available in
@@ -389,17 +388,17 @@ IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
#define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0}
-IPDEF8("CDPATH", &cdpath, "cdpath", 0),
-IPDEF8("FIGNORE", &fignore, "fignore", 0),
-IPDEF8("FPATH", &fpath, "fpath", 0),
-IPDEF8("MAILPATH", &mailpath, "mailpath", 0),
-IPDEF8("WATCH", &watch, "watch", 0),
-IPDEF8("PATH", &path, "path", PM_RESTRICTED),
-IPDEF8("PSVAR", &psvar, "psvar", 0),
-IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY),
+IPDEF8("CDPATH", &cdpath, "cdpath", PM_TIED),
+IPDEF8("FIGNORE", &fignore, "fignore", PM_TIED),
+IPDEF8("FPATH", &fpath, "fpath", PM_TIED),
+IPDEF8("MAILPATH", &mailpath, "mailpath", PM_TIED),
+IPDEF8("WATCH", &watch, "watch", PM_TIED),
+IPDEF8("PATH", &path, "path", PM_RESTRICTED|PM_TIED),
+IPDEF8("PSVAR", &psvar, "psvar", PM_TIED),
+IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY_SPECIAL|PM_TIED),
/* MODULE_PATH is not imported for security reasons */
-IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
+IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED|PM_TIED),
#define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
@@ -409,7 +408,7 @@ IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
*/
/* All of these have sh compatible equivalents. */
-IPDEF1("ARGC", argc_gsu, PM_READONLY),
+IPDEF1("ARGC", argc_gsu, PM_READONLY_SPECIAL),
IPDEF2("HISTCHARS", histchars_gsu, PM_DONTIMPORT),
IPDEF4("status", &lastval),
IPDEF7("prompt", &prompt),
@@ -417,20 +416,20 @@ IPDEF7("PROMPT", &prompt),
IPDEF7("PROMPT2", &prompt2),
IPDEF7("PROMPT3", &prompt3),
IPDEF7("PROMPT4", &prompt4),
-IPDEF8("MANPATH", &manpath, "manpath", 0),
-IPDEF9("argv", &pparams, NULL),
-IPDEF9("fignore", &fignore, "FIGNORE"),
-IPDEF9("cdpath", &cdpath, "CDPATH"),
-IPDEF9("fpath", &fpath, "FPATH"),
-IPDEF9("mailpath", &mailpath, "MAILPATH"),
-IPDEF9("manpath", &manpath, "MANPATH"),
-IPDEF9("psvar", &psvar, "PSVAR"),
-IPDEF9("watch", &watch, "WATCH"),
+IPDEF8("MANPATH", &manpath, "manpath", PM_TIED),
+IPDEF9("argv", &pparams, NULL, 0),
+IPDEF9("fignore", &fignore, "FIGNORE", PM_TIED),
+IPDEF9("cdpath", &cdpath, "CDPATH", PM_TIED),
+IPDEF9("fpath", &fpath, "FPATH", PM_TIED),
+IPDEF9("mailpath", &mailpath, "MAILPATH", PM_TIED),
+IPDEF9("manpath", &manpath, "MANPATH", PM_TIED),
+IPDEF9("psvar", &psvar, "PSVAR", PM_TIED),
+IPDEF9("watch", &watch, "WATCH", PM_TIED),
-IPDEF9F("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_READONLY),
+IPDEF9("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_TIED|PM_READONLY_SPECIAL),
-IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED),
-IPDEF9F("path", &path, "PATH", PM_RESTRICTED),
+IPDEF9("module_path", &module_path, "MODULE_PATH", PM_TIED|PM_RESTRICTED),
+IPDEF9("path", &path, "PATH", PM_TIED|PM_RESTRICTED),
/* These are known to zsh alone. */
@@ -451,7 +450,7 @@ IPDEF8("MAILPATH", &mailpath, NULL, 0),
IPDEF8("WATCH", &watch, NULL, 0),
IPDEF8("PATH", &path, NULL, PM_RESTRICTED),
IPDEF8("PSVAR", &psvar, NULL, 0),
-IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY),
+IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY_SPECIAL),
/* MODULE_PATH is not imported for security reasons */
IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED),
@@ -464,7 +463,7 @@ IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED),
* and $@, this is not readonly. This parameter is not directly
* visible in user space.
*/
-static initparam argvparam_pm = IPDEF9F("", &pparams, NULL, \
+static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \
PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT);
#undef BR
@@ -5024,10 +5023,10 @@ arrfixenv(char *s, char **t)
if (!(pm->node.flags & PM_EXPORTED))
return;
- if (pm->node.flags & PM_TIED)
- joinchar = STOUC(((struct tieddata *)pm->u.data)->joinchar);
- else
+ if (pm->node.flags & PM_SPECIAL)
joinchar = ':';
+ else
+ joinchar = STOUC(((struct tieddata *)pm->u.data)->joinchar);
addenv(pm, t ? zjoin(t, joinchar, 1) : "");
}
@@ -5650,7 +5649,7 @@ freeparamnode(HashNode hn)
pm->gsu.s->unsetfn(pm, 1);
zsfree(pm->node.nam);
/* If this variable was tied by the user, ename was ztrdup'd */
- if (pm->node.flags & PM_TIED)
+ if (!(pm->node.flags & PM_SPECIAL))
zsfree(pm->ename);
zfree(pm, sizeof(struct param));
}
@@ -5685,7 +5684,9 @@ static const struct paramtypes pmtypes[] = {
{ PM_UPPER, "uppercase", 'u', 0},
{ PM_READONLY, "readonly", 'r', 0},
{ PM_TAGGED, "tagged", 't', 0},
- { PM_EXPORTED, "exported", 'x', 0}
+ { PM_EXPORTED, "exported", 'x', 0},
+ { PM_UNIQUE, "unique", 'U', 0},
+ { PM_TIED, "tied", 'T', 0}
};
#define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes)))
@@ -5774,10 +5775,6 @@ printparamvalue(Param p, int printflags)
}
break;
}
- if ((printflags & (PRINT_KV_PAIR|PRINT_LINE)) == PRINT_KV_PAIR)
- putchar(' ');
- else if (!(printflags & PRINT_KV_PAIR))
- putchar('\n');
}
/**/
@@ -5785,36 +5782,41 @@ mod_export void
printparamnode(HashNode hn, int printflags)
{
Param p = (Param) hn;
+ Param peer = NULL;
if (p->node.flags & PM_UNSET) {
- if (isset(POSIXBUILTINS) && (p->node.flags & PM_READONLY) &&
- (printflags & PRINT_TYPESET))
- {
+ if (printflags & (PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT) &&
+ p->node.flags & (PM_READONLY|PM_EXPORTED)) {
/*
- * Special POSIX rules: show the parameter as readonly
+ * Special POSIX rules: show the parameter as readonly/exported
* even though it's unset, but with no value.
*/
printflags |= PRINT_NAMEONLY;
}
- else if (p->node.flags & PM_EXPORTED)
- printflags |= PRINT_NAMEONLY;
else
return;
}
if (p->node.flags & PM_AUTOLOAD)
printflags |= PRINT_NAMEONLY;
- if (printflags & PRINT_TYPESET) {
- if ((p->node.flags & (PM_READONLY|PM_SPECIAL)) ==
- (PM_READONLY|PM_SPECIAL) ||
- (p->node.flags & PM_AUTOLOAD)) {
+ if (printflags & (PRINT_TYPESET|PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT)) {
+ if (p->node.flags & (PM_RO_BY_DESIGN|PM_AUTOLOAD)) {
/*
* It's not possible to restore the state of
* these, so don't output.
*/
return;
}
- if (locallevel && p->level >= locallevel) {
+ /*
+ * The zsh variants of export -p/readonly -p also report other
+ * flags to indicate other attributes or scope. The POSIX variants
+ * don't.
+ */
+ if (printflags & PRINT_POSIX_EXPORT) {
+ printf("export ");
+ } else if (printflags & PRINT_POSIX_READONLY) {
+ printf("readonly ");
+ } else if (locallevel && p->level >= locallevel) {
printf("typeset "); /* printf("local "); */
} else if ((p->node.flags & PM_EXPORTED) &&
!(p->node.flags & (PM_ARRAY|PM_HASHED))) {
@@ -5863,13 +5865,46 @@ printparamnode(HashNode hn, int printflags)
}
if (doneminus)
putchar(' ');
+
+ if (p->node.flags & PM_TIED) {
+ /*
+ * For scalars tied to arrays,s
+ * * typeset +m outputs
+ * array tied SCALAR array
+ * tied array SCALAR
+ * * typeset -p outputs:
+ * typeset -T SCALAR array (for hidden values)
+ * typeset -T SCALAR array=(values)
+ * for both scalar and array (flags may be different)
+ *
+ * We choose to print the value for the array instead of the scalar
+ * as scalars can't disambiguate between
+ * typeset -T SCALAR array=()
+ * and
+ * typeset -T SCALAR array=('')
+ * (same for (a b:c)...)
+ */
+ Param tmp = (Param) paramtab->getnode(paramtab, p->ename);
+
+ /*
+ * Swap param and tied peer for typeset -p output
+ */
+ if (!(printflags & PRINT_TYPESET) || (p->node.flags & PM_ARRAY))
+ peer = tmp;
+ else {
+ peer = p;
+ p = tmp;
+ }
+
+ quotedzputs(peer->node.nam, stdout);
+ putchar(' ');
+ }
}
if ((printflags & PRINT_NAMEONLY) ||
- ((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) {
- zputs(p->node.nam, stdout);
- putchar('\n');
- } else {
+ ((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE)))
+ quotedzputs(p->node.nam, stdout);
+ else {
if (printflags & PRINT_KV_PAIR) {
if (printflags & PRINT_LINE)
printf("\n ");
@@ -5881,4 +5916,22 @@ printparamnode(HashNode hn, int printflags)
printparamvalue(p, printflags);
}
+ if (peer && (printflags & PRINT_TYPESET) && !(p->node.flags & PM_SPECIAL)) {
+ /*
+ * append the join char for tied parameters if different from colon
+ * for typeset -p output.
+ */
+ unsigned char joinchar = STOUC(((struct tieddata *)peer->u.data)->joinchar);
+ if (joinchar != ':') {
+ char buf[2];
+ buf[0] = joinchar;
+ buf[1] = '\0';
+ putchar(' ');
+ quotedzputs(buf, stdout);
+ }
+ }
+ if ((printflags & (PRINT_KV_PAIR|PRINT_LINE)) == PRINT_KV_PAIR)
+ putchar(' ');
+ else if (!(printflags & PRINT_KV_PAIR))
+ putchar('\n');
}
diff --git a/Src/prompt.c b/Src/prompt.c
index 959ed8e3d..568bfc2a9 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -33,7 +33,7 @@
/* text attribute mask */
/**/
-mod_export unsigned txtattrmask;
+mod_export zattr txtattrmask;
/* the command stack for use with %_ in prompts */
@@ -168,7 +168,7 @@ promptpath(char *p, int npath, int tilde)
/**/
mod_export char *
-promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep)
+promptexpand(char *s, int ns, char *rs, char *Rs, zattr *txtchangep)
{
struct buf_vars new_vars;
@@ -236,8 +236,8 @@ promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep)
}
/* Parse the argument for %F and %K */
-static int
-parsecolorchar(int arg, int is_fg)
+static zattr
+parsecolorchar(zattr arg, int is_fg)
{
if (bv->fm[1] == '{') {
char *ep;
@@ -268,10 +268,11 @@ parsecolorchar(int arg, int is_fg)
/**/
static int
-putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
+putpromptchar(int doprint, int endchar, zattr *txtchangep)
{
char *ss, *hostnam;
int t0, arg, test, sep, j, numjobs, len;
+ zattr atr;
struct tm *tm;
struct timespec ts;
time_t timet;
@@ -538,13 +539,13 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
tsetcap(TCUNDERLINEEND, TSC_PROMPT|TSC_DIRTY);
break;
case 'F':
- arg = parsecolorchar(arg, 1);
- if (arg >= 0 && !(arg & TXTNOFGCOLOUR)) {
- txtchangeset(txtchangep, arg & TXT_ATTR_FG_ON_MASK,
+ atr = parsecolorchar(arg, 1);
+ if (!(atr & (TXT_ERROR | TXTNOFGCOLOUR))) {
+ txtchangeset(txtchangep, atr & TXT_ATTR_FG_ON_MASK,
TXTNOFGCOLOUR | TXT_ATTR_FG_COL_MASK);
txtunset(TXT_ATTR_FG_COL_MASK);
- txtset(arg & TXT_ATTR_FG_ON_MASK);
- set_colour_attribute(arg, COL_SEQ_FG, TSC_PROMPT);
+ txtset(atr & TXT_ATTR_FG_ON_MASK);
+ set_colour_attribute(atr, COL_SEQ_FG, TSC_PROMPT);
break;
}
/* else FALLTHROUGH */
@@ -554,13 +555,13 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
set_colour_attribute(TXTNOFGCOLOUR, COL_SEQ_FG, TSC_PROMPT);
break;
case 'K':
- arg = parsecolorchar(arg, 0);
- if (arg >= 0 && !(arg & TXTNOBGCOLOUR)) {
- txtchangeset(txtchangep, arg & TXT_ATTR_BG_ON_MASK,
+ atr = parsecolorchar(arg, 0);
+ if (!(atr & (TXT_ERROR | TXTNOBGCOLOUR))) {
+ txtchangeset(txtchangep, atr & TXT_ATTR_BG_ON_MASK,
TXTNOBGCOLOUR | TXT_ATTR_BG_COL_MASK);
txtunset(TXT_ATTR_BG_COL_MASK);
- txtset(arg & TXT_ATTR_BG_ON_MASK);
- set_colour_attribute(arg, COL_SEQ_BG, TSC_PROMPT);
+ txtset(atr & TXT_ATTR_BG_ON_MASK);
+ set_colour_attribute(atr, COL_SEQ_BG, TSC_PROMPT);
break;
}
/* else FALLTHROUGH */
@@ -1185,7 +1186,7 @@ countprompt(char *str, int *wp, int *hp, int overf)
/**/
static int
prompttrunc(int arg, int truncchar, int doprint, int endchar,
- unsigned int *txtchangep)
+ zattr *txtchangep)
{
if (arg > 0) {
char ch = *bv->fm, *ptr, *truncstr;
@@ -1567,8 +1568,8 @@ static const char *ansi_colours[] = {
/* Defines the available types of highlighting */
struct highlight {
const char *name;
- int mask_on;
- int mask_off;
+ zattr mask_on;
+ zattr mask_off;
};
static const struct highlight highlights[] = {
@@ -1615,24 +1616,12 @@ match_named_colour(const char **teststrp)
*/
/**/
-mod_export int
+mod_export zattr
match_colour(const char **teststrp, int is_fg, int colour)
{
- int shft, on, named = 0, tc;
+ int shft, named = 0, tc;
+ zattr on;
- if (teststrp) {
- if ((named = ialpha(**teststrp))) {
- colour = match_named_colour(teststrp);
- if (colour == 8) {
- /* default */
- return is_fg ? TXTNOFGCOLOUR : TXTNOBGCOLOUR;
- }
- }
- else
- colour = (int)zstrtol(*teststrp, (char **)teststrp, 10);
- }
- if (colour < 0 || colour >= 256)
- return -1;
if (is_fg) {
shft = TXT_ATTR_FG_COL_SHIFT;
on = TXTFGCOLOUR;
@@ -1642,8 +1631,47 @@ match_colour(const char **teststrp, int is_fg, int colour)
on = TXTBGCOLOUR;
tc = TCBGCOLOUR;
}
+ if (teststrp) {
+ if (**teststrp == '#' && isxdigit((*teststrp)[1])) {
+ struct color_rgb color;
+ char *end;
+ zlong col = zstrtol(*teststrp+1, &end, 16);
+ if (end - *teststrp == 4) {
+ color.red = col >> 8 | ((col >> 8) << 4);
+ color.green = (col & 0xf0) >> 4;
+ color.green |= color.green << 4;
+ color.blue = col & 0xf;
+ color.blue |= color.blue << 4;
+ } else if (end - *teststrp == 7) {
+ color.red = col >> 16;
+ color.green = (col & 0xff00) >> 8;
+ color.blue = col & 0xff;
+ } else
+ return TXT_ERROR;
+ *teststrp = end;
+ colour = runhookdef(GETCOLORATTR, &color) - 1;
+ if (colour == -1) { /* no hook function added, try true color (24-bit) */
+ colour = (((color.red << 8) + color.green) << 8) + color.blue;
+ return on | (is_fg ? TXT_ATTR_FG_24BIT : TXT_ATTR_BG_24BIT) |
+ (zattr)colour << shft;
+ } else if (colour <= -2) {
+ return TXT_ERROR;
+ }
+ } else if ((named = ialpha(**teststrp))) {
+ colour = match_named_colour(teststrp);
+ if (colour == 8) {
+ /* default */
+ return is_fg ? TXTNOFGCOLOUR : TXTNOBGCOLOUR;
+ }
+ }
+ else {
+ colour = (int)zstrtol(*teststrp, (char **)teststrp, 10);
+ if (colour < 0 || colour >= 256)
+ return TXT_ERROR;
+ }
+ }
/*
- * Try termcap for numbered characters if posible.
+ * Try termcap for numbered characters if possible.
* Don't for named characters, since our best bet
* of getting the names right is with ANSI sequences.
*/
@@ -1654,7 +1682,7 @@ match_colour(const char **teststrp, int is_fg, int colour)
* Can we assume ANSI colours work?
*/
if (colour > 7)
- return -1; /* No. */
+ return TXT_ERROR; /* No. */
} else {
/*
* We can handle termcap colours and the number
@@ -1664,7 +1692,7 @@ match_colour(const char **teststrp, int is_fg, int colour)
TXT_ATTR_BG_TERMCAP;
}
}
- return on | (colour << shft);
+ return on | (zattr)colour << shft;
}
/*
@@ -1674,7 +1702,7 @@ match_colour(const char **teststrp, int is_fg, int colour)
/**/
mod_export void
-match_highlight(const char *teststr, int *on_var)
+match_highlight(const char *teststr, zattr *on_var)
{
int found = 1;
@@ -1684,7 +1712,8 @@ match_highlight(const char *teststr, int *on_var)
found = 0;
if (strpfx("fg=", teststr) || strpfx("bg=", teststr)) {
- int is_fg = (teststr[0] == 'f'), atr;
+ int is_fg = (teststr[0] == 'f');
+ zattr atr;
teststr += 3;
atr = match_colour(&teststr, is_fg, 0);
@@ -1694,7 +1723,7 @@ match_highlight(const char *teststr, int *on_var)
break;
found = 1;
/* skip out of range colours but keep scanning attributes */
- if (atr >= 0)
+ if (atr != TXT_ERROR)
*on_var |= atr;
} else {
for (hl = highlights; hl->name; hl++) {
@@ -1718,11 +1747,12 @@ match_highlight(const char *teststr, int *on_var)
/*
* Count or output a string for colour information: used
- * by output_highlight().
+ * by output_highlight(). count when buf is NULL.
+ * returned count excludes the terminating null byte.
*/
static int
-output_colour(int colour, int fg_bg, int use_tc, char *buf)
+output_colour(int colour, int fg_bg, int use_tc, int truecol, char *buf)
{
int atrlen = 3, len;
char *ptr = buf;
@@ -1730,8 +1760,12 @@ output_colour(int colour, int fg_bg, int use_tc, char *buf)
strcpy(ptr, fg_bg == COL_SEQ_FG ? "fg=" : "bg=");
ptr += 3;
}
+ if (truecol) {
+ /* length of hex triplet always 7, don't need sprintf to count */
+ atrlen += buf ? sprintf(ptr, "#%02x%02x%02x", colour >> 16,
+ (colour >> 8) & 0xff, colour & 0xff) : 7;
/* colour should only be > 7 if using termcap but let's be safe */
- if (use_tc || colour > 7) {
+ } else if (use_tc || colour > 7) {
char digbuf[DIGBUFSIZE];
sprintf(digbuf, "%d", colour);
len = strlen(digbuf);
@@ -1759,7 +1793,7 @@ output_colour(int colour, int fg_bg, int use_tc, char *buf)
/**/
mod_export int
-output_highlight(int atr, char *buf)
+output_highlight(zattr atr, char *buf)
{
const struct highlight *hp;
int atrlen = 0, len;
@@ -1769,6 +1803,7 @@ output_highlight(int atr, char *buf)
len = output_colour(txtchangeget(atr, TXT_ATTR_FG_COL),
COL_SEQ_FG,
(atr & TXT_ATTR_FG_TERMCAP),
+ (atr & TXT_ATTR_FG_24BIT),
ptr);
atrlen += len;
if (buf)
@@ -1785,6 +1820,7 @@ output_highlight(int atr, char *buf)
len = output_colour(txtchangeget(atr, TXT_ATTR_BG_COL),
COL_SEQ_BG,
(atr & TXT_ATTR_BG_TERMCAP),
+ (atr & TXT_ATTR_BG_24BIT),
ptr);
atrlen += len;
if (buf)
@@ -1922,7 +1958,8 @@ allocate_colour_buffer(void)
strlen(fg_bg_sequences[COL_SEQ_BG].end);
len = lenfg > lenbg ? lenfg : lenbg;
- colseq_buf = (char *)zalloc(len+1);
+ /* add 1 for the null and 14 for truecolor */
+ colseq_buf = (char *)zalloc(len+15);
}
/* Free the colour buffer previously allocated. */
@@ -1953,21 +1990,23 @@ free_colour_buffer(void)
/**/
mod_export void
-set_colour_attribute(int atr, int fg_bg, int flags)
+set_colour_attribute(zattr atr, int fg_bg, int flags)
{
char *ptr;
int do_free, is_prompt = (flags & TSC_PROMPT) ? 1 : 0;
- int colour, tc, def, use_termcap;
+ int colour, tc, def, use_termcap, use_truecolor;
if (fg_bg == COL_SEQ_FG) {
colour = txtchangeget(atr, TXT_ATTR_FG_COL);
tc = TCFGCOLOUR;
def = txtchangeisset(atr, TXTNOFGCOLOUR);
+ use_truecolor = txtchangeisset(atr, TXT_ATTR_FG_24BIT);
use_termcap = txtchangeisset(atr, TXT_ATTR_FG_TERMCAP);
} else {
colour = txtchangeget(atr, TXT_ATTR_BG_COL);
tc = TCBGCOLOUR;
def = txtchangeisset(atr, TXTNOBGCOLOUR);
+ use_truecolor = txtchangeisset(atr, TXT_ATTR_BG_24BIT);
use_termcap = txtchangeisset(atr, TXT_ATTR_BG_TERMCAP);
}
@@ -1975,12 +2014,13 @@ set_colour_attribute(int atr, int fg_bg, int flags)
* If we're not restoring the default, and either have a
* colour value that is too large for ANSI, or have been told
* to use the termcap sequence, try to use the termcap sequence.
+ * True color is not covered by termcap.
*
* We have already sanitised the values we allow from the
* highlighting variables, so much of this shouldn't be
* necessary at this point, but we might as well be safe.
*/
- if (!def && (colour > 7 || use_termcap)) {
+ if (!def && !use_truecolor && (colour > 7 || use_termcap)) {
/*
* We can if it's available, and either we couldn't get
* the maximum number of colours, or the colour is in range.
@@ -2024,6 +2064,9 @@ set_colour_attribute(int atr, int fg_bg, int flags)
strcpy(ptr, fg_bg_sequences[fg_bg].def);
while (*ptr)
ptr++;
+ } else if (use_truecolor) {
+ ptr += sprintf(ptr, "8;2;%d;%d;%d", colour >> 16,
+ (colour >> 8) & 0xff, colour & 0xff);
} else
*ptr++ = colour + '0';
strcpy(ptr, fg_bg_sequences[fg_bg].end);
diff --git a/Src/signals.c b/Src/signals.c
index 99aad0fab..f294049c2 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -540,8 +540,8 @@ wait_for_processes(void)
if (WIFEXITED(status) &&
pn->pid == jn->gleader &&
killpg(pn->pid, 0) == -1) {
- jn->gleader = 0;
- if (!(jn->stat & STAT_NOSTTY)) {
+ if (last_attached_pgrp == jn->gleader &&
+ !(jn->stat & STAT_NOSTTY)) {
/*
* This PID was in control of the terminal;
* reclaim terminal now it has exited.
@@ -552,6 +552,7 @@ wait_for_processes(void)
attachtty(mypgrp);
adjustwinsize(0);
}
+ jn->gleader = 0;
}
}
update_job(jn);
@@ -781,7 +782,20 @@ killjb(Job jn, int sig)
if (kill(pn->pid, sig) == -1 && errno != ESRCH)
err = -1;
- return err;
+ /*
+ * The following marks both the superjob and subjob
+ * as running, as done elsewhere.
+ *
+ * It's not entirely clear to me what the right way
+ * to flag the status of a still-pausd final process,
+ * as handled above, but we should be cnsistent about
+ * this inside makerunning() rather than doing anything
+ * special here.
+ */
+ if (err != -1)
+ makerunning(jn);
+
+ return err;
}
if (killpg(jobtab[jn->other].gleader, sig) == -1 && errno != ESRCH)
err = -1;
@@ -791,8 +805,11 @@ killjb(Job jn, int sig)
return err;
}
- else
- return killpg(jn->gleader, sig);
+ else {
+ err = killpg(jn->gleader, sig);
+ if (sig == SIGCONT && err != -1)
+ makerunning(jn);
+ }
}
for (pn = jn->procs; pn; pn = pn->next) {
/*
diff --git a/Src/subst.c b/Src/subst.c
index c1021fbf3..ff6750a59 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -2405,6 +2405,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
aspar = 0;
} else if (aspar)
idbeg = val;
+ if (*val == Nularg)
+ ++val;
*s = sav;
/*
* This tests for the second double quote in an expression
@@ -2552,8 +2554,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
val = dyncat(val, "-readonly");
if (f & PM_TAGGED)
val = dyncat(val, "-tag");
- if (f & PM_TAGGED_LOCAL)
- val = dyncat(val, "-tag_local");
+ if (f & PM_TIED)
+ val = dyncat(val, "-tied");
if (f & PM_EXPORTED)
val = dyncat(val, "-export");
if (f & PM_UNIQUE)
diff --git a/Src/utils.c b/Src/utils.c
index 075d27241..e43a3cdb4 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -3820,6 +3820,14 @@ wordcount(char *s, char *sep, int mul)
return r;
}
+/*
+ * 's' is a NULL-terminated array of strings.
+ * 'sep' is a string.
+ *
+ * Return a string consisting of the elements of 's' joined by 'sep',
+ * allocated on the heap iff 'heap'.
+ */
+
/**/
mod_export char *
sepjoin(char **s, char *sep, int heap)
@@ -4670,6 +4678,10 @@ attachtty(pid_t pgrp)
ep = 1;
}
}
+ else
+ {
+ last_attached_pgrp = pgrp;
+ }
}
}
@@ -7447,19 +7459,28 @@ mailstat(char *path, struct stat *st)
/* See if cur/ is present */
dir = appstr(ztrdup(path), "/cur");
- if (stat(dir, &st_tmp) || !S_ISDIR(st_tmp.st_mode)) return 0;
+ if (stat(dir, &st_tmp) || !S_ISDIR(st_tmp.st_mode)) {
+ zsfree(dir);
+ return 0;
+ }
st_ret.st_atime = st_tmp.st_atime;
/* See if tmp/ is present */
dir[plen] = 0;
dir = appstr(dir, "/tmp");
- if (stat(dir, &st_tmp) || !S_ISDIR(st_tmp.st_mode)) return 0;
+ if (stat(dir, &st_tmp) || !S_ISDIR(st_tmp.st_mode)) {
+ zsfree(dir);
+ return 0;
+ }
st_ret.st_mtime = st_tmp.st_mtime;
/* And new/ */
dir[plen] = 0;
dir = appstr(dir, "/new");
- if (stat(dir, &st_tmp) || !S_ISDIR(st_tmp.st_mode)) return 0;
+ if (stat(dir, &st_tmp) || !S_ISDIR(st_tmp.st_mode)) {
+ zsfree(dir);
+ return 0;
+ }
st_ret.st_mtime = st_tmp.st_mtime;
#if THERE_IS_EXACTLY_ONE_MAILDIR_IN_MAILPATH
@@ -7471,6 +7492,7 @@ mailstat(char *path, struct stat *st)
st_tmp.st_atime == st_new_last.st_atime &&
st_tmp.st_mtime == st_new_last.st_mtime) {
*st = st_ret_last;
+ zsfree(dir);
return 0;
}
st_new_last = st_tmp;
diff --git a/Src/zsh.h b/Src/zsh.h
index b81db1527..10897372b 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1867,7 +1867,7 @@ struct tieddata {
/* The following are the same since they *
* both represent -U option to typeset */
#define PM_UNIQUE (1<<13) /* remove duplicates */
-#define PM_UNALIASED (1<<13) /* do not expand aliases when autoloading */
+#define PM_UNALIASED (1<<13) /* (function) do not expand aliases when autoloading */
#define PM_HIDE (1<<14) /* Special behaviour hidden by local */
#define PM_CUR_FPATH (1<<14) /* (function): can use $fpath with filename */
@@ -1876,28 +1876,30 @@ struct tieddata {
#define PM_TIED (1<<16) /* array tied to colon-path or v.v. */
#define PM_TAGGED_LOCAL (1<<16) /* (function): non-recursive PM_TAGGED */
-#define PM_KSHSTORED (1<<17) /* function stored in ksh form */
-#define PM_ZSHSTORED (1<<18) /* function stored in zsh form */
-
/* Remaining flags do not correspond directly to command line arguments */
-#define PM_DONTIMPORT_SUID (1<<19) /* do not import if running setuid */
-#define PM_LOADDIR (1<<19) /* (function) filename gives load directory */
-#define PM_SINGLE (1<<20) /* special can only have a single instance */
-#define PM_ANONYMOUS (1<<20) /* (function) anonymous function */
-#define PM_LOCAL (1<<21) /* this parameter will be made local */
-#define PM_SPECIAL (1<<22) /* special builtin parameter */
-#define PM_DONTIMPORT (1<<23) /* do not import this variable */
-#define PM_RESTRICTED (1<<24) /* cannot be changed in restricted mode */
-#define PM_UNSET (1<<25) /* has null value */
-#define PM_REMOVABLE (1<<26) /* special can be removed from paramtab */
-#define PM_AUTOLOAD (1<<27) /* autoloaded from module */
-#define PM_NORESTORE (1<<28) /* do not restore value of local special */
-#define PM_AUTOALL (1<<28) /* autoload all features in module
+#define PM_DONTIMPORT_SUID (1<<17) /* do not import if running setuid */
+#define PM_LOADDIR (1<<17) /* (function) filename gives load directory */
+#define PM_SINGLE (1<<18) /* special can only have a single instance */
+#define PM_ANONYMOUS (1<<18) /* (function) anonymous function */
+#define PM_LOCAL (1<<19) /* this parameter will be made local */
+#define PM_KSHSTORED (1<<19) /* (function) stored in ksh form */
+#define PM_SPECIAL (1<<20) /* special builtin parameter */
+#define PM_ZSHSTORED (1<<20) /* (function) stored in zsh form */
+#define PM_RO_BY_DESIGN (1<<21) /* to distinguish from specials that can be
+ made read-only by the user */
+#define PM_READONLY_SPECIAL (PM_SPECIAL|PM_READONLY|PM_RO_BY_DESIGN)
+#define PM_DONTIMPORT (1<<22) /* do not import this variable */
+#define PM_RESTRICTED (1<<23) /* cannot be changed in restricted mode */
+#define PM_UNSET (1<<24) /* has null value */
+#define PM_REMOVABLE (1<<25) /* special can be removed from paramtab */
+#define PM_AUTOLOAD (1<<26) /* autoloaded from module */
+#define PM_NORESTORE (1<<27) /* do not restore value of local special */
+#define PM_AUTOALL (1<<27) /* autoload all features in module
* when loading: valid only if PM_AUTOLOAD
* is also present.
*/
-#define PM_HASHELEM (1<<29) /* is a hash-element */
-#define PM_NAMEDDIR (1<<30) /* has a corresponding nameddirtab entry */
+#define PM_HASHELEM (1<<28) /* is a hash-element */
+#define PM_NAMEDDIR (1<<29) /* has a corresponding nameddirtab entry */
/* The option string corresponds to the first of the variables above */
#define TYPESET_OPTSTR "aiEFALRZlurtxUhHTkz"
@@ -2138,6 +2140,8 @@ typedef groupset *Groupset;
#define PRINT_INCLUDEVALUE (1<<4)
#define PRINT_TYPESET (1<<5)
#define PRINT_LINE (1<<6)
+#define PRINT_POSIX_EXPORT (1<<7)
+#define PRINT_POSIX_READONLY (1<<8)
/* flags for printing for the whence builtin */
#define PRINT_WHENCE_CSH (1<<7)
@@ -2629,6 +2633,12 @@ struct ttyinfo {
* Text attributes for displaying in ZLE
*/
+#ifdef HAVE_STDINT_H
+ typedef uint64_t zattr;
+#else
+ typedef zulong zattr;
+#endif
+
#define TXTBOLDFACE 0x0001
#define TXTSTANDOUT 0x0002
#define TXTUNDERLINE 0x0004
@@ -2660,32 +2670,41 @@ struct ttyinfo {
*/
#define TXT_MULTIWORD_MASK 0x0400
+/* used when, e.g an invalid colour is specified */
+#define TXT_ERROR 0x0800
+
/* Mask for colour to use in foreground */
-#define TXT_ATTR_FG_COL_MASK 0x000FF000
+#define TXT_ATTR_FG_COL_MASK 0x000000FFFFFF0000
/* Bits to shift the foreground colour */
-#define TXT_ATTR_FG_COL_SHIFT (12)
+#define TXT_ATTR_FG_COL_SHIFT (16)
/* Mask for colour to use in background */
-#define TXT_ATTR_BG_COL_MASK 0x0FF00000
+#define TXT_ATTR_BG_COL_MASK 0xFFFFFF0000000000
/* Bits to shift the background colour */
-#define TXT_ATTR_BG_COL_SHIFT (20)
+#define TXT_ATTR_BG_COL_SHIFT (40)
/* Flag to use termcap AF sequence to set colour, if available */
-#define TXT_ATTR_FG_TERMCAP 0x10000000
+#define TXT_ATTR_FG_TERMCAP 0x1000
/* Flag to use termcap AB sequence to set colour, if available */
-#define TXT_ATTR_BG_TERMCAP 0x20000000
+#define TXT_ATTR_BG_TERMCAP 0x2000
+
+/* Flag to indicate that foreground is a 24-bit colour */
+#define TXT_ATTR_FG_24BIT 0x4000
+/* Flag to indicate that background is a 24-bit colour */
+#define TXT_ATTR_BG_24BIT 0x8000
/* Things to turn on, including values for the colour elements */
#define TXT_ATTR_ON_VALUES_MASK \
(TXT_ATTR_ON_MASK|TXT_ATTR_FG_COL_MASK|TXT_ATTR_BG_COL_MASK|\
- TXT_ATTR_FG_TERMCAP|TXT_ATTR_BG_TERMCAP)
+ TXT_ATTR_FG_TERMCAP|TXT_ATTR_BG_TERMCAP|\
+ TXT_ATTR_FG_24BIT|TXT_ATTR_BG_24BIT)
/* Mask out everything to do with setting a foreground colour */
#define TXT_ATTR_FG_ON_MASK \
- (TXTFGCOLOUR|TXT_ATTR_FG_COL_MASK|TXT_ATTR_FG_TERMCAP)
+ (TXTFGCOLOUR|TXT_ATTR_FG_COL_MASK|TXT_ATTR_FG_TERMCAP|TXT_ATTR_FG_24BIT)
/* Mask out everything to do with setting a background colour */
#define TXT_ATTR_BG_ON_MASK \
- (TXTBGCOLOUR|TXT_ATTR_BG_COL_MASK|TXT_ATTR_BG_TERMCAP)
+ (TXTBGCOLOUR|TXT_ATTR_BG_COL_MASK|TXT_ATTR_BG_TERMCAP|TXT_ATTR_BG_24BIT)
/* Mask out everything to do with activating colours */
#define TXT_ATTR_COLOUR_ON_MASK \
@@ -2703,6 +2722,12 @@ struct ttyinfo {
#define COL_SEQ_BG (1)
#define COL_SEQ_COUNT (2)
+struct color_rgb {
+ unsigned int red, green, blue;
+};
+
+typedef struct color_rgb *Color_rgb;
+
/*
* Flags to testcap() and set_colour_attribute (which currently only
* handles TSC_PROMPT).
@@ -3199,6 +3224,7 @@ enum {
#define EXITHOOK (zshhooks + 0)
#define BEFORETRAPHOOK (zshhooks + 1)
#define AFTERTRAPHOOK (zshhooks + 2)
+#define GETCOLORATTR (zshhooks + 3)
#ifdef MULTIBYTE_SUPPORT
/* Final argument to mb_niceformat() */
diff --git a/Src/zsh_system.h b/Src/zsh_system.h
index 8289ee97c..e7d529b6e 100644
--- a/Src/zsh_system.h
+++ b/Src/zsh_system.h
@@ -137,6 +137,10 @@ char *alloca _((size_t));
#include <stddef.h>
#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
#include <stdio.h>
#include <ctype.h>
#include <sys/stat.h>