diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/parameter.c | 20 | ||||
-rw-r--r-- | Src/Modules/regex.c | 23 | ||||
-rw-r--r-- | Src/Zle/zle.h | 1 | ||||
-rw-r--r-- | Src/Zle/zle_params.c | 32 | ||||
-rw-r--r-- | Src/Zle/zle_utils.c | 30 | ||||
-rw-r--r-- | Src/builtin.c | 100 | ||||
-rw-r--r-- | Src/exec.c | 27 | ||||
-rw-r--r-- | Src/glob.c | 15 | ||||
-rw-r--r-- | Src/hashtable.c | 3 | ||||
-rw-r--r-- | Src/hist.c | 3 | ||||
-rw-r--r-- | Src/init.c | 123 | ||||
-rw-r--r-- | Src/jobs.c | 24 | ||||
-rw-r--r-- | Src/options.c | 16 | ||||
-rw-r--r-- | Src/params.c | 141 | ||||
-rw-r--r-- | Src/prompt.c | 16 | ||||
-rw-r--r-- | Src/subst.c | 69 | ||||
-rw-r--r-- | Src/utils.c | 53 | ||||
-rw-r--r-- | Src/zsh_system.h | 4 |
18 files changed, 540 insertions, 160 deletions
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 092efa0c3..4d29ba635 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -531,7 +531,11 @@ functracegetfn(UNUSED(Param pm)) char *colonpair; colonpair = zhalloc(strlen(f->caller) + (f->lineno > 9999 ? 24 : 6)); +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + sprintf(colonpair, "%s:%lld", f->caller, f->lineno); +#else sprintf(colonpair, "%s:%ld", f->caller, (long)f->lineno); +#endif *p = colonpair; } @@ -559,7 +563,11 @@ funcsourcetracegetfn(UNUSED(Param pm)) char *fname = f->filename ? f->filename : ""; colonpair = zhalloc(strlen(fname) + (f->flineno > 9999 ? 24 : 6)); +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + sprintf(colonpair, "%s:%lld", fname, f->flineno); +#else sprintf(colonpair, "%s:%ld", fname, (long)f->flineno); +#endif *p = colonpair; } @@ -594,7 +602,11 @@ funcfiletracegetfn(UNUSED(Param pm)) */ colonpair = zhalloc(strlen(f->caller) + (f->lineno > 9999 ? 24 : 6)); +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + sprintf(colonpair, "%s:%lld", f->caller, f->lineno); +#else sprintf(colonpair, "%s:%ld", f->caller, (long)f->lineno); +#endif } else { /* * Calling context is a function or eval; we need to find @@ -604,7 +616,7 @@ funcfiletracegetfn(UNUSED(Param pm)) * together with the $functrace line number for the current * context. */ - long flineno = (long)(f->prev->flineno + f->lineno); + zlong flineno = f->prev->flineno + f->lineno; /* * Line numbers in eval start from 1, not zero, * so offset by one to get line in file. @@ -614,7 +626,11 @@ funcfiletracegetfn(UNUSED(Param pm)) fname = f->prev->filename ? f->prev->filename : ""; colonpair = zhalloc(strlen(fname) + (flineno > 9999 ? 24 : 6)); - sprintf(colonpair, "%s:%ld", fname, flineno); +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + sprintf(colonpair, "%s:%lld", fname, flineno); +#else + sprintf(colonpair, "%s:%ld", fname, (long)flineno); +#endif } *p = colonpair; diff --git a/Src/Modules/regex.c b/Src/Modules/regex.c index 08e815003..ce57de986 100644 --- a/Src/Modules/regex.c +++ b/Src/Modules/regex.c @@ -3,7 +3,7 @@ * * This file is part of zsh, the Z shell. * - * Copyright (c) 2007 Phil Pennock + * Copyright (c) 2007,2012 Phil Pennock * All Rights Reserved. * * Permission is hereby granted, without written agreement and without @@ -56,14 +56,19 @@ zcond_regex_match(char **a, int id) regex_t re; regmatch_t *m, *matches = NULL; size_t matchessz = 0; - char *lhstr, *rhre, *s, **arr, **x; + char *lhstr, *lhstr_zshmeta, *rhre, *rhre_zshmeta, *s, **arr, **x; int r, n, return_value, rcflags, reflags, nelem, start; - lhstr = cond_str(a,0,0); - rhre = cond_str(a,1,0); + lhstr_zshmeta = cond_str(a,0,0); + rhre_zshmeta = cond_str(a,1,0); rcflags = reflags = 0; return_value = 0; /* 1 => matched successfully */ + lhstr = ztrdup(lhstr_zshmeta); + unmetafy(lhstr, NULL); + rhre = ztrdup(rhre_zshmeta); + unmetafy(rhre, NULL); + switch(id) { case ZREGEX_EXTENDED: rcflags |= REG_EXTENDED; @@ -101,7 +106,7 @@ zcond_regex_match(char **a, int id) if (nelem) { arr = x = (char **) zalloc(sizeof(char *) * (nelem + 1)); for (m = matches + start, n = start; n <= (int)re.re_nsub; ++n, ++m, ++x) { - *x = ztrduppfx(lhstr + m->rm_so, m->rm_eo - m->rm_so); + *x = metafy(lhstr + m->rm_so, m->rm_eo - m->rm_so, META_DUP); } *x = NULL; } @@ -112,7 +117,7 @@ zcond_regex_match(char **a, int id) char *ptr; m = matches; - s = ztrduppfx(lhstr + m->rm_so, m->rm_eo - m->rm_so); + s = metafy(lhstr + m->rm_so, m->rm_eo - m->rm_so, META_DUP); setsparam("MATCH", s); /* * Count the characters before the match. @@ -174,12 +179,16 @@ zcond_regex_match(char **a, int id) break; default: DPUTS(1, "bad regex option"); - return 0; /* nothing to cleanup, especially not "re". */ + return_value = 0; + goto CLEAN_BASEMETA; } if (matches) zfree(matches, matchessz); regfree(&re); +CLEAN_BASEMETA: + free(lhstr); + free(rhre); return return_value; } diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index bedf28f17..cf44b47d2 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -269,6 +269,7 @@ struct change { ZLE_STRING_T ins; /* characters to insert */ int insl; /* no. of characters in ins */ int old_cs, new_cs; /* old and new cursor positions */ + zlong changeno; /* unique number of this change */ }; #define CH_NEXT (1<<0) /* next structure is also part of this change */ diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index 3fdb5f8ed..a9bbf136a 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -93,6 +93,8 @@ static const struct gsu_integer pending_gsu = { get_pending, NULL, zleunsetfn }; static const struct gsu_integer region_active_gsu = { get_region_active, set_region_active, zleunsetfn }; +static const struct gsu_integer undo_change_no_gsu = +{ get_undo_current_change, NULL, zleunsetfn }; static const struct gsu_array killring_gsu = { get_killring, set_killring, unset_killring }; @@ -133,6 +135,8 @@ static struct zleparam { { "RBUFFER", PM_SCALAR, GSU(rbuffer_gsu), NULL }, { "REGION_ACTIVE", PM_INTEGER, GSU(region_active_gsu), NULL}, { "region_highlight", PM_ARRAY, GSU(region_highlight_gsu), NULL }, + { "UNDO_CHANGE_NO", PM_INTEGER | PM_READONLY, GSU(undo_change_no_gsu), + NULL }, { "WIDGET", PM_SCALAR | PM_READONLY, GSU(widget_gsu), NULL }, { "WIDGETFUNC", PM_SCALAR | PM_READONLY, GSU(widgetfunc_gsu), NULL }, { "WIDGETSTYLE", PM_SCALAR | PM_READONLY, GSU(widgetstyle_gsu), NULL }, @@ -705,21 +709,17 @@ get_context(UNUSED(Param pm)) static char * get_zle_state(UNUSED(Param pm)) { - char *zle_state = NULL, *ptr = NULL; + char *zle_state = NULL, *ptr = NULL, **arr = NULL; int itp, istate, len = 0; /* - * When additional substrings are added, they should be kept in - * alphabetical order, so the user can easily match against this - * parameter: if [[ $ZLE_STATE == *bar*foo*zonk* ]]; then ...; fi + * Substrings are sorted at the end, so the user can + * easily match against this parameter: + * if [[ $ZLE_STATE == *bar*foo*zonk* ]]; then ...; fi */ for (itp = 0; itp < 2; itp++) { char *str; - /* - * Currently there is only one state: insert or overwrite. - * This loop is to make it easy to add others. - */ - for (istate = 0; istate < 1; istate++) { + for (istate = 0; istate < 2; istate++) { int slen; switch (istate) { case 0: @@ -729,6 +729,13 @@ get_zle_state(UNUSED(Param pm)) str = "overwrite"; } break; + case 1: + if (hist_skip_flags & HIST_FOREIGN) { + str = "localhistory"; + } else { + str = "globalhistory"; + } + break; default: str = ""; @@ -742,7 +749,7 @@ get_zle_state(UNUSED(Param pm)) } else { /* Accumulating string */ if (istate) - *ptr++ = ' '; + *ptr++ = ':'; memcpy(ptr, str, slen); ptr += slen; } @@ -755,5 +762,10 @@ get_zle_state(UNUSED(Param pm)) } } + arr = colonsplit(zle_state, 0); + strmetasort(arr, SORTIT_ANYOLDHOW, NULL); + zle_state = zjoin(arr, ' ', 1); + freearray(arr); + return zle_state; } diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 45e30445e..cf6787f3a 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1359,6 +1359,10 @@ static struct change *changes, *curchange; static struct change *nextchanges, *endnextchanges; +/* incremented to provide a unique change number */ + +static zlong undo_changeno; + /**/ void initundo(void) @@ -1368,6 +1372,7 @@ initundo(void) curchange->prev = curchange->next = NULL; curchange->del = curchange->ins = NULL; curchange->dell = curchange->insl = 0; + curchange->changeno = undo_changeno = 0; lastline = zalloc((lastlinesz = linesz) * ZLE_CHAR_SIZE); ZS_memcpy(lastline, zleline, (lastll = zlell)); lastcs = zlecs; @@ -1492,6 +1497,7 @@ mkundoent(void) ch->flags = 0; ch->prev = NULL; } + ch->changeno = ++undo_changeno; endnextchanges = ch; } @@ -1512,8 +1518,15 @@ setlastline(void) /**/ int -undo(UNUSED(char **args)) +undo(char **args) { + zlong last_change = (zlong)0; + + if (*args) + { + last_change = zstrtol(*args, NULL, 0); + } + handleundo(); do { if(!curchange->prev) @@ -1522,7 +1535,8 @@ undo(UNUSED(char **args)) curchange = curchange->prev; else break; - } while(curchange->flags & CH_PREV); + } while (*args ? curchange->changeno != last_change : + (curchange->flags & CH_PREV)); setlastline(); return 0; } @@ -1637,3 +1651,15 @@ zlecallhook(char *name, char *arg) errflag = saverrflag; retflag = savretflag; } + +/* + * Return the number corresponding to the last change made. + */ + +/**/ +zlong +get_undo_current_change(UNUSED(Param pm)) +{ + return undo_changeno; +} + diff --git a/Src/builtin.c b/Src/builtin.c index b43c08235..b5a98cbd2 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -58,7 +58,7 @@ static struct builtin builtins[] = BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmrs", NULL), BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL), BUILTIN("echo", BINF_SKIPINVALID, bin_print, 0, -1, BIN_ECHO, "neE", "-"), - BUILTIN("emulate", 0, bin_emulate, 0, 3, 0, "LR", NULL), + BUILTIN("emulate", 0, bin_emulate, 0, -1, 0, "LR", NULL), BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmrs", 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), @@ -1498,7 +1498,7 @@ bin_fc(char *nam, char **argv, Options ops, int func) } if (OPT_ISSET(ops,'l')) { /* list the required part of the history */ - retval = fclist(stdout, ops, first, last, asgf, pprog); + retval = fclist(stdout, ops, first, last, asgf, pprog, 0); unqueue_signals(); } else { @@ -1530,7 +1530,7 @@ bin_fc(char *nam, char **argv, Options ops, int func) } } ops->ind['n'] = 1; /* No line numbers here. */ - if (!fclist(out, ops, first, last, asgf, pprog)) { + if (!fclist(out, ops, first, last, asgf, pprog, 1)) { char *editor; if (func == BIN_R) @@ -1639,7 +1639,7 @@ fcsubs(char **sp, struct asgment *sub) /**/ static int fclist(FILE *f, Options ops, zlong first, zlong last, - struct asgment *subs, Patprog pprog) + struct asgment *subs, Patprog pprog, int is_command) { int fclistdone = 0; zlong tmp; @@ -1652,8 +1652,8 @@ fclist(FILE *f, Options ops, zlong first, zlong last, last = first; first = tmp; } - if (first > last) { - zwarnnam("fc", "history events are in wrong order, aborted"); + if (is_command && first > last) { + zwarnnam("fc", "history events can't be executed backwards, aborted"); if (f != stdout) fclose(f); return 1; @@ -1976,9 +1976,10 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), tc = 0; /* but don't do a normal conversion */ } } else if (!setsecondstype(pm, on, off)) { - if (value && !setsparam(pname, ztrdup(value))) + if (value && !(pm = setsparam(pname, ztrdup(value)))) return NULL; - return pm; + usepm = 1; + err = 0; } } if (err) @@ -3054,6 +3055,34 @@ bin_unset(char *name, char **argv, Options ops, int func) *sse = ']'; } paramtab = tht; + } else if (PM_TYPE(pm->node.flags) == PM_SCALAR || + PM_TYPE(pm->node.flags) == PM_ARRAY) { + struct value vbuf; + vbuf.isarr = (PM_TYPE(pm->node.flags) == PM_ARRAY ? + SCANPM_ARRONLY : 0); + vbuf.pm = pm; + vbuf.flags = 0; + vbuf.start = 0; + vbuf.end = -1; + vbuf.arr = 0; + *ss = '['; + if (getindex(&ss, &vbuf, SCANPM_ASSIGNING) == 0 && + vbuf.pm && !(vbuf.pm->node.flags & PM_UNSET)) { + if (PM_TYPE(pm->node.flags) == PM_SCALAR) { + setstrvalue(&vbuf, ztrdup("")); + } else { + /* start is after the element for reverse index */ + int start = vbuf.start - !!(vbuf.flags & VALFLAG_INV); + if (start < arrlen(vbuf.pm->u.arr)) { + char *arr[2]; + arr[0] = ""; + arr[1] = 0; + setarrvalue(&vbuf, zarrdup(arr)); + } + } + } + returnval = errflag; + errflag = 0; } else { zerrnam(name, "%s: invalid element for unset", s); returnval = 1; @@ -4958,14 +4987,14 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) { int opt_L = OPT_ISSET(ops, 'L'); int opt_R = OPT_ISSET(ops, 'R'); - int saveemulation, savesticky_emulation; - int ret; + int saveemulation, savesticky_emulation, savehackchar; + int ret = 1; char saveopts[OPT_SIZE]; + char *cmd = 0; + const char *shname = *argv; /* without arguments just print current emulation */ - if (!*argv) { - const char *shname; - + if (!shname) { if (opt_L || opt_R) { zwarnnam("emulate", "not enough arguments"); return 1; @@ -4995,39 +5024,46 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) /* with single argument set current emulation */ if (!argv[1]) { - emulate(*argv, OPT_ISSET(ops,'R')); + emulate(shname, OPT_ISSET(ops,'R')); if (OPT_ISSET(ops,'L')) opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1; return 0; } - /* If "-c command" is given, evaluate command using specified - * emulation mode. - */ - if (strcmp(argv[1], "-c")) { - zwarnnam("emulate", "unknown argument %s", argv[1]); - return 1; - } + argv++; + memcpy(saveopts, opts, sizeof(opts)); + savehackchar = keyboardhackchar; + cmd = parseopts("emulate", &argv); - if (!argv[2]) { - zwarnnam("emulate", "not enough arguments"); - return 1; + /* parseopts() has consumed anything that looks like an option */ + if (*argv) { + zwarnnam("emulate", "unknown argument %s", *argv); + goto restore; } - if (opt_L) { - zwarnnam("emulate", "option -L incompatible with -c"); - return 1; - } + /* If "-c command" is given, evaluate command using specified + * emulation mode. + */ + if (cmd) { + if (opt_L) { + zwarnnam("emulate", "option -L incompatible with -c"); + goto restore; + } + *--argv = cmd; /* on stack, never free()d, see execbuiltin() */ + } else + return 0; - memcpy(saveopts, opts, sizeof(opts)); saveemulation = emulation; savesticky_emulation = sticky_emulation; - emulate(*argv, OPT_ISSET(ops,'R')); + emulate(shname, OPT_ISSET(ops,'R')); sticky_emulation = emulation; - ret = eval(argv+2); - memcpy(opts, saveopts, sizeof(opts)); + ret = eval(argv); sticky_emulation = savesticky_emulation; emulation = saveemulation; + restore: + memcpy(opts, saveopts, sizeof(opts)); + keyboardhackchar = savehackchar; + inittyptab(); /* restore banghist */ return ret; } diff --git a/Src/exec.c b/Src/exec.c index 503e0843d..6ebc9c014 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1617,9 +1617,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) (list_pipe || (pline_level && !(jn->stat & STAT_SUBJOB))))) deletejob(jn, 0); thisjob = pj; - } - if (slflags & WC_SUBLIST_NOT) + if ((slflags & WC_SUBLIST_NOT) && !errflag) lastval = !lastval; } if (!pline_level) @@ -1679,9 +1678,13 @@ execpline2(Estate state, wordcode pcode, if (pipe(synch) < 0) { zerr("pipe failed: %e", errno); + lastval = errflag = 1; + return; } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); + lastval = errflag = 1; + return; } else if (pid) { char dummy, *text; @@ -2490,7 +2493,7 @@ execcmd(Estate state, int input, int output, int how, int last1) if (!firstnode(args)) { zerr("exec requires a command to execute"); errflag = lastval = 1; - return; + goto done; } uremnode(args, firstnode(args)); if (!strcmp(next, "--")) @@ -2507,12 +2510,12 @@ execcmd(Estate state, int input, int output, int how, int last1) if (!firstnode(args)) { zerr("exec requires a command to execute"); errflag = lastval = 1; - return; + goto done; } if (!nextnode(firstnode(args))) { zerr("exec flag -a requires a parameter"); errflag = lastval = 1; - return; + goto done; } exec_argv0 = (char *) getdata(nextnode(firstnode(args))); @@ -2813,15 +2816,12 @@ execcmd(Estate state, int input, int output, int how, int last1) if (pipe(synch) < 0) { zerr("pipe failed: %e", errno); - if (oautocont >= 0) - opts[AUTOCONTINUE] = oautocont; - return; + goto fatal; } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); - if (oautocont >= 0) - opts[AUTOCONTINUE] = oautocont; - return; + lastval = errflag = 1; + goto fatal; } if (pid) { @@ -3252,7 +3252,11 @@ execcmd(Estate state, int input, int output, int how, int last1) } if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) && lastval && !subsh) { +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + fprintf(stderr, "zsh: exit %lld\n", lastval); +#else fprintf(stderr, "zsh: exit %ld\n", (long)lastval); +#endif fflush(stderr); } @@ -3365,6 +3369,7 @@ execcmd(Estate state, int input, int output, int how, int last1) * classify as a builtin) we treat all errors as fatal. * The "command" builtin is not special so resets this behaviour. */ + fatal: if (redir_err || errflag) { if (!isset(INTERACTIVE)) { if (forked) diff --git a/Src/glob.c b/Src/glob.c index d003d95da..ca2ffaf51 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -997,7 +997,9 @@ gmatchcmp(Gmatch a, Gmatch b) break; } if (r) - return (int) ((s->tp & GS_DESC) ? -r : r); + return (s->tp & GS_DESC) ? + (r < 0L ? 1 : -1) : + (r > 0L ? 1 : -1); } return 0; } @@ -2089,7 +2091,8 @@ xpandbraces(LinkList list, LinkNode *np) char *dots, *p, *dots2 = NULL; LinkNode olast = last; /* Get the first number of the range */ - int rstart = zstrtol(str+1,&dots,10), rend = 0, err = 0, rev = 0, rincr = 1; + zlong rstart = zstrtol(str+1,&dots,10), rend = 0; + int err = 0, rev = 0, rincr = 1; int wid1 = (dots - str) - 1, wid2 = (str2 - dots) - 2, wid3 = 0; int strp = str - str3; @@ -2134,7 +2137,7 @@ xpandbraces(LinkList list, LinkNode *np) } if (rstart > rend) { /* Handle decreasing ranges correctly. */ - int rt = rend; + zlong rt = rend; rend = rstart; rstart = rt; rev = !rev; @@ -2147,7 +2150,11 @@ xpandbraces(LinkList list, LinkNode *np) for (; rend >= rstart; rend -= rincr) { /* Node added in at end, so do highest first */ p = dupstring(str3); - sprintf(p + strp, "%0*d", minw, rend); +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + sprintf(p + strp, "%0*lld", minw, rend); +#else + sprintf(p + strp, "%0*ld", minw, (long)rend); +#endif strcat(p + strp, str2 + 1); insertlinknode(list, last, p); if (rev) /* decreasing: add in reverse order. */ diff --git a/Src/hashtable.c b/Src/hashtable.c index 775b6a277..be71a1cc9 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -664,7 +664,8 @@ hashdir(char **dirp) * executable plain files. */ if (unset(HASHEXECUTABLESONLY) || - (stat(pathbuf, &statbuf) == 0 && + (access(pathbuf, X_OK) == 0 && + stat(pathbuf, &statbuf) == 0 && S_ISREG(statbuf.st_mode) && (statbuf.st_mode & S_IXUGO))) add = 1; } diff --git a/Src/hist.c b/Src/hist.c index 4d522dddb..0e63dca37 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -2225,7 +2225,8 @@ readhistline(int start, char **bufp, int *bufsiz, FILE *in) } else { buf[len - 1] = '\0'; - if (len > 1 && buf[len - 2] == '\\') { + if (len > 1 && buf[len - 2] == '\\' && + (len < 3 || buf[len - 3] != '\\')) { buf[--len - 1] = '\n'; if (!feof(in)) return readhistline(len, bufp, bufsiz, in); diff --git a/Src/init.c b/Src/init.c index 9820070fb..6f14943e1 100644 --- a/Src/init.c +++ b/Src/init.c @@ -215,6 +215,7 @@ loop(int toplevel, int justonce) return LOOP_OK; } +/* Shared among parseargs(), parseopts(), init_io(), and init_misc() */ static char *cmd; static int restricted; @@ -222,9 +223,7 @@ static int restricted; static void parseargs(char **argv, char **runscript) { - int optionbreak = 0; char **x; - int action, optno; LinkList paramlist; argzero = *argv++; @@ -247,6 +246,49 @@ parseargs(char **argv, char **runscript) opts[SHINSTDIN] = 0; opts[SINGLECOMMAND] = 0; + cmd = parseopts(NULL, &argv); + + paramlist = znewlinklist(); + if (*argv) { + if (unset(SHINSTDIN)) { + if (cmd) + argzero = *argv; + else + *runscript = *argv; + opts[INTERACTIVE] &= 1; + argv++; + } + while (*argv) + zaddlinknode(paramlist, ztrdup(*argv++)); + } else if (!cmd) + opts[SHINSTDIN] = 1; + if(isset(SINGLECOMMAND)) + opts[INTERACTIVE] &= 1; + opts[INTERACTIVE] = !!opts[INTERACTIVE]; + if (opts[MONITOR] == 2) + opts[MONITOR] = opts[INTERACTIVE]; + if (opts[HASHDIRS] == 2) + opts[HASHDIRS] = opts[INTERACTIVE]; + pparams = x = (char **) zshcalloc((countlinknodes(paramlist) + 1) * sizeof(char *)); + + while ((*x++ = (char *)getlinknode(paramlist))); + free(paramlist); + argzero = ztrdup(argzero); +} + +/**/ +mod_export char * +parseopts(char *nam, char ***argvp) +{ + int optionbreak = 0; + int action, optno; + char *cmd = 0; /* deliberately hides static */ + char **argv = *argvp; + +#define WARN_OPTION(F, S) if (nam) zwarnnam(nam, F, S); else zerr(F, S) +#define LAST_OPTION(N) \ + if (nam) { if (*argv) argv++; goto doneargv; } else exit(N) + /* loop through command line options (begins with "-" or "+") */ while (!optionbreak && *argv && (**argv == '-' || **argv == '+')) { char *args = *argv; @@ -267,11 +309,11 @@ parseargs(char **argv, char **runscript) if (!strcmp(*argv, "version")) { printf("zsh %s (%s-%s-%s)\n", ZSH_VERSION, MACHTYPE, VENDOR, OSTYPE); - exit(0); + LAST_OPTION(0); } if (!strcmp(*argv, "help")) { printhelp(); - exit(0); + LAST_OPTION(0); } /* `-' characters are allowed in long options */ for(args = *argv; *args; args++) @@ -292,75 +334,58 @@ parseargs(char **argv, char **runscript) if (!*++*argv) argv++; if (!*argv) { - zerr("string expected after -o"); - exit(1); + WARN_OPTION("string expected after -o", NULL); + LAST_OPTION(1); } longoptions: if (!(optno = optlookup(*argv))) { - zerr("no such option: %s", *argv); - exit(1); - } else if (optno == RESTRICTED) + WARN_OPTION("no such option: %s", *argv); + LAST_OPTION(1); + } else if (optno == RESTRICTED && !nam) { restricted = action; - else - dosetopt(optno, action, 1); + } else if ((optno == EMACSMODE || optno == VIMODE) && nam) { + WARN_OPTION("can't change option: %s", *argv); + } else if (dosetopt(optno, action, !nam) && nam) { + WARN_OPTION("can't change option: %s", *argv); + } break; } else if (isspace(STOUC(**argv))) { /* zsh's typtab not yet set, have to use ctype */ while (*++*argv) if (!isspace(STOUC(**argv))) { - badoptionstring: - zerr("bad option string: `%s'", args); - exit(1); + badoptionstring: + WARN_OPTION("bad option string: '%s'", args); + LAST_OPTION(1); } break; } else { if (!(optno = optlookupc(**argv))) { - zerr("bad option: -%c", **argv); - exit(1); - } else if (optno == RESTRICTED) + WARN_OPTION("bad option: -%c", **argv); + LAST_OPTION(1); + } else if (optno == RESTRICTED && !nam) { restricted = action; - else - dosetopt(optno, action, 1); + } else if ((optno == EMACSMODE || optno == VIMODE) && nam) { + WARN_OPTION("can't change option: %s", *argv); + } else if (dosetopt(optno, action, !nam) && nam) { + WARN_OPTION("can't change option: -%c", **argv); + } } } argv++; } - doneoptions: - paramlist = znewlinklist(); + doneoptions: if (cmd) { if (!*argv) { - zerr("string expected after -%s", cmd); - exit(1); + WARN_OPTION("string expected after -%s", cmd); + LAST_OPTION(1); } cmd = *argv++; } - if (*argv) { - if (unset(SHINSTDIN)) { - if (cmd) - argzero = *argv; - else - *runscript = *argv; - opts[INTERACTIVE] &= 1; - argv++; - } - while (*argv) - zaddlinknode(paramlist, ztrdup(*argv++)); - } else if (!cmd) - opts[SHINSTDIN] = 1; - if(isset(SINGLECOMMAND)) - opts[INTERACTIVE] &= 1; - opts[INTERACTIVE] = !!opts[INTERACTIVE]; - if (opts[MONITOR] == 2) - opts[MONITOR] = opts[INTERACTIVE]; - if (opts[HASHDIRS] == 2) - opts[HASHDIRS] = opts[INTERACTIVE]; - pparams = x = (char **) zshcalloc((countlinknodes(paramlist) + 1) * sizeof(char *)); - - while ((*x++ = (char *)getlinknode(paramlist))); - free(paramlist); - argzero = ztrdup(argzero); + doneargv: + *argvp = argv; + return cmd; } - + /**/ static void printhelp(void) diff --git a/Src/jobs.c b/Src/jobs.c index 94d25bb85..c9c549e1e 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -716,17 +716,22 @@ printtime(struct timeval *real, child_times_t *ti, char *desc) #endif #ifdef HAVE_STRUCT_RUSAGE_RU_IXRSS case 'X': - fprintf(stderr, "%ld", (long)(ti->ru_ixrss / total_time)); + fprintf(stderr, "%ld", + total_time ? + (long)(ti->ru_ixrss / total_time) : + (long)0); break; #endif #ifdef HAVE_STRUCT_RUSAGE_RU_IDRSS case 'D': fprintf(stderr, "%ld", + total_time ? (long) ((ti->ru_idrss #ifdef HAVE_STRUCT_RUSAGE_RU_ISRSS + ti->ru_isrss #endif - ) / total_time)); + ) / total_time) : + (long)0); break; #endif #if defined(HAVE_STRUCT_RUSAGE_RU_IDRSS) || \ @@ -735,6 +740,7 @@ printtime(struct timeval *real, child_times_t *ti, char *desc) case 'K': /* treat as D if X not available */ fprintf(stderr, "%ld", + total_time ? (long) (( #ifdef HAVE_STRUCT_RUSAGE_RU_IXRSS ti->ru_ixrss @@ -747,7 +753,8 @@ printtime(struct timeval *real, child_times_t *ti, char *desc) #ifdef HAVE_STRUCT_RUSAGE_RU_ISRSS + ti->ru_isrss #endif - ) / total_time)); + ) / total_time) : + (long)0); break; #endif #ifdef HAVE_STRUCT_RUSAGE_RU_MAXRSS @@ -2157,10 +2164,15 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func)) /* check for, and interpret, a signal specifier */ if (*argv && **argv == '-') { - if (idigit((*argv)[1])) + if (idigit((*argv)[1])) { + char *endp; /* signal specified by number */ - sig = atoi(*argv + 1); - else if ((*argv)[1] != '-' || (*argv)[2]) { + sig = zstrtol(*argv + 1, &endp, 10); + if (*endp) { + zwarnnam(nam, "invalid signal number: %s", *argv); + return 1; + } + } else if ((*argv)[1] != '-' || (*argv)[2]) { char *signame; /* with argument "-l" display the list of signal names */ diff --git a/Src/options.c b/Src/options.c index 5fbb06b11..c6db75372 100644 --- a/Src/options.c +++ b/Src/options.c @@ -523,6 +523,20 @@ emulate(const char *zsh_name, int fully) if (fully) emulation |= EMULATE_FULLY; installemulation(); + + if (funcstack && funcstack->tp == FS_FUNC) { + /* + * We are inside a function. Decide if it's traced. + * Pedantic note: the function in the function table isn't + * guaranteed to be what we're executing, but it's + * close enough. + */ + Shfunc shf = (Shfunc)shfunctab->getnode(shfunctab, funcstack->name); + if (shf && (shf->node.flags & PM_TAGGED)) { + /* Tracing is on, so set xtrace */ + opts[XTRACE] = 1; + } + } } /* setopt, unsetopt */ @@ -753,6 +767,8 @@ dosetopt(int optno, int value, int force) return -1; #endif /* GETPWNAM_FAKED */ } else if ((optno == EMACSMODE || optno == VIMODE) && value) { + if (sticky_emulation) + return -1; zleentry(ZLE_CMD_SET_KEYMAP, optno); opts[(optno == EMACSMODE) ? VIMODE : EMACSMODE] = 0; } else if (optno == SUNKEYBOARDHACK) { diff --git a/Src/params.c b/Src/params.c index 59d5daf2f..8649178ef 100644 --- a/Src/params.c +++ b/Src/params.c @@ -315,7 +315,7 @@ IPDEF4("LINENO", &lineno), IPDEF4("PPID", &ppid), IPDEF4("ZSH_SUBSHELL", &zsh_subshell), -#define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(varinteger_gsu),10,0,NULL,NULL,NULL,0} +#define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0} IPDEF5("COLUMNS", &zterm_columns, zlevar_gsu), IPDEF5("LINES", &zterm_lines, zlevar_gsu), IPDEF5("OPTIND", &zoptind, varinteger_gsu), @@ -698,16 +698,18 @@ createparamtable(void) * So allow the user to set it in the special cases where it's * useful. */ - setsparam("TMPPREFIX", ztrdup(DEFAULT_TMPPREFIX)); - setsparam("TIMEFMT", ztrdup(DEFAULT_TIMEFMT)); - setsparam("WATCHFMT", ztrdup(default_watchfmt)); + setsparam("TMPPREFIX", ztrdup_metafy(DEFAULT_TMPPREFIX)); + setsparam("TIMEFMT", ztrdup_metafy(DEFAULT_TIMEFMT)); + setsparam("WATCHFMT", ztrdup_metafy(default_watchfmt)); hostnam = (char *)zalloc(256); gethostname(hostnam, 256); - setsparam("HOST", ztrdup(hostnam)); + setsparam("HOST", ztrdup_metafy(hostnam)); zfree(hostnam, 256); - setsparam("LOGNAME", ztrdup((str = getlogin()) && *str ? str : cached_username)); + setsparam("LOGNAME", + ztrdup_metafy((str = getlogin()) && *str ? + str : cached_username)); #if !defined(HAVE_PUTENV) && !defined(USE_SET_UNSET_ENV) /* Copy the environment variables we are inheriting to dynamic * @@ -778,22 +780,22 @@ createparamtable(void) if(uname(&unamebuf)) setsparam("CPUTYPE", ztrdup("unknown")); else { - machinebuf = ztrdup(unamebuf.machine); + machinebuf = ztrdup_metafy(unamebuf.machine); setsparam("CPUTYPE", machinebuf); } - + #else - setsparam("CPUTYPE", ztrdup("unknown")); + setsparam("CPUTYPE", ztrdup_metafy("unknown")); #endif - setsparam("MACHTYPE", ztrdup(MACHTYPE)); - setsparam("OSTYPE", ztrdup(OSTYPE)); - setsparam("TTY", ztrdup(ttystrname)); - setsparam("VENDOR", ztrdup(VENDOR)); - setsparam("ZSH_NAME", ztrdup(zsh_name)); - setsparam("ZSH_VERSION", ztrdup(ZSH_VERSION)); - setsparam("ZSH_PATCHLEVEL", ztrdup(ZSH_PATCHLEVEL)); + setsparam("MACHTYPE", ztrdup_metafy(MACHTYPE)); + setsparam("OSTYPE", ztrdup_metafy(OSTYPE)); + setsparam("TTY", ztrdup_metafy(ttystrname)); + setsparam("VENDOR", ztrdup_metafy(VENDOR)); + setsparam("ZSH_NAME", ztrdup_metafy(zsh_name)); + setsparam("ZSH_VERSION", ztrdup_metafy(ZSH_VERSION)); + setsparam("ZSH_PATCHLEVEL", ztrdup_metafy(ZSH_PATCHLEVEL)); setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *))); - for (t = sigs; (*sigptr++ = ztrdup(*t++)); ); + for (t = sigs; (*sigptr++ = ztrdup_metafy(*t++)); ); noerrs = 0; } @@ -1903,6 +1905,18 @@ fetchvalue(Value v, char **pptr, int bracks, int flags) if (!bracks && *s) return NULL; *pptr = s; +#if 0 + /* + * Check for large subscripts that might be erroneous. + * This code is too gross in several ways: + * - the limit is completely arbitrary + * - the test vetoes operations on existing arrays + * - it's not at all clear a general test on large arrays of + * this kind is any use. + * + * Until someone comes up with workable replacement code it's + * therefore commented out. + */ if (v->start > MAX_ARRLEN) { zerr("subscript too %s: %d", "big", v->start + !isset(KSHARRAYS)); return NULL; @@ -1919,6 +1933,7 @@ fetchvalue(Value v, char **pptr, int bracks, int flags) zerr("subscript too %s: %d", "small", v->end); return NULL; } +#endif return v; } @@ -3454,18 +3469,104 @@ tiedarrunsetfn(Param pm, UNUSED(int exp)) /**/ static void -arrayuniq(char **x, int freeok) +simple_arrayuniq(char **x, int freeok) { char **t, **p = x; + char *hole = ""; + /* Find duplicates and replace them with holes */ while (*++p) for (t = x; t < p; t++) - if (!strcmp(*p, *t)) { + if (*t != hole && !strcmp(*p, *t)) { if (freeok) zsfree(*p); - for (t = p--; (*t = t[1]) != NULL; t++); + *p = hole; break; } + /* Swap non-holes into holes in optimal jumps */ + for (p = t = x; *t != NULL; t++) { + if (*t == hole) { + while (*p == hole) + ++p; + if ((*t = *p) != NULL) + *p++ = hole; + } else if (p == t) + p++; + } + /* Erase all the remaining holes, just in case */ + while (++t < p) + *t = NULL; +} + +/**/ +static void +arrayuniq_freenode(HashNode hn) +{ + (void)hn; +} + +/**/ +HashTable +newuniqtable(zlong size) +{ + HashTable ht = newhashtable((int)size, "arrayuniq", NULL); + /* ??? error checking */ + + ht->hash = hasher; + ht->emptytable = emptyhashtable; + ht->filltable = NULL; + ht->cmpnodes = strcmp; + ht->addnode = addhashnode; + ht->getnode = gethashnode2; + ht->getnode2 = gethashnode2; + ht->removenode = removehashnode; + ht->disablenode = disablehashnode; + ht->enablenode = enablehashnode; + ht->freenode = arrayuniq_freenode; + ht->printnode = NULL; + + return ht; +} + +/**/ +static void +arrayuniq(char **x, int freeok) +{ + char **it, **write_it; + zlong array_size = arrlen(x); + HashTable ht; + + if (array_size == 0) + return; + if (array_size < 10 || !(ht = newuniqtable(array_size + 1))) { + /* fallback to simpler routine */ + simple_arrayuniq(x, freeok); + return; + } + + for (it = x, write_it = x; *it;) { + if (! gethashnode2(ht, *it)) { + HashNode new_node = zhalloc(sizeof(struct hashnode)); + if (!new_node) { + /* Oops, out of heap memory, no way to recover */ + zerr("out of memory in arrayuniq"); + break; + } + (void) addhashnode2(ht, *it, new_node); + *write_it = *it; + if (it != write_it) + *it = NULL; + ++write_it; + } + else { + if (freeok) + zsfree(*it); + *it = NULL; + } + ++it; + } + + deletehashtable(ht); } /**/ diff --git a/Src/prompt.c b/Src/prompt.c index d15b7c0d4..e51ce2451 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -663,12 +663,20 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) break; case 'L': addbufspc(DIGBUFSIZE); +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + sprintf(bv->bp, "%lld", shlvl); +#else sprintf(bv->bp, "%ld", (long)shlvl); +#endif bv->bp += strlen(bv->bp); break; case '?': addbufspc(DIGBUFSIZE); +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + sprintf(bv->bp, "%lld", lastval); +#else sprintf(bv->bp, "%ld", (long)lastval); +#endif bv->bp += strlen(bv->bp); break; case '%': @@ -764,7 +772,11 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) if (funcstack->tp == FS_EVAL) lineno--; addbufspc(DIGBUFSIZE); +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + sprintf(bv->bp, "%lld", flineno); +#else sprintf(bv->bp, "%ld", (long)flineno); +#endif bv->bp += strlen(bv->bp); break; } @@ -772,7 +784,11 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) /* FALLTHROUGH */ case 'i': addbufspc(DIGBUFSIZE); +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + sprintf(bv->bp, "%lld", lineno); +#else sprintf(bv->bp, "%ld", (long)lineno); +#endif bv->bp += strlen(bv->bp); break; case 'x': diff --git a/Src/subst.c b/Src/subst.c index b9229861b..932f41287 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1649,7 +1649,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * This is one of the things that decides whether multsub * will produce an array, but in an extremely indirect fashion. */ - int nojoin = (pf_flags & PREFORK_SHWORDSPLIT) ? !(ifs && *ifs) : 0; + int nojoin = (pf_flags & PREFORK_SHWORDSPLIT) ? !(ifs && *ifs) && !qt : 0; /* * != 0 means ${...}, otherwise $... What works without braces * is largely a historical artefact (everything works with braces, @@ -1828,6 +1828,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) quotemod = 1; quotetype = QT_SINGLE_OPTIONAL; } else { + if (quotetype == QT_SINGLE_OPTIONAL) { + /* extra q's after '-' not allowed */ + goto flagerr; + } quotemod++, quotetype++; } break; @@ -2872,6 +2876,69 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } break; } + } else if (inbrace && (*s == '|' || *s == Bar || + *s == '*' || *s == Star)) { + int intersect = (*s == '*' || *s == Star); + char **compare, **ap, **apsrc; + ++s; + if (*itype_end(s, IIDENT, 0)) { + untokenize(s); + zerr("not an identifier: %s", s); + return NULL; + } + compare = getaparam(s); + if (compare) { + HashTable ht = newuniqtable(arrlen(compare)+1); + int present; + for (ap = compare; *ap; ap++) + (void)addhashnode2(ht, *ap, (HashNode) + zhalloc(sizeof(struct hashnode))); + if (!vunset && isarr) { + if (!copied) { + aval = arrdup(aval); + copied = 1; + } + for (ap = apsrc = aval; *apsrc; apsrc++) { + untokenize(*apsrc); + present = (gethashnode2(ht, *apsrc) != NULL); + if (intersect ? present : !present) { + if (ap != apsrc) { + *ap = *apsrc; + } + ap++; + } + } + *ap = NULL; + } else { + if (vunset) { + if (unset(UNSET)) { + *idend = '\0'; + zerr("%s: parameter not set", idbeg); + deletehashtable(ht); + return NULL; + } + val = dupstring(""); + } else { + present = (gethashnode2(ht, val) != NULL); + if (intersect ? !present : present) + val = dupstring(""); + } + } + deletehashtable(ht); + } else if (intersect) { + /* + * The intersection with nothing is nothing... + * Seems a bit pointless complaining that the first + * expression is unset here if the second is, too. + */ + if (!vunset) { + if (isarr) { + aval = mkarray(NULL); + } else { + val = dupstring(""); + } + } + } } else { /* no ${...=...} or anything, but possible modifiers. */ /* * Handler ${+...}. TODO: strange, why do we handle this only diff --git a/Src/utils.c b/Src/utils.c index 014cb2fa2..d35ca1dfd 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -275,9 +275,13 @@ zerrmsg(FILE *file, const char *fmt, va_list ap) #endif char *errmsg; - if ((unset(SHINSTDIN) || locallevel) && lineno) + if ((unset(SHINSTDIN) || locallevel) && lineno) { +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + fprintf(file, "%lld: ", lineno); +#else fprintf(file, "%ld: ", (long)lineno); - else +#endif + } else fputc((unsigned char)' ', file); while (*fmt) @@ -1682,7 +1686,7 @@ adjustwinsize(int from) (shttyinfo.winsize.ws_row != ttyrows || shttyinfo.winsize.ws_col != ttycols)) { /* shttyinfo.winsize is already set up correctly */ - ioctl(SHTTY, TIOCSWINSZ, (char *)&shttyinfo.winsize); + /* ioctl(SHTTY, TIOCSWINSZ, (char *)&shttyinfo.winsize); */ } #endif /* TIOCGWINSZ */ @@ -3110,7 +3114,7 @@ wordcount(char *s, char *sep, int mul) r = 1; sl = strlen(sep); for (; (c = findsep(&s, sep, 0)) >= 0; s += sl) - if ((c && *(s + sl)) || mul) + if ((c || mul) && (sl || *(s + sl))) r++; } else { char *t = s; @@ -4009,6 +4013,28 @@ metafy(char *buf, int len, int heap) /* + * Duplicate a string, metafying it as we go. + * + * Typically, this is used only for strings imported from outside + * zsh, as strings internally are either already metafied or passed + * around with an associated length. + */ +/**/ +mod_export char * +ztrdup_metafy(const char *s) +{ + /* To mimic ztrdup() behaviour */ + if (!s) + return NULL; + /* + * metafy() does lots of different things, so the pointer + * isn't const. Using it with META_DUP should be safe. + */ + return metafy((char *)s, -1, META_DUP); +} + + +/* * Take a null-terminated, metafied string in s into a literal * representation by converting in place. The length is in *len * len is non-NULL; if len is NULL, you don't know the length of @@ -4709,7 +4735,7 @@ quotestring(const char *s, char **e, int instring) char *v; int alloclen; char *buf; - int sf = 0, shownull; + int sf = 0, shownull = 0; /* * quotesub is used with QT_SINGLE_OPTIONAL. * quotesub = 0: mechanism not active @@ -4724,14 +4750,12 @@ quotestring(const char *s, char **e, int instring) const char *uend; slen = strlen(s); - if (instring == QT_BACKSLASH_SHOWNULL) { - shownull = 1; - instring = QT_BACKSLASH; - } else { - shownull = 0; - } switch (instring) { + case QT_BACKSLASH_SHOWNULL: + shownull = 1; + instring = QT_BACKSLASH; + /*FALLTHROUGH*/ case QT_BACKSLASH: /* * With QT_BACKSLASH we may need to use $'\300' stuff. @@ -4739,22 +4763,23 @@ quotestring(const char *s, char **e, int instring) * storage and using heap for correct size at end. */ alloclen = slen * 7 + 1; - if (!*s && shownull) - alloclen += 2; /* for '' */ break; case QT_SINGLE_OPTIONAL: /* * Here, we may need to add single quotes. + * Always show empty strings. */ alloclen = slen * 4 + 3; - quotesub = 1; + quotesub = shownull = 1; break; default: alloclen = slen * 4 + 1; break; } + if (!*s && shownull) + alloclen += 2; /* for '' */ quotestart = v = buf = zshcalloc(alloclen); diff --git a/Src/zsh_system.h b/Src/zsh_system.h index f38533023..f20a7bb90 100644 --- a/Src/zsh_system.h +++ b/Src/zsh_system.h @@ -874,3 +874,7 @@ extern short ospeed; # endif # endif #endif + +#ifdef TGOTO_PROTO_MISSING +char *tgoto(const char *cap, int col, int row); +#endif |