diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/clone.c | 3 | ||||
-rw-r--r-- | Src/Modules/datetime.c | 64 | ||||
-rw-r--r-- | Src/Modules/db_gdbm.c | 2 | ||||
-rw-r--r-- | Src/Modules/nearcolor.c | 210 | ||||
-rw-r--r-- | Src/Modules/nearcolor.mdd | 5 | ||||
-rw-r--r-- | Src/Modules/parameter.c | 44 | ||||
-rw-r--r-- | Src/Modules/stat.c | 4 | ||||
-rw-r--r-- | Src/Zle/compcore.c | 4 | ||||
-rw-r--r-- | Src/Zle/complist.c | 9 | ||||
-rw-r--r-- | Src/Zle/computil.c | 4 | ||||
-rw-r--r-- | Src/Zle/zle.h | 4 | ||||
-rw-r--r-- | Src/Zle/zle_refresh.c | 31 | ||||
-rw-r--r-- | Src/Zle/zle_tricky.c | 9 | ||||
-rw-r--r-- | Src/builtin.c | 207 | ||||
-rw-r--r-- | Src/exec.c | 70 | ||||
-rw-r--r-- | Src/hashtable.h | 1 | ||||
-rw-r--r-- | Src/init.c | 9 | ||||
-rw-r--r-- | Src/input.c | 2 | ||||
-rw-r--r-- | Src/jobs.c | 131 | ||||
-rw-r--r-- | Src/lex.c | 9 | ||||
-rw-r--r-- | Src/module.c | 2 | ||||
-rw-r--r-- | Src/params.c | 165 | ||||
-rw-r--r-- | Src/prompt.c | 137 | ||||
-rw-r--r-- | Src/signals.c | 27 | ||||
-rw-r--r-- | Src/subst.c | 6 | ||||
-rw-r--r-- | Src/utils.c | 28 | ||||
-rw-r--r-- | Src/zsh.h | 82 | ||||
-rw-r--r-- | Src/zsh_system.h | 4 |
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 @@ -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; @@ -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> |