From 93e72ed1e9ef573e3bb9cd95d67233df46d33973 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 2 Jun 2015 09:17:04 +0100 Subject: 35353: print -x and print -X expand tabs --- Src/utils.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'Src/utils.c') diff --git a/Src/utils.c b/Src/utils.c index 271c800fd..7409dc876 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4964,6 +4964,108 @@ metacharlenconv(const char *x, int *c) /**/ #endif /* MULTIBYTE_SUPPORT */ +/* + * Expand tabs to given width, with given starting position on line. + * len is length of unmetafied string in bytes. + * Output to fout. + * Return the end position on the line, i.e. if this is 0 modulo width + * the next character is aligned with a tab stop. + * + * If all is set, all tabs are expanded, else only leading tabs. + */ + +/**/ +mod_export int +zexpandtabs(const char *s, int len, int width, int startpos, FILE *fout, + int all) +{ + int at_start = 1; + +#ifdef MULTIBYTE_SUPPORT + mbstate_t mbs; + size_t ret; + wchar_t wc; + + memset(&mbs, 0, sizeof(mbs)); +#endif + + while (len) { + if (*s == '\t') { + if (all || at_start) { + s++; + len--; + if (width <= 0 || !(startpos % width)) { + /* always output at least one space */ + fputc(' ', fout); + startpos++; + } + if (width <= 0) + continue; /* paranoia */ + while (startpos % width) { + fputc(' ', fout); + startpos++; + } + } else { + /* + * Leave tab alone. + * Guess width to apply... we might get this wrong. + * This is only needed if there's a following string + * that needs tabs expanding, which is unusual. + */ + startpos += width - startpos % width; + s++; + len--; + fputc('\t', fout); + } + continue; + } else if (*s == '\n' || *s == '\r') { + fputc(*s, fout); + s++; + len--; + startpos = 0; + at_start = 1; + continue; + } + + at_start = 0; +#ifdef MULTIBYTE_SUPPORT + if (isset(MULTIBYTE)) { + const char *sstart = s; + ret = mbrtowc(&wc, s, len, &mbs); + if (ret == MB_INVALID) { + /* Assume single character per character */ + memset(&mbs, 0, sizeof(mbs)); + s++; + len--; + } else if (ret == MB_INCOMPLETE) { + /* incomplete at end --- assume likewise, best we've got */ + s++; + len--; + } else { + s += ret; + len -= (int)ret; + } + if (ret == MB_INVALID || ret == MB_INCOMPLETE) { + startpos++; + } else { + int wcw = WCWIDTH(wc); + if (wcw > 0) /* paranoia */ + startpos += wcw; + } + fwrite(sstart, s - sstart, 1, fout); + + continue; + } +#endif /* MULTIBYTE_SUPPORT */ + fputc(*s, fout); + s++; + len--; + startpos++; + } + + return startpos; +} + /* check for special characters in the string */ /**/ -- cgit v1.2.3 From 2abba7243a736a2fc626f3cc917d8a67014d4d20 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 5 Jun 2015 11:21:22 +0100 Subject: 35386: expand tabs where useful in builtins outputing function. Also add to zed -f. Option is -x . --- ChangeLog | 8 ++++++ Doc/Zsh/builtins.yo | 25 ++++++++++++++---- Doc/Zsh/contrib.yo | 9 ++++--- Functions/Misc/zed | 17 +++++++++--- Src/builtin.c | 50 ++++++++++++++++++++++++++---------- Src/hashtable.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++------ Src/pattern.c | 13 +++------- Src/text.c | 46 +++++++++++++++++++++++++++++++-- Src/utils.c | 43 ++++++++++++++++++++++++++++--- Src/zsh.h | 9 ++++--- 10 files changed, 243 insertions(+), 51 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 24ec700f9..b6c233d8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2015-06-05 Peter Stephenson + + * 35386: Doc/Zsh/builtins.yo, Doc/Zsh/contrib.yo, + Functions/Misc/zed, Src/builtin.c, Src/hashtable.c, + Src/pattern.c, Src/text.c, Src/utils.c, Src/zsh.h: + expand tabs for function output in functions, whence, where, + which and also zed -f using -x num option. + 2015-06-03 Oliver Kiddle * 35360 (replacing 35357): configure.ac, Src/Modules/zpty.c: diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 6fa603ac8..53b668214 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -791,11 +791,18 @@ Equivalent to tt(typeset -E), except that options irrelevant to floating point numbers are not permitted. ) findex(functions) -xitem(tt(functions) [ {tt(PLUS())|tt(-)}tt(UkmtTuz) ] [ var(name) ... ]) +xitem(tt(functions) [ {tt(PLUS())|tt(-)}tt(UkmtTuz) ] [ tt(-x) var(num) ] [ var(name) ... ]) xitem(tt(functions -M) var(mathfn) [ var(min) [ var(max) [ var(shellfn) ] ] ]) xitem(tt(functions -M) [ tt(-m) var(pattern) ... ]) item(tt(functions +M) [ tt(-m) ] var(mathfn) ... )( -Equivalent to tt(typeset -f), with the exception of the tt(-M) option. +Equivalent to tt(typeset -f), with the exception of the tt(-x) and +tt(-M) options. + +The tt(-x) option indicates that any functions output will have +each leading tab for indentation, added by the shell to show syntactic +structure, expanded to the given number var(num) of spaces. var(num) +can also be 0 to suppress all indentation. + Use of the tt(-M) option may not be combined with any of the options handled by tt(typeset -f). @@ -1927,6 +1934,9 @@ function is first referenced; see noderef(Functions). The tt(-k) and tt(-z) flags make the function be loaded using ksh-style or zsh-style autoloading respectively. If neither is given, the setting of the tt(KSH_AUTOLOAD) option determines how the function is loaded. + +Note that the builtin tt(functions) provides the same basic capabilities +as tt(typeset -f) but gives access to a few extra options. ) item(tt(-h))( Hide: only useful for special parameters (those marked `' in the table in @@ -2180,7 +2190,7 @@ the user is potentially interested in both, so this problem is intrinsic to process IDs. ) findex(whence) -item(tt(whence) [ tt(-vcwfpamsS) ] var(name) ...)( +item(tt(whence) [ tt(-vcwfpamsS) ] [ tt(-x) var(num) ] var(name) ...)( For each var(name), indicate how it would be interpreted if used as a command name. @@ -2233,14 +2243,19 @@ As tt(-s), but if the pathname had to be resolved by following multiple symlinks, the intermediate steps are printed, too. The symlink resolved at each step might be anywhere in the path. ) +item(tt(-x) var(num))( +Expand tabs when outputting shell functions using the tt(-c) option. +This has the same effect as the tt(-x) option to the tt(functions) +builtin. +) enditem() ) findex(where) -item(tt(where) [ tt(-wpmsS) ] var(name) ...)( +item(tt(where) [ tt(-wpmsS) ] [ tt(-x) var(num) ] var(name) ...)( Equivalent to tt(whence -ca). ) findex(which) -item(tt(which) [ tt(-wpamsS) ] var(name) ...)( +item(tt(which) [ tt(-wpamsS) ] [ tt(-x) var(num) ] var(name) ...)( Equivalent to tt(whence -c). ) findex(zcompile) diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 8b6b7d3b7..323bf0f9a 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -3561,7 +3561,7 @@ set to the ANSI terminal escapes that turn off all attributes and turn on bold intensity, respectively. ) findex(fned) -item(tt(fned) var(name))( +item(tt(fned) [ tt(-x) var(num) ] var(name))( Same as tt(zed -f). This function does not appear in the zsh distribution, but can be created by linking tt(zed) to the name tt(fned) in some directory in your tt(fpath). @@ -3749,7 +3749,7 @@ the difference in function between tt(zargs) and tt(xargs)) or run tt(zargs) with the tt(-)tt(-help) option. ) findex(zed) -xitem(tt(zed) [ tt(-f) ] var(name)) +xitem(tt(zed) [ tt(-f) [ tt(-x) var(num) ] var(name)) item(tt(zed -b))( This function uses the ZLE editor to edit a file or function. @@ -3758,7 +3758,10 @@ If the tt(-f) option is given, the name is taken to be that of a function; if the function is marked for autoloading, tt(zed) searches for it in the tt(fpath) and loads it. Note that functions edited this way are installed into the current shell, but em(not) written back to the -autoload file. +autoload file. In this case the tt(-x) option specifies that leading +tabs indenting the function according to syntax should be converted into +the given number of spaces; `tt(-x 2)' is consistent with the layout +of functions distributed with the shell. Without tt(-f), var(name) is the path name of the file to edit, which need not exist; it is created on write, if necessary. diff --git a/Functions/Misc/zed b/Functions/Misc/zed index c2caaf3f5..010b69bee 100644 --- a/Functions/Misc/zed +++ b/Functions/Misc/zed @@ -9,8 +9,9 @@ local var opt zed_file_name # We do not want timeout while we are editing a file integer TMOUT=0 okargs=1 fun bind +local -a expand -while getopts "fb" opt; do +while getopts "fbx:" opt; do case $opt in (f) fun=1 @@ -19,6 +20,14 @@ while getopts "fb" opt; do (b) bind=1 ;; + + (x) + if [[ $OPTARG != <-> ]]; then + print -r "Integer expected after -x: $OPTARG" >&2 + return 1 + fi + expand=(-x $OPTARG) + ;; esac done shift $(( OPTIND - 1 )) @@ -29,8 +38,8 @@ shift $(( OPTIND - 1 )) if (( $# != okargs )); then echo 'Usage: zed filename -zed -f function -zed -b' +zed -f [ -x N ] function +zed -b' >&2 return 1 fi @@ -71,7 +80,7 @@ fi setopt localoptions nobanghist if ((fun)) then - var="$(functions $1)" + var="$(functions $expand $1)" # If function is undefined but autoloadable, load it if [[ $var = *\#\ undefined* ]] then var="$(autoload +X $1; functions $1)" diff --git a/Src/builtin.c b/Src/builtin.c index 4b081468d..0d1d00ec3 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -72,7 +72,7 @@ static struct builtin builtins[] = BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W", NULL), BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL), BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"), - BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtTuUz", NULL), + BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtTuUx:z", NULL), BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"), BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL), BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "Ldfmrv", NULL), @@ -128,9 +128,9 @@ static struct builtin builtins[] = BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fmv", NULL), BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL), BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL), - BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSw", NULL), - BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsSw", "ca"), - BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsSw", "c"), + BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSwx:", NULL), + BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsSwx:", "ca"), + BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsSwx:", "c"), BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilmpue", NULL), BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL), }; @@ -2749,7 +2749,7 @@ bin_functions(char *name, char **argv, Options ops, int func) Patprog pprog; Shfunc shf; int i, returnval = 0; - int on = 0, off = 0, pflags = 0, roff; + int on = 0, off = 0, pflags = 0, roff, expand = 0; /* Do we have any flags defined? */ if (OPT_PLUS(ops,'u')) @@ -2785,11 +2785,23 @@ bin_functions(char *name, char **argv, Options ops, int func) } if ((off & PM_UNDEFINED) || (OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) || + (OPT_ISSET(ops,'x') && !OPT_HASARG(ops,'x')) || (OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || *argv || !scriptname))) { zwarnnam(name, "invalid option(s)"); return 1; } + if (OPT_ISSET(ops,'x')) { + char *eptr; + expand = (int)zstrtol(OPT_ARG(ops,'x'), &eptr, 10); + if (*eptr) { + zwarnnam(name, "number expected after -x"); + return 1; + } + if (expand == 0) /* no indentation at all */ + expand = -1; + } + if (OPT_PLUS(ops,'f') || roff || OPT_ISSET(ops,'+')) pflags |= PRINT_NAMEONLY; @@ -2948,8 +2960,8 @@ bin_functions(char *name, char **argv, Options ops, int func) } else { if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u')) on &= ~PM_UNDEFINED; - scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode, - pflags); + scanshfunc(1, on|off, DISABLED, shfunctab->printnode, + pflags, expand); } unqueue_signals(); return ret; @@ -2965,8 +2977,8 @@ bin_functions(char *name, char **argv, Options ops, int func) /* with no options, just print all functions matching the glob pattern */ queue_signals(); if (!(on|off) && !OPT_ISSET(ops,'X')) { - scanmatchtable(shfunctab, pprog, 1, 0, DISABLED, - shfunctab->printnode, pflags); + scanmatchshfunc(pprog, 1, 0, DISABLED, + shfunctab->printnode, pflags, expand); } else { /* apply the options to all functions matching the glob pattern */ for (i = 0; i < shfunctab->hsize; i++) { @@ -3008,7 +3020,7 @@ bin_functions(char *name, char **argv, Options ops, int func) returnval = 1; } else /* no flags, so just print */ - shfunctab->printnode(&shf->node, pflags); + printshfuncexpand(&shf->node, pflags, expand); } else if (on & PM_UNDEFINED) { int signum = -1, ok = 1; @@ -3222,6 +3234,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) int aliasflags; int csh, all, v, wd; int informed = 0; + int expand = 0; char *cnam, **allmatched = 0; /* Check some option information */ @@ -3230,6 +3243,17 @@ bin_whence(char *nam, char **argv, Options ops, int func) all = OPT_ISSET(ops,'a'); wd = OPT_ISSET(ops,'w'); + if (OPT_ISSET(ops,'x')) { + char *eptr; + expand = (int)zstrtol(OPT_ARG(ops,'x'), &eptr, 10); + if (*eptr) { + zwarnnam(nam, "number expected after -x"); + return 1; + } + if (expand == 0) /* no indentation at all */ + expand = -1; + } + if (OPT_ISSET(ops,'w')) printflags |= PRINT_WHENCE_WORD; else if (OPT_ISSET(ops,'c')) @@ -3286,8 +3310,8 @@ bin_whence(char *nam, char **argv, Options ops, int func) /* and shell functions... */ informed += - scanmatchtable(shfunctab, pprog, 1, 0, DISABLED, - shfunctab->printnode, printflags); + scanmatchshfunc(pprog, 1, 0, DISABLED, + shfunctab->printnode, printflags, expand); /* and builtins. */ informed += @@ -3342,7 +3366,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) } /* Look for shell function */ if ((hn = shfunctab->getnode(shfunctab, *argv))) { - shfunctab->printnode(hn, printflags); + printshfuncexpand(hn, printflags, expand); informed = 1; if (!all) continue; diff --git a/Src/hashtable.c b/Src/hashtable.c index ab381cc6a..2b5524999 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -937,13 +937,17 @@ printshfuncnode(HashNode hn, int printflags) quotedzputs(f->node.nam, stdout); if (f->funcdef || f->node.flags & PM_UNDEFINED) { - printf(" () {\n\t"); - if (f->node.flags & PM_UNDEFINED) - printf("%c undefined\n\t", hashchar); - else + printf(" () {\n"); + zoutputtab(stdout); + if (f->node.flags & PM_UNDEFINED) { + printf("%c undefined\n", hashchar); + zoutputtab(stdout); + } else t = getpermtext(f->funcdef, NULL, 1); - if (f->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL)) - printf("%c traced\n\t", hashchar); + if (f->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL)) { + printf("%c traced\n", hashchar); + zoutputtab(stdout); + } if (!t) { char *fopt = "UtTkz"; int flgs[] = { @@ -959,11 +963,12 @@ printshfuncnode(HashNode hn, int printflags) zputs(t, stdout); zsfree(t); if (f->funcdef->flags & EF_RUN) { - printf("\n\t"); + printf("\n"); + zoutputtab(stdout); quotedzputs(f->node.nam, stdout); printf(" \"$@\""); } - } + } printf("\n}"); } else { printf(" () { }"); @@ -979,6 +984,59 @@ printshfuncnode(HashNode hn, int printflags) putchar('\n'); } +/* + * Wrap scanmatchtable for shell functions with optional + * expansion of leading tabs. + * expand = 0 is standard: use hard tabs. + * expand > 0 uses that many spaces. + * expand < 0 uses no identation. + * + * Note this function and the following two are called with + * interrupts queued, so saving and restoring text_expand_tabs + * is safe. + */ + +/**/ +mod_export int +scanmatchshfunc(Patprog pprog, int sorted, int flags1, int flags2, + ScanFunc scanfunc, int scanflags, int expand) +{ + int ret, save_expand; + + save_expand = text_expand_tabs; + text_expand_tabs = expand; + ret = scanmatchtable(shfunctab, pprog, sorted, flags1, flags2, + scanfunc, scanflags); + text_expand_tabs = save_expand; + + return ret; +} + +/* Wrap scanhashtable to expand tabs for shell functions */ + +/**/ +mod_export int +scanshfunc(int sorted, int flags1, int flags2, + ScanFunc scanfunc, int scanflags, int expand) +{ + return scanmatchshfunc(NULL, sorted, flags1, flags2, + scanfunc, scanflags, expand); +} + +/* Wrap shfunctab->printnode to expand tabs */ + +/**/ +mod_export void +printshfuncexpand(HashNode hn, int printflags, int expand) +{ + int save_expand; + + save_expand = text_expand_tabs; + text_expand_tabs = expand; + shfunctab->printnode(hn, printflags); + text_expand_tabs = save_expand; +} + /**************************************/ /* Reserved Word Hash Table Functions */ /**************************************/ diff --git a/Src/pattern.c b/Src/pattern.c index 4e5e8a110..7e07548f9 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -2202,20 +2202,15 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, if ((patglobflags & GF_MATCHREF) && !(patflags & PAT_FILE)) { char *str = ztrduppfx(patinstart, patinlen); - char *ptr = patinstart; - int mlen = 0; + int mlen; /* * Count the characters. We're not using CHARSUB() - * because the string is still metafied. We're - * not using mb_metastrlen() because that expects - * the string to be null terminated. + * because the string is still metafied. */ MB_METACHARINIT(); - while (ptr < patinstart + patinlen) { - mlen++; - ptr += MB_METACHARLEN(ptr); - } + mlen = MB_METASTRLEN2END(patinstart, 0, + patinstart + patinlen); setsparam("MATCH", str); setiparam("MBEGIN", diff --git a/Src/text.c b/Src/text.c index 958303c68..850879699 100644 --- a/Src/text.c +++ b/Src/text.c @@ -30,6 +30,16 @@ #include "zsh.mdh" #include "text.pro" +/* + * If non-zero, expand syntactically significant leading tabs in text + * to this number of spaces. + * + * If negative, don't output leading whitespace at all. + */ + +/**/ +int text_expand_tabs; + static char *tptr, *tbuf, *tlim, *tpending; static int tsiz, tindent, tnewlins, tjob; @@ -156,8 +166,16 @@ taddnl(int no_semicolon) if (tnewlins) { tdopending(); taddchr('\n'); - for (t0 = 0; t0 != tindent; t0++) - taddchr('\t'); + for (t0 = 0; t0 != tindent; t0++) { + if (text_expand_tabs >= 0) { + if (text_expand_tabs) { + int t1; + for (t1 = 0; t1 < text_expand_tabs; t1++) + taddchr(' '); + } else + taddchr('\t'); + } + } } else if (no_semicolon) { taddstr(" "); } else { @@ -165,6 +183,30 @@ taddnl(int no_semicolon) } } +/* + * Output a tab that may be expanded as part of a leading set. + * Note this is not part of the text framework; it's for + * code that needs to output its own tabs that are to be + * consistent with those from getpermtext(). + * + * Note these tabs are only expected to be useful at the + * start of the line, so we make no attempt to count columns. + */ + +/**/ +void +zoutputtab(FILE *outf) +{ + if (text_expand_tabs < 0) + return; + if (text_expand_tabs) { + int i; + for (i = 0; i < text_expand_tabs; i++) + fputc(' ', outf); + } else + fputc('\t', outf); +} + /* get a permanent textual representation of n */ /**/ diff --git a/Src/utils.c b/Src/utils.c index 7409dc876..c33c16d5a 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4471,9 +4471,37 @@ ztrlen(char const *s) for (l = 0; *s; l++) { if (*s++ == Meta) { #ifdef DEBUG - if (! *s) + if (! *s) { fprintf(stderr, "BUG: unexpected end of string in ztrlen()\n"); - else + break; + } else +#endif + s++; + } + } + return l; +} + +#ifndef MULTIBYTE_SUPPORT +/* + * ztrlen() but with explicit end point for non-null-terminated + * segments. eptr may not be NULL. + */ + +/**/ +mod_export int +ztrlenend(char const *s, char const *eptr) +{ + int l; + + for (l = 0; s < eptr; l++) { + if (*s++ == Meta) { +#ifdef DEBUG + if (! *s) { + fprintf(stderr, + "BUG: unexpected end of string in ztrlenend()\n"); + break; + } else #endif s++; } @@ -4481,6 +4509,8 @@ ztrlen(char const *s) return l; } +#endif /* MULTIBYTE_SUPPORT */ + /* Subtract two pointers in a metafied string. */ /**/ @@ -4879,11 +4909,16 @@ mb_metacharlenconv(const char *s, wint_t *wcp) * If width is 1, return total character width rather than number. * If width is greater than 1, return 1 if character has non-zero width, * else 0. + * + * Ends if either *ptr is '\0', the normal case (eptr may be NULL for + * this), or ptr is eptr (i.e. *eptr is where the null would be if null + * terminated) for strings not delimited by nulls --- note these are + * still metafied. */ /**/ mod_export int -mb_metastrlen(char *ptr, int width) +mb_metastrlenend(char *ptr, int width, char *eptr) { char inchar, *laststart; size_t ret; @@ -4898,7 +4933,7 @@ mb_metastrlen(char *ptr, int width) num = num_in_char = 0; memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); - while (*ptr) { + while (*ptr && !(eptr && ptr >= eptr)) { if (*ptr == Meta) inchar = *++ptr ^ 32; else diff --git a/Src/zsh.h b/Src/zsh.h index f6e08e28d..c88c2e739 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2926,9 +2926,11 @@ enum { typedef wint_t convchar_t; #define MB_METACHARLENCONV(str, cp) mb_metacharlenconv((str), (cp)) #define MB_METACHARLEN(str) mb_metacharlenconv(str, NULL) -#define MB_METASTRLEN(str) mb_metastrlen(str, 0) -#define MB_METASTRWIDTH(str) mb_metastrlen(str, 1) -#define MB_METASTRLEN2(str, widthp) mb_metastrlen(str, widthp) +#define MB_METASTRLEN(str) mb_metastrlenend(str, 0, NULL) +#define MB_METASTRWIDTH(str) mb_metastrlenend(str, 1, NULL) +#define MB_METASTRLEN2(str, widthp) mb_metastrlenend(str, widthp, NULL) +#define MB_METASTRLEN2END(str, widthp, eptr) \ + mb_metastrlenend(str, widthp, eptr) /* * We replace broken implementations with one that uses Unicode @@ -3011,6 +3013,7 @@ typedef int convchar_t; #define MB_METASTRLEN(str) ztrlen(str) #define MB_METASTRWIDTH(str) ztrlen(str) #define MB_METASTRLEN2(str, widthp) ztrlen(str) +#define MB_METASTRLEN2END(str, widthp, eptr) ztrlenend(str, eptr) #define WCWIDTH_WINT(c) (1) -- cgit v1.2.3 From f1923bdfa6300a0d32e3329eb2488447f76b8970 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 12 Jun 2015 09:30:39 +0100 Subject: Add non-metafied character length handling. Use this in regex module and add test using $'\ua0'. Rename mb_metacharinit() to mb_charinit() as it does not involve metafied characters. --- ChangeLog | 10 ++++++ Src/Modules/curses.c | 2 +- Src/Modules/regex.c | 33 +++++++++++++------ Src/Zle/complist.c | 2 +- Src/Zle/zle_utils.c | 2 +- Src/builtin.c | 4 +-- Src/glob.c | 14 ++++---- Src/hist.c | 2 +- Src/prompt.c | 2 +- Src/utils.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++---- Src/zsh.h | 12 ++++++- Test/D07multibyte.ztst | 13 ++++++++ 12 files changed, 154 insertions(+), 31 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 4f96800b6..5b45e5e8f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2015-06-12 Peter Stephenson + + * 35448: Src/Modules/curses.c, Src/Modules/regex.c, + Src/Zle/complist.c, Src/Zle/zle_utils.c, Src/builtin.c, + Src/glob.c, Src/hist.c, Src/prompt.c, Src/utils.c, Src/zsh.h, + Test/D07multibyte.ztst: Add non-metafied character length + handling and use this for regex module. Add test. + Rename mb_metacharinit() to mb_charinit() since it doesn't + involve metafied characters. + 2015-06-11 Peter Stephenson * 35442: Doc/Zsh/options.yo: multibyte option now on diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c index 41ad2c6e4..62dbd55ea 100644 --- a/Src/Modules/curses.c +++ b/Src/Modules/curses.c @@ -765,7 +765,7 @@ zccmd_string(const char *nam, char **args) w = (ZCWin)getdata(node); #ifdef HAVE_WADDWSTR - mb_metacharinit(); + mb_charinit(); wptr = wstr = zhalloc((strlen(str)+1) * sizeof(wchar_t)); while (*str && (clen = mb_metacharlenconv(str, &wc))) { diff --git a/Src/Modules/regex.c b/Src/Modules/regex.c index ce57de986..94f523f32 100644 --- a/Src/Modules/regex.c +++ b/Src/Modules/regex.c @@ -115,6 +115,7 @@ zcond_regex_match(char **a, int id) } else { zlong offs; char *ptr; + int clen, leftlen; m = matches; s = metafy(lhstr + m->rm_so, m->rm_eo - m->rm_so, META_DUP); @@ -123,19 +124,25 @@ zcond_regex_match(char **a, int id) * Count the characters before the match. */ ptr = lhstr; + leftlen = m->rm_so; offs = 0; - MB_METACHARINIT(); - while (ptr < lhstr + m->rm_so) { + MB_CHARINIT(); + while (leftlen) { offs++; - ptr += MB_METACHARLEN(ptr); + clen = MB_CHARLEN(ptr, leftlen); + ptr += clen; + leftlen -= clen; } setiparam("MBEGIN", offs + !isset(KSHARRAYS)); /* * Add on the characters in the match. */ - while (ptr < lhstr + m->rm_eo) { + leftlen = m->rm_eo - m->rm_so; + while (leftlen) { offs++; - ptr += MB_METACHARLEN(ptr); + clen = MB_CHARLEN(ptr, leftlen); + ptr += clen; + leftlen -= clen; } setiparam("MEND", offs + !isset(KSHARRAYS) - 1); if (nelem) { @@ -149,19 +156,25 @@ zcond_regex_match(char **a, int id) { char buf[DIGBUFSIZE]; ptr = lhstr; + leftlen = m->rm_so; offs = 0; /* Find the start offset */ - MB_METACHARINIT(); - while (ptr < lhstr + m->rm_so) { + MB_CHARINIT(); + while (leftlen) { offs++; - ptr += MB_METACHARLEN(ptr); + clen = MB_CHARLEN(ptr, leftlen); + ptr += clen; + leftlen -= clen; } convbase(buf, offs + !isset(KSHARRAYS), 10); *bptr = ztrdup(buf); /* Continue to the end offset */ - while (ptr < lhstr + m->rm_eo) { + leftlen = m->rm_eo - m->rm_so; + while (leftlen ) { offs++; - ptr += MB_METACHARLEN(ptr); + clen = MB_CHARLEN(ptr, leftlen); + ptr += clen; + leftlen -= clen; } convbase(buf, offs + !isset(KSHARRAYS) - 1, 10); *eptr = ztrdup(buf); diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index f54206619..a02a5c37b 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -728,7 +728,7 @@ clnicezputs(int do_colors, char *s, int ml) if (do_colors) initiscol(); - mb_metacharinit(); + mb_charinit(); while (umleft > 0) { size_t cnt = eol ? MB_INVALID : mbrtowc(&cc, uptr, umleft, &mbs); diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index e4ab97a54..06e458190 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1288,7 +1288,7 @@ showmsg(char const *msg) p = unmetafy(umsg, &ulen); memset(&mbs, 0, sizeof mbs); - mb_metacharinit(); + mb_charinit(); while (ulen > 0) { char const *n; if (*p == '\n') { diff --git a/Src/builtin.c b/Src/builtin.c index a3d847f41..0edc07024 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -4582,7 +4582,7 @@ bin_print(char *name, char **args, Options ops, int func) convchar_t cc; #ifdef MULTIBYTE_SUPPORT if (isset(MULTIBYTE)) { - mb_metacharinit(); + mb_charinit(); (void)mb_metacharlenconv(metafy(curarg+1, curlen-1, META_USEHEAP), &cc); } @@ -5557,7 +5557,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func)) wint_t wi; if (isset(MULTIBYTE)) { - mb_metacharinit(); + mb_charinit(); (void)mb_metacharlenconv(delimstr, &wi); } else diff --git a/Src/glob.c b/Src/glob.c index 057d44a17..eff34a24e 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2237,7 +2237,7 @@ xpandbraces(LinkList list, LinkNode *np) #ifdef MULTIBYTE_SUPPORT char *ncptr; int nclen; - mb_metacharinit(); + mb_charinit(); ncptr = wcs_nicechar(cend, NULL, NULL); nclen = strlen(ncptr); p = zhalloc(lenalloc + nclen); @@ -2805,7 +2805,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, * ... now we know whether it's worth looking for the * shortest, which we do by brute force. */ - mb_metacharinit(); + mb_charinit(); for (t = s, umlen = 0; t < s + mlen; ) { set_pat_end(p, *t); if (pattrylen(p, s, t - s, umlen, 0)) { @@ -2831,7 +2831,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, * so that match, mbegin, mend and MATCH, MBEGIN, MEND are * correct. */ - mb_metacharinit(); + mb_charinit(); tmatch = NULL; for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) { set_pat_start(p, t-s); @@ -2855,7 +2855,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, /* Largest possible match at tail of string: * * move forward along string until we get a match. * * Again there's no optimisation. */ - mb_metacharinit(); + mb_charinit(); for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) { set_pat_start(p, t-s); if (pattrylen(p, t, s + l - t, umlen, ioff)) { @@ -2889,7 +2889,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, } ioff = 0; /* offset into string */ umlen = umltot; - mb_metacharinit(); + mb_charinit(); do { /* loop over all matches for global substitution */ matched = 0; @@ -2986,7 +2986,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, */ nmatches = 0; tmatch = NULL; - mb_metacharinit(); + mb_charinit(); for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) { set_pat_start(p, t-s); if (pattrylen(p, t, s + l - t, umlen, ioff)) { @@ -3002,7 +3002,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, * We need to find the n'th last match. */ n = nmatches - n; - mb_metacharinit(); + mb_charinit(); for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) { set_pat_start(p, t-s); if (pattrylen(p, t, s + l - t, umlen, ioff) && diff --git a/Src/hist.c b/Src/hist.c index bd03c4f11..672531394 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -2000,7 +2000,7 @@ casemodify(char *str, int how) VARARR(char, mbstr, MB_CUR_MAX); mbstate_t ps; - mb_metacharinit(); + mb_charinit(); memset(&ps, 0, sizeof(ps)); while (*str) { wint_t wc; diff --git a/Src/prompt.c b/Src/prompt.c index ffc1d0df2..9e8589d5b 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -964,7 +964,7 @@ stradd(char *d) /* FALL THROUGH */ default: /* Take full wide character in one go */ - mb_metacharinit(); + mb_charinit(); pc = wcs_nicechar(cc, NULL, NULL); break; } diff --git a/Src/utils.c b/Src/utils.c index c33c16d5a..13fc96a16 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -82,7 +82,7 @@ set_widearray(char *mb_array, Widechar_array wca) wchar_t *wcptr = tmpwcs; wint_t wci; - mb_metacharinit(); + mb_charinit(); while (*mb_array) { int mblen = mb_metacharlenconv(mb_array, &wci); @@ -332,7 +332,7 @@ zerrmsg(FILE *file, const char *fmt, va_list ap) case 'c': num = va_arg(ap, int); #ifdef MULTIBYTE_SUPPORT - mb_metacharinit(); + mb_charinit(); zputs(wcs_nicechar(num, NULL, NULL), file); #else zputs(nicechar(num), file); @@ -461,12 +461,13 @@ static mbstate_t mb_shiftstate; /* * Initialise multibyte state: called before a sequence of - * wcs_nicechar() or mb_metacharlenconv(). + * wcs_nicechar(), mb_metacharlenconv(), or + * mb_charlenconv(). */ /**/ mod_export void -mb_metacharinit(void) +mb_charinit(void) { memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); } @@ -500,7 +501,7 @@ mb_metacharinit(void) * (but not both). (Note the complication that the wide character * part may contain metafied characters.) * - * The caller needs to call mb_metacharinit() before the first call, to + * The caller needs to call mb_charinit() before the first call, to * set up the multibyte shift state for a range of characters. */ @@ -3832,7 +3833,7 @@ itype_end(const char *ptr, int itype, int once) #ifdef MULTIBYTE_SUPPORT if (isset(MULTIBYTE) && (itype != IIDENT || !isset(POSIXIDENTIFIERS))) { - mb_metacharinit(); + mb_charinit(); while (*ptr) { wint_t wc; int len = mb_metacharlenconv(ptr, &wc); @@ -4972,6 +4973,65 @@ mb_metastrlenend(char *ptr, int width, char *eptr) return num + num_in_char; } +/* + * The equivalent of mb_metacharlenconv_r() for + * strings that aren't metafied and hence have + * explicit lengths. + */ + +/**/ +mod_export int +mb_charlenconv_r(const char *s, int slen, wint_t *wcp, mbstate_t *mbsp) +{ + size_t ret = MB_INVALID; + char inchar; + const char *ptr; + wchar_t wc; + + for (ptr = s; slen; ) { + inchar = *ptr; + ptr++; + slen--; + ret = mbrtowc(&wc, &inchar, 1, mbsp); + + if (ret == MB_INVALID) + break; + if (ret == MB_INCOMPLETE) + continue; + if (wcp) + *wcp = wc; + return ptr - s; + } + + if (wcp) + *wcp = WEOF; + /* No valid multibyte sequence */ + memset(mbsp, 0, sizeof(*mbsp)); + if (ptr > s) { + return 1; /* Treat as single byte character */ + } else + return 0; /* Probably shouldn't happen */ +} + +/* + * The equivalent of mb_metacharlenconv() for + * strings that aren't metafied and hence have + * explicit lengths; + */ + +/**/ +mod_export int +mb_charlenconv(const char *s, int slen, wint_t *wcp) +{ + if (!isset(MULTIBYTE)) { + if (wcp) + *wcp = (wint_t)*s; + return 1; + } + + return mb_charlenconv_r(s, slen, wcp, &mb_shiftstate); +} + /**/ #else @@ -4996,6 +5056,23 @@ metacharlenconv(const char *x, int *c) return 1; } +/* Simple replacement for mb_charlenconv */ + +/**/ +mod_export int +charlenconv(const char *x, int len, int *c) +{ + if (!len) { + if (c) + *c = '\0'; + return 0; + } + + if (c) + *c = (char)*x; + return 1; +} + /**/ #endif /* MULTIBYTE_SUPPORT */ diff --git a/Src/zsh.h b/Src/zsh.h index c88c2e739..fb04929d9 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2921,8 +2921,9 @@ enum { #define AFTERTRAPHOOK (zshhooks + 2) #ifdef MULTIBYTE_SUPPORT +/* Metafied input */ #define nicezputs(str, outs) (void)mb_niceformat((str), (outs), NULL, 0) -#define MB_METACHARINIT() mb_metacharinit() +#define MB_METACHARINIT() mb_charinit() typedef wint_t convchar_t; #define MB_METACHARLENCONV(str, cp) mb_metacharlenconv((str), (cp)) #define MB_METACHARLEN(str) mb_metacharlenconv(str, NULL) @@ -2932,6 +2933,11 @@ typedef wint_t convchar_t; #define MB_METASTRLEN2END(str, widthp, eptr) \ mb_metastrlenend(str, widthp, eptr) +/* Unmetafined input */ +#define MB_CHARINIT() mb_charinit() +#define MB_CHARLENCONV(str, len, cp) mb_charlenconv((str), (len), (cp)) +#define MB_CHARLEN(str, len) mb_charlenconv((str), (len), NULL) + /* * We replace broken implementations with one that uses Unicode * characters directly as wide characters. In principle this is only @@ -3015,6 +3021,10 @@ typedef int convchar_t; #define MB_METASTRLEN2(str, widthp) ztrlen(str) #define MB_METASTRLEN2END(str, widthp, eptr) ztrlenend(str, eptr) +#define MB_CHARINIT() +#define MB_CHARLENCONV(str, len, cp) charlenconv((str), (len), (cp)) +#define MB_CHARLEN(str, len) ((len) ? 1 : 0) + #define WCWIDTH_WINT(c) (1) /* Leave character or string as is. */ diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst index c9ecb78e9..5f9e8abcf 100644 --- a/Test/D07multibyte.ztst +++ b/Test/D07multibyte.ztst @@ -484,3 +484,16 @@ # This doesn't look aligned in my editor because actually the characters # aren't quite double width, but the arithmetic is correct. # It appears just to be an effect of the font. + + if zmodload -i zsh/regex 2>/dev/null; then + [[ $'\ua0' =~ '^.$' ]] && print OK + [[ $'\ua0' =~ $'^\ua0$' ]] && print OK + [[ $'\ua0'X =~ '^X$' ]] || print OK + else + print -u$ZTST_fd "Regexp test skipped, regexp library not found." + print -l OK OK OK + fi +0:Ensure no confusion on metafied input to regex module +>OK +>OK +>OK -- cgit v1.2.3 From e402747dd6450cafaf1ca6c01671a5adf1595d02 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Thu, 9 Jul 2015 11:51:57 +0200 Subject: 35745: ztrftime: Pass everything unhandled to the system strftime() --- ChangeLog | 5 ++++ Src/utils.c | 79 +++++++++++++++++++++++++++++++++++---------------- Test/V09datetime.ztst | 63 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 25 deletions(-) create mode 100644 Test/V09datetime.ztst (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 5dcc1e266..d36a73639 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-07-09 Mikael Magnusson + + * 35745: Src/utils.c, Test/V09datetime.ztst: ztrftime: Pass + everything unhandled to the system strftime() + 2015-07-09 Oliver Kiddle * 35748: Completion/Zsh/Type/_ps1234, diff --git a/Src/utils.c b/Src/utils.c index 13fc96a16..8ff575fd9 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2883,7 +2883,7 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) int hr12; #ifdef HAVE_STRFTIME int decr; - char tmp[4]; + char *fmtstart; #else static char *astr[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; @@ -2899,7 +2899,11 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) int strip; int digs = 3; +#ifdef HAVE_STRFTIME + fmtstart = +#endif fmt++; + if (*fmt == '-') { strip = 1; fmt++; @@ -2924,6 +2928,21 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) */ if (ztrftimebuf(&bufsize, 2)) return -1; +#ifdef HAVE_STRFTIME + /* Our internal handling doesn't handle padding and other gnu extensions, + * so here we detect them and pass over to strftime(). We don't want + * to do this unconditionally though, as we have some extensions that + * strftime() doesn't have (%., %f, %L and %K) */ +morefmt: + if (!((fmt - fmtstart == 1) || (fmt - fmtstart == 2 && strip) || *fmt == '.')) { + while (*fmt && strchr("OE^#_-0123456789", *fmt)) + fmt++; + if (*fmt) { + fmt++; + goto strftimehandling; + } + } +#endif switch (*fmt++) { case '.': if (ztrftimebuf(&bufsize, digs)) @@ -2939,10 +2958,10 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) sprintf(buf, "%0*ld", digs, usec); buf += digs; break; - case 'd': - if (tm->tm_mday > 9 || !strip) - *buf++ = '0' + tm->tm_mday / 10; - *buf++ = '0' + tm->tm_mday % 10; + case '\0': + /* Guard against premature end of string */ + *buf++ = '%'; + fmt--; break; case 'f': strip = 1; @@ -2983,6 +3002,12 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) *buf++ = '0' + (hr12 % 10); break; +#ifndef HAVE_STRFTIME + case 'd': + if (tm->tm_mday > 9 || !strip) + *buf++ = '0' + tm->tm_mday / 10; + *buf++ = '0' + tm->tm_mday % 10; + break; case 'm': if (tm->tm_mon > 8 || !strip) *buf++ = '0' + (tm->tm_mon + 1) / 10; @@ -3003,18 +3028,8 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) *buf++ = '0' + (tm->tm_year / 10) % 10; *buf++ = '0' + tm->tm_year % 10; break; - case '\0': - /* Guard against premature end of string */ - *buf++ = '%'; - fmt--; - break; -#ifndef HAVE_STRFTIME case 'Y': { - /* - * Not worth handling this natively if - * strftime has it. - */ int year, digits, testyear; year = tm->tm_year + 1900; digits = 1; @@ -3048,24 +3063,38 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) if (fmt[-1] != '%') *buf++ = fmt[-1]; #else + case 'E': + case 'O': + case '^': + case '#': + case '_': + case '-': + case '0' ... '9': + goto morefmt; +strftimehandling: default: /* * Remember we've already allowed for two characters * in the accounting in bufsize (but nowhere else). */ - *buf = '\1'; - sprintf(tmp, strip ? "%%-%c" : "%%%c", fmt[-1]); - if (!strftime(buf, bufsize + 2, tmp, tm)) { - if (*buf) { - buf[0] = '\0'; - return -1; + int size = fmt - fmtstart; + char *tmp = zhalloc(size + 1); + strncpy(tmp, fmtstart, size); + tmp[size] = '\0'; + *buf = '\1'; + if (!strftime(buf, bufsize + 2, tmp, tm)) + { + if (*buf) { + buf[0] = '\0'; + return -1; + } + return 0; } - return 0; + decr = strlen(buf); + buf += decr; + bufsize -= decr - 2; } - decr = strlen(buf); - buf += decr; - bufsize -= decr - 2; #endif break; } diff --git a/Test/V09datetime.ztst b/Test/V09datetime.ztst new file mode 100644 index 000000000..c69e31ed5 --- /dev/null +++ b/Test/V09datetime.ztst @@ -0,0 +1,63 @@ +%prep + + if ! (zmodload zsh/datetime >/dev/null 2>/dev/null); then + ZTST_unimplemented="can't load the zsh/datetime module for testing" + fi + setopt multibyte + zmodload zsh/datetime + unset LC_ALL + LC_TIME=C + if [[ "$(strftime %04y 1)" = "0070" ]]; then + [[ "$(LC_TIME=ja_JP.UTF-8 strftime %OS 1)" = 一 ]] || { + print -u $ZTST_fd "Not testing alternate date format extensions (missing ja_JP.UTF-8 locale)" + skip_japanese=1 + } + else + print -u $ZTST_fd "Skipping strftime extension tests" + skip_extensions=1 + fi + +%test + + strftime %y 0 + strftime %Y 1000000000 + strftime %x 1200000000 + strftime %X 1200000001 +0:basic format specifiers +>70 +>2001 +>01/10/08 +>22:20:01 + + strftime %-m_%f_%K_%L 1181000000 + strftime %6. 0 +0:zsh extensions +>6_5_1_1 +>000000 + + [[ $skip_japanese = 1 ]] && repeat 5; do echo skipped; done || ( + LC_TIME=ja_JP.UTF-8 + strftime %Ey 1000000000 + strftime %Oy 1000000000 + strftime %Ex 1000000000 + strftime %OS 1000000000 + strftime %03Ey 650000000 + ) +0:alternate format extensions +*>skipped|13 +>skipped|一 +>skipped|平成13年09月09日 +>skipped|四十 +>skipped|002 + + [[ $skip_extensions = 1 ]] && repeat 4; do echo skipped; done || ( + strftime '%#A' 0 + strftime '%^_10B' 0 + strftime %03Ey 650000000 + strftime %-Oe 0 + ) +0:various extensions +*>skipped|THURSDAY +>skipped| JANUARY +>skipped|090 +>skipped|1 -- cgit v1.2.3 From a1f8d4ffc73293e0461c01ff005194a474854376 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Wed, 22 Jul 2015 12:52:24 -0700 Subject: 35826: add getsparam_u() to return unmetafied string, use it for a number of references to non-special params --- ChangeLog | 5 +++++ Src/Modules/newuser.c | 2 +- Src/Modules/zftp.c | 6 +++--- Src/Zle/complist.c | 4 ++-- Src/Zle/zle_misc.c | 4 ++-- Src/init.c | 2 +- Src/params.c | 23 ++++++++++++++++------- Src/utils.c | 10 +++++++--- Src/watch.c | 2 +- 9 files changed, 38 insertions(+), 20 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 90babd20e..0b631c1a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2015-07-22 Barton E. Schaefer + * 35826: Src/Modules/newuser.c, Src/Modules/zftp.c, + Src/Zle/complist.c, Src/Zle/zle_misc.c, Src/init.c, Src/params.c, + Src/utils.c, Src/watch.c: add getsparam_u() to return unmetafied + string, use it for a number of references to non-special params + * 35823: Functions/Zle/narrow-to-region: fix handling of MARK and CURSOR, clean up documentary comment diff --git a/Src/Modules/newuser.c b/Src/Modules/newuser.c index 71902da7d..efdb2abba 100644 --- a/Src/Modules/newuser.c +++ b/Src/Modules/newuser.c @@ -67,7 +67,7 @@ check_dotfile(const char *dotdir, const char *fname) int boot_(UNUSED(Module m)) { - const char *dotdir = getsparam("ZDOTDIR"); + const char *dotdir = getsparam_u("ZDOTDIR"); const char *spaths[] = { #ifdef SITESCRIPT_DIR SITESCRIPT_DIR, diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index 09d4bd703..30f517658 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -731,7 +731,7 @@ zfgetmsg(void) stopit = (*ptr++ != '-'); queue_signals(); - if (!(verbose = getsparam("ZFTP_VERBOSE"))) + if (!(verbose = getsparam_u("ZFTP_VERBOSE"))) verbose = ""; if (strchr(verbose, lastcodestr[0])) { /* print the whole thing verbatim */ @@ -1785,7 +1785,7 @@ zftp_open(char *name, char **args, int flags) char *hname; alarm(0); queue_signals(); - if ((hname = getsparam("ZFTP_HOST")) && *hname) + if ((hname = getsparam_u("ZFTP_HOST")) && *hname) zwarnnam(name, "timeout connecting to %s", hname); else zwarnnam(name, "timeout on host name lookup"); @@ -3077,7 +3077,7 @@ bin_zftp(char *name, char **args, UNUSED(Options ops), UNUSED(int func)) } queue_signals(); - if ((prefs = getsparam("ZFTP_PREFS"))) { + if ((prefs = getsparam_u("ZFTP_PREFS"))) { zfprefs = 0; for (ptr = prefs; *ptr; ptr++) { switch (toupper(STOUC(*ptr))) { diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index f37a43231..fd90ccb31 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -507,8 +507,8 @@ getcols() max_caplen = lr_caplen = 0; mcolors.flags = 0; queue_signals(); - if (!(s = getsparam("ZLS_COLORS")) && - !(s = getsparam("ZLS_COLOURS"))) { + if (!(s = getsparam_u("ZLS_COLORS")) && + !(s = getsparam_u("ZLS_COLOURS"))) { for (i = 0; i < NUM_COLS; i++) mcolors.files[i] = filecol(""); mcolors.pats = NULL; diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index d350688a7..556ce5ba6 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -1552,13 +1552,13 @@ makesuffix(int n) { char *suffixchars; - if (!(suffixchars = getsparam("ZLE_REMOVE_SUFFIX_CHARS"))) + if (!(suffixchars = getsparam_u("ZLE_REMOVE_SUFFIX_CHARS"))) suffixchars = " \t\n;&|"; addsuffixstring(SUFTYP_POSSTR, 0, suffixchars, n); /* Do this second so it takes precedence */ - if ((suffixchars = getsparam("ZLE_SPACE_SUFFIX_CHARS")) && *suffixchars) + if ((suffixchars = getsparam_u("ZLE_SPACE_SUFFIX_CHARS")) && *suffixchars) addsuffixstring(SUFTYP_POSSTR, SUFFLAGS_SPACE, suffixchars, n); suffixlen = n; diff --git a/Src/init.c b/Src/init.c index 0fe4d758c..2ef90992d 100644 --- a/Src/init.c +++ b/Src/init.c @@ -1426,7 +1426,7 @@ sourcehome(char *s) char *h; queue_signals(); - if (EMULATION(EMULATE_SH|EMULATE_KSH) || !(h = getsparam("ZDOTDIR"))) { + if (EMULATION(EMULATE_SH|EMULATE_KSH) || !(h = getsparam_u("ZDOTDIR"))) { h = home; if (!h) return; diff --git a/Src/params.c b/Src/params.c index 312fa9ae1..00f43e47d 100644 --- a/Src/params.c +++ b/Src/params.c @@ -2639,6 +2639,15 @@ getsparam(char *s) return getstrvalue(v); } +/**/ +mod_export char * +getsparam_u(char *s) +{ + if ((s = getsparam(s))) + return unmetafy(s, NULL); + return s; +} + /* Retrieve an array parameter */ /**/ @@ -3971,7 +3980,7 @@ setlang(char *x) struct localename *ln; char *x2; - if ((x2 = getsparam("LC_ALL")) && *x2) + if ((x2 = getsparam_u("LC_ALL")) && *x2) return; /* @@ -3985,10 +3994,10 @@ setlang(char *x) * from this is meaningless. So just all $LANG to show through in * that case. */ - setlocale(LC_ALL, x ? x : ""); + setlocale(LC_ALL, x ? unmeta(x) : ""); queue_signals(); for (ln = lc_names; ln->name; ln++) - if ((x = getsparam(ln->name)) && *x) + if ((x = getsparam_u(ln->name)) && *x) setlocale(ln->category, x); unqueue_signals(); } @@ -4004,7 +4013,7 @@ lc_allsetfn(Param pm, char *x) * that with any LC_* that are set. */ if (!x || !*x) { - x = getsparam("LANG"); + x = getsparam_u("LANG"); if (x && *x) { queue_signals(); setlang(x); @@ -4012,7 +4021,7 @@ lc_allsetfn(Param pm, char *x) } } else - setlocale(LC_ALL, x); + setlocale(LC_ALL, unmeta(x)); } /**/ @@ -4020,7 +4029,7 @@ void langsetfn(Param pm, char *x) { strsetfn(pm, x); - setlang(x); + setlang(unmeta(x)); } /**/ @@ -4046,7 +4055,7 @@ lcsetfn(Param pm, char *x) if (x && *x) { for (ln = lc_names; ln->name; ln++) if (!strcmp(ln->name, pm->node.nam)) - setlocale(ln->category, x); + setlocale(ln->category, unmeta(x)); } unqueue_signals(); } diff --git a/Src/utils.c b/Src/utils.c index 8ff575fd9..ba9056459 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -248,7 +248,7 @@ VA_DCL VA_START(ap, message); VA_GET_ARG(ap, message, const char *); - if ((filename = getsparam("ZSH_DEBUG_LOG")) != NULL && + if ((filename = getsparam_u("ZSH_DEBUG_LOG")) != NULL && (file = fopen(filename, "a")) != NULL) { zerrmsg(file, message, ap); fclose(file); @@ -1949,7 +1949,8 @@ extern char *_mktemp(char *); /* Get a unique filename for use as a temporary file. If "prefix" is * NULL, the name is relative to $TMPPREFIX; If it is non-NULL, the * unique suffix includes a prefixed '.' for improved readability. If - * "use_heap" is true, we allocate the returned name on the heap. */ + * "use_heap" is true, we allocate the returned name on the heap. + * The string passed as "prefix" is expected to be metafied. */ /**/ mod_export char * @@ -1976,6 +1977,9 @@ gettempname(const char *prefix, int use_heap) return ret; } +/* The gettempfile() "prefix" is expected to be metafied, see hist.c + * and gettempname(). */ + /**/ mod_export int gettempfile(const char *prefix, int use_heap, char **tempname) @@ -3585,7 +3589,7 @@ zbeep(void) { char *vb; queue_signals(); - if ((vb = getsparam("ZBEEP"))) { + if ((vb = getsparam_u("ZBEEP"))) { int len; vb = getkeystring(vb, &len, GETKEYS_BINDKEY, NULL); write_loop(SHTTY, vb, len); diff --git a/Src/watch.c b/Src/watch.c index fe409f91a..e1bdaa4a0 100644 --- a/Src/watch.c +++ b/Src/watch.c @@ -566,7 +566,7 @@ dowatch(void) return; } queue_signals(); - if (!(fmt = getsparam("WATCHFMT"))) + if (!(fmt = getsparam_u("WATCHFMT"))) fmt = DEFAULT_WATCHFMT; while ((uct || wct) && !errflag) if (!uct || (wct && ucmp(uptr, wptr) > 0)) -- cgit v1.2.3 From bbd4cae6ad3dc52702e61397cbab9197e55b21b5 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 23 Jul 2015 10:04:09 +0100 Subject: 35872: protect against NULL pointers in unmeta --- ChangeLog | 2 ++ Src/utils.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index dbdb22319..418d922ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2015-07-23 Peter Stephenson + * 35872: Src/utils.c: protect against NULL pointers in unmeta(). + * 35849: Src/exec.c, Src/jobs.c, Test/D03procsubst.ztst: close file descriptors from process substitution in parent after fork. diff --git a/Src/utils.c b/Src/utils.c index ba9056459..0acab88ff 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4401,7 +4401,10 @@ unmeta(const char *file_name) char *p; const char *t; int newsz, meta; - + + if (!file_name) + return NULL; + meta = 0; for (t = file_name; *t; t++) { if (*t == Meta) -- cgit v1.2.3 From dd8079e0415cf213d9bb5d41d1ad95c04b774f3a Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sat, 25 Jul 2015 21:36:54 +0100 Subject: 35809: fix $((...)) completion by _expand widget. This changes internal quoting of the form still including tokens not to add unnecessary internal backslashes. --- ChangeLog | 3 +++ Src/utils.c | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index b74208d2d..899ff08e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-07-25 Peter Stephenson + * 35909: Src/utils.c: fix $((...) completion in _expand by + normalising quoting of the math expression containing tokens. + * 35908: Src/ZLe/zle_tricky.c: fix $((...)) completion by expand-or-complete widget. diff --git a/Src/utils.c b/Src/utils.c index 0acab88ff..f7aaaedf4 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -5551,7 +5551,25 @@ quotestring(const char *s, char **e, int instring) /* Needs to be passed straight through. */ if (dobackslash) *v++ = '\\'; - *v++ = *u++; + if (*u == Inparmath) { + /* + * Already syntactically quoted: don't + * add more. + */ + int inmath = 1; + *v++ = *u++; + for (;;) { + char uc = *u; + *v++ = *u++; + if (uc == '\0') + break; + else if (uc == Outparmath && !--inmath) + break; + else if (uc == Inparmath) + ++inmath; + } + } else + *v++ = *u++; continue; } -- cgit v1.2.3 From d09dc4562a1bd72b923a730dbe837406e4f10ccb Mon Sep 17 00:00:00 2001 From: Jun-ichi Takimoto Date: Sat, 8 Aug 2015 03:39:51 +0900 Subject: 35928: '%-m' should work even if not supported by strftime(3) Also clarify document. --- ChangeLog | 6 ++++++ Doc/Zsh/prompt.yo | 7 ++++--- Src/utils.c | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 337a1f31f..45fc04732 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-08-08 Jun-ichi Takimoto + + * 35928: Src/utils.c, Doc/Zsh/prompt.yo: date/time format such + as '%-m' should work even if strftime(3) doesn't support it. + Also clarify document. + 2015-08-05 Mikael Magnusson * 35989: Completion/Unix/Command/_ssh: update to 6.9 diff --git a/Doc/Zsh/prompt.yo b/Doc/Zsh/prompt.yo index c4e201465..3c8f2a094 100644 --- a/Doc/Zsh/prompt.yo +++ b/Doc/Zsh/prompt.yo @@ -206,9 +206,10 @@ The GNU extension that a `tt(-)' between the tt(%) and the format character causes a leading zero or space to be stripped is handled directly by the shell for the format characters tt(d), tt(f), tt(H), tt(k), tt(l), tt(m), tt(M), tt(S) and tt(y); any other format -characters are provided to tt(strftime+LPAR()RPAR()) with any leading `tt(-)', -present, so the handling is system dependent. Further GNU -extensions are not supported at present. +characters are provided to the system's strftime+LPAR()3RPAR() +with any leading `tt(-)' present, so the handling is system dependent. +Further GNU (or other) extensions are also passed to strftime+LPAR()3RPAR() +and may work if the system supports them. ) enditem() diff --git a/Src/utils.c b/Src/utils.c index f7aaaedf4..236661a9f 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -3006,7 +3006,6 @@ morefmt: *buf++ = '0' + (hr12 % 10); break; -#ifndef HAVE_STRFTIME case 'd': if (tm->tm_mday > 9 || !strip) *buf++ = '0' + tm->tm_mday / 10; @@ -3032,6 +3031,7 @@ morefmt: *buf++ = '0' + (tm->tm_year / 10) % 10; *buf++ = '0' + tm->tm_year % 10; break; +#ifndef HAVE_STRFTIME case 'Y': { int year, digits, testyear; -- cgit v1.2.3 From f8164fb647a8e7947cfde137ddd9517b2fab51c4 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 18 Aug 2015 16:20:48 +0100 Subject: 36227: attempt to fix metafication problem with ztrftime. fmt is treated as metafied on entry; use returned length to ensure we metafy or output the correct length if there are embedded nulls. --- ChangeLog | 6 ++++++ Src/Builtins/sched.c | 3 ++- Src/Modules/datetime.c | 11 +++++++---- Src/Modules/stat.c | 7 +++++-- Src/builtin.c | 7 +++++-- Src/prompt.c | 8 +++++--- Src/utils.c | 30 +++++++++++++++++++++++++++--- Src/watch.c | 5 ++++- 8 files changed, 61 insertions(+), 16 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 2165a9ae3..d0705f8fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2015-08-18 Peter Stephenson + * 36227: Src/Builtins/sched.c, Src/Modules/datetime.c, + Src/Modules/stat.c, Src/builtin.c, Src/prompt.c, Src/utils.c, + Src/watch.c: real fix for metafication problem in ztrftime: + unmetafy fmt on input and metafy return value with correct + length. + * unposted: revert 36222, not the correct fix. * 36222: Src/Modules/datetime.c: unmetafy output from strftime. diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c index bcf7661f4..5d5dac6b7 100644 --- a/Src/Builtins/sched.c +++ b/Src/Builtins/sched.c @@ -220,7 +220,8 @@ bin_sched(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func)) endstr = "-- "; else endstr = ""; - printf("%3d %s %s%s%s\n", sn, tbuf, flagstr, endstr, sch->cmd); + printf("%3d %s %s%s%s\n", sn, tbuf, flagstr, endstr, + unmeta(sch->cmd)); } return 0; } else if (!argptr[1]) { diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c index d9416679f..86c61cf1c 100644 --- a/Src/Modules/datetime.c +++ b/Src/Modules/datetime.c @@ -98,7 +98,7 @@ reverse_strftime(char *nam, char **argv, char *scalar, int quiet) static int output_strftime(char *nam, char **argv, Options ops, UNUSED(int func)) { - int bufsize, x; + int bufsize, x, len; char *endptr = NULL, *scalar = NULL, *buffer; time_t secs; struct tm *t; @@ -131,16 +131,19 @@ output_strftime(char *nam, char **argv, Options ops, UNUSED(int func)) bufsize = strlen(argv[0]) * 8; buffer = zalloc(bufsize); + len = 0; for (x=0; x < 4; x++) { - if (ztrftime(buffer, bufsize, argv[0], t, 0L) >= 0) + if ((len = ztrftime(buffer, bufsize, argv[0], t, 0L)) >= 0) break; buffer = zrealloc(buffer, bufsize *= 2); } + DPUTS(len < 0, "bad output from ztrftime"); if (scalar) { - setsparam(scalar, metafy(buffer, -1, META_DUP)); + setsparam(scalar, metafy(buffer, len, META_DUP)); } else { - printf("%s\n", buffer); + fwrite(buffer, 1, len, stdout); + putchar('\n'); } zfree(buffer, bufsize); diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c index 6fc53894c..396177149 100644 --- a/Src/Modules/stat.c +++ b/Src/Modules/stat.c @@ -197,8 +197,11 @@ stattimeprint(time_t tim, char *outbuf, int flags) } if (flags & STF_STRING) { char *oend = outbuf + strlen(outbuf); - ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) : - localtime(&tim), 0L); + /* Where the heck does "40" come from? */ + int len = ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) : + localtime(&tim), 0L); + if (len > 0) + metafy(oend, len, META_NOALLOC); if (flags & STF_RAW) strcat(oend, ")"); } diff --git a/Src/builtin.c b/Src/builtin.c index 4a97a3163..572a0dd68 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1783,9 +1783,12 @@ fclist(FILE *f, Options ops, zlong first, zlong last, command, if required */ if (tdfmt != NULL) { struct tm *ltm; + int len; ltm = localtime(&ent->stim); - if (ztrftime(timebuf, 256, tdfmt, ltm, 0L)) - fprintf(f, "%s ", timebuf); + if ((len = ztrftime(timebuf, 256, tdfmt, ltm, 0L)) >= 0) { + fwrite(timebuf, 1, len, f); + fprintf(f, " "); + } } /* display the time taken by the command, if required */ if (OPT_ISSET(ops,'D')) { diff --git a/Src/prompt.c b/Src/prompt.c index 9e8589d5b..be067ee7e 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -271,7 +271,7 @@ static int putpromptchar(int doprint, int endchar, unsigned int *txtchangep) { char *ss, *hostnam; - int t0, arg, test, sep, j, numjobs; + int t0, arg, test, sep, j, numjobs, len; struct tm *tm; struct timezone dummy_tz; struct timeval tv; @@ -673,12 +673,14 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) */ for(j = 0, t0 = strlen(tmfmt)*8; j < 3; j++, t0*=2) { addbufspc(t0); - if (ztrftime(bv->bp, t0, tmfmt, tm, tv.tv_usec) >= 0) + if ((len = ztrftime(bv->bp, t0, tmfmt, tm, tv.tv_usec)) + >= 0) break; } /* There is enough room for this because addbufspc(t0) * allocates room for t0 * 2 bytes. */ - metafy(bv->bp, -1, META_NOALLOC); + if (len >= 0) + metafy(bv->bp, len, META_NOALLOC); bv->bp += strlen(bv->bp); zsfree(tmbuf); break; diff --git a/Src/utils.c b/Src/utils.c index 236661a9f..20e01a207 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2878,6 +2878,10 @@ ztrftimebuf(int *bufsizeptr, int decr) * not enough memory --- and return -1. Not guaranteed to be portable, * since the strftime() interface doesn't make any guarantees about * the state of the buffer if it returns zero. + * + * fmt is metafied, but we need to unmetafy it on the fly to + * pass into strftime / combine with the output from strftime. + * The return value in buf is not metafied. */ /**/ @@ -2898,8 +2902,14 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) char *origbuf = buf; - while (*fmt) - if (*fmt == '%') { + while (*fmt) { + if (*fmt == Meta) { + int chr = fmt[1] ^ 32; + if (ztrftimebuf(&bufsize, 1)) + return -1; + *buf++ = chr; + fmt += 2; + } else if (*fmt == '%') { int strip; int digs = 3; @@ -3083,8 +3093,21 @@ strftimehandling: */ { int size = fmt - fmtstart; - char *tmp = zhalloc(size + 1); + char *tmp, *last; + tmp = zhalloc(size + 1); strncpy(tmp, fmtstart, size); + last = fmt-1; + if (*last == Meta) { + /* + * This is for consistency in counting: + * a metafiable character isn't actually + * a valid strftime descriptor. + * + * Previous characters were explicitly checked, + * so can't be metafied. + */ + *last = *++fmt ^ 32; + } tmp[size] = '\0'; *buf = '\1'; if (!strftime(buf, bufsize + 2, tmp, tm)) @@ -3107,6 +3130,7 @@ strftimehandling: return -1; *buf++ = *fmt++; } + } *buf = '\0'; return buf - origbuf; } diff --git a/Src/watch.c b/Src/watch.c index e1bdaa4a0..c804913ad 100644 --- a/Src/watch.c +++ b/Src/watch.c @@ -237,6 +237,7 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini) time_t timet; struct tm *tm; char *fm2; + int len; # ifdef WATCH_UTMP_UT_HOST char *p; int i; @@ -330,7 +331,9 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini) } timet = getlogtime(u, inout); tm = localtime(&timet); - ztrftime(buf, 40, fm2, tm, 0L); + len = ztrftime(buf, 40, fm2, tm, 0L); + if (len > 0) + metafy(buf, len, META_NOALLOC); printf("%s", (*buf == ' ') ? buf + 1 : buf); break; case '%': -- cgit v1.2.3 From 61afb8dc8d75106940ac4248632cb14823a3650e Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 21 Aug 2015 10:04:13 +0100 Subject: 36262: Replace fix for missing unmeta in chdir(). It was needed in the argument to one of a pair of lchdir()s rather than within zchdir(). Add tests for the case of a character with 0x83 within it. --- ChangeLog | 4 ++++ Src/builtin.c | 2 +- Src/compat.c | 11 ++++++++--- Src/utils.c | 13 +++++++++---- Test/D07multibyte.ztst | 12 ++++++++++++ 5 files changed, 34 insertions(+), 8 deletions(-) (limited to 'Src/utils.c') diff --git a/ChangeLog b/ChangeLog index 2975a651c..ace02a203 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2015-08-21 Peter Stephenson + * 36262: Src/builin.c, Src/compat.c, Src/utils.c, + Test/D07multibyte.ztst: replace 36232: the unmeta() + was needed at a place higher up. Add test. + * 36250, tweaked: README, NEWS: highlight bracketed paste mode; next version will be 5.1 rather than 5.0.9. diff --git a/Src/builtin.c b/Src/builtin.c index 572a0dd68..3d34aa74c 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1163,7 +1163,7 @@ cd_try_chdir(char *pfix, char *dest, int hard) * or a parent directory is renamed in the interim. */ if (lchdir(buf, NULL, hard) && - (pfix || *dest == '/' || lchdir(dest, NULL, hard))) { + (pfix || *dest == '/' || lchdir(unmeta(dest), NULL, hard))) { free(buf); return NULL; } diff --git a/Src/compat.c b/Src/compat.c index a0ce1823c..db468529a 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -454,8 +454,13 @@ zgetcwd(void) return ret; } -/* chdir with arbitrary long pathname. Returns 0 on success, -1 on normal * - * failure and -2 when chdir failed and the current directory is lost. */ +/* + * chdir with arbitrary long pathname. Returns 0 on success, -1 on normal * + * failure and -2 when chdir failed and the current directory is lost. + * + * This is to be treated as if at system level, so dir is unmetafied but + * terminated by a NULL. + */ /**/ mod_export int @@ -465,7 +470,7 @@ zchdir(char *dir) int currdir = -2; for (;;) { - if (!*dir || chdir(unmeta(dir)) == 0) { + if (!*dir || chdir(dir) == 0) { #ifdef HAVE_FCHDIR if (currdir >= 0) close(currdir); diff --git a/Src/utils.c b/Src/utils.c index 20e01a207..4c4dc55cd 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -6440,10 +6440,15 @@ init_dirsav(Dirsav d) d->dirfd = d->level = -1; } -/* Change directory, without following symlinks. Returns 0 on success, -1 * - * on failure. Sets errno to ENOTDIR if any symlinks are encountered. If * - * fchdir() fails, or the current directory is unreadable, we might end up * - * in an unwanted directory in case of failure. */ +/* + * Change directory, without following symlinks. Returns 0 on success, -1 + * on failure. Sets errno to ENOTDIR if any symlinks are encountered. If + * fchdir() fails, or the current directory is unreadable, we might end up + * in an unwanted directory in case of failure. + * + * path is an unmetafied but null-terminated string, as needed by system + * calls. + */ /**/ mod_export int diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst index 644d28046..0e3e98d38 100644 --- a/Test/D07multibyte.ztst +++ b/Test/D07multibyte.ztst @@ -496,3 +496,15 @@ >OK >OK >OK + + () { + emulate -L zsh + setopt errreturn + local cdpath=(.) + mkdir ホ + cd ホ + cd .. + cd ./ホ + cd .. + } +0:cd with special characters -- cgit v1.2.3