* Incorrect evaluation of ~ test in ternary conditional @ 2017-12-15 13:55 Felix Uhl 2017-12-16 22:01 ` Bart Schaefer 0 siblings, 1 reply; 5+ messages in thread From: Felix Uhl @ 2017-12-15 13:55 UTC (permalink / raw) To: zsh-workers Hi everybody! Let there be a directory ~/work. Using the ~ test character in a conditional ternary prompt will return incorrect results when the argument is 2 as shown below: $ cd && print -P "%(2~:true:false)" false $ cd work/.. && print -P "%(2~:true:false)" true The docs say: (http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html#Conditional-Substrings-in-Prompts) > c [...] . [...] ~ [...] True if the current path, with prefix replacement, has at least n elements relative to the root directory, hence / is counted as 0 elements. So the first command behaves properly, but the second one doesn't. I'm using zsh 5.0.5. Can somebody confirm this for the current version of zsh as well? BR, Felix ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Incorrect evaluation of ~ test in ternary conditional 2017-12-15 13:55 Incorrect evaluation of ~ test in ternary conditional Felix Uhl @ 2017-12-16 22:01 ` Bart Schaefer 2017-12-18 15:07 ` Felix Uhl 0 siblings, 1 reply; 5+ messages in thread From: Bart Schaefer @ 2017-12-16 22:01 UTC (permalink / raw) To: Felix Uhl; +Cc: zsh-workers On Fri, Dec 15, 2017 at 5:55 AM, Felix Uhl <felix.uhl@outlook.de> wrote: > Hi everybody! > > Let there be a directory ~/work. Using the ~ test character in a > conditional ternary prompt will return incorrect results when the > argument is 2 as shown below: > > $ cd && print -P "%(2~:true:false)" > false > $ cd work/.. && print -P "%(2~:true:false)" > true I actually get randomly incorrect results in the FIRST of your examples: repeat 5 do cd && print -P "%~ %(2~:true:false)" ; done ~ true ~ false ~ true ~ false ~ false The second case is consistent but is always wrong: repeat 5 do cd work/.. && print -P "%~ %(2~:true:false)" ; done ~ true ~ true ~ true ~ true ~ true Both of the foregoing happen in each of 5.0.2 and the latest development version. I don't have 5.0.5 handy. This seems to be the fix: diff --git a/Src/prompt.c b/Src/prompt.c index c478e69..63e8093 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -315,7 +315,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) case '/': case 'C': /* `/' gives 0, `/any' gives 1, etc. */ - if (*ss++ == '/' && *ss) + if (*ss && *ss++ == '/' && *ss) arg--; for (; *ss; ss++) if (*ss == '/') I'm not sure whether (*ss == '/' && *++ss) would be equivalent, i.e., I don't know why the original formulation skips over the first character whether or not it is a '/'. Possibly to skip a leading '~'? ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Incorrect evaluation of ~ test in ternary conditional 2017-12-16 22:01 ` Bart Schaefer @ 2017-12-18 15:07 ` Felix Uhl 2017-12-30 2:40 ` Bart Schaefer 0 siblings, 1 reply; 5+ messages in thread From: Felix Uhl @ 2017-12-18 15:07 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-workers On 16.12.2017 23:01, Bart Schaefer wrote: > On Fri, Dec 15, 2017 at 5:55 AM, Felix Uhl <felix.uhl@outlook.de> wrote: >> Hi everybody! >> >> Let there be a directory ~/work. Using the ~ test character in a >> conditional ternary prompt will return incorrect results when the >> argument is 2 as shown below: >> >> $ cd && print -P "%(2~:true:false)" >> false >> $ cd work/.. && print -P "%(2~:true:false)" >> true > I actually get randomly incorrect results in the FIRST of your examples: > > repeat 5 do cd && print -P "%~ %(2~:true:false)" ; done > ~ true > ~ false > ~ true > ~ false > ~ false > > The second case is consistent but is always wrong: > > repeat 5 do cd work/.. && print -P "%~ %(2~:true:false)" ; done > ~ true > ~ true > ~ true > ~ true > ~ true > > Both of the foregoing happen in each of 5.0.2 and the latest > development version. I don't have 5.0.5 handy. > > Huh, interesting. Even at 5000 repetitions, I don't get a single wrong result on the first example (takes about 2 minutes to run though): $ repeat 5000 do cd && print -nP "%(2~:true:)" ; done $ I wonder where that discrepancy comes from. > This seems to be the fix: > > diff --git a/Src/prompt.c b/Src/prompt.c > index c478e69..63e8093 100644 > --- a/Src/prompt.c > +++ b/Src/prompt.c > @@ -315,7 +315,7 @@ putpromptchar(int doprint, int endchar, unsigned > int *txtchangep) > case '/': > case 'C': > /* `/' gives 0, `/any' gives 1, etc. */ > - if (*ss++ == '/' && *ss) > + if (*ss && *ss++ == '/' && *ss) > arg--; > for (; *ss; ss++) > if (*ss == '/') > > I'm not sure whether (*ss == '/' && *++ss) would be equivalent, i.e., > I don't know why the original formulation skips over the first > character whether or not it is a '/'. Possibly to skip a leading '~'? The original implementation doesn't skip the first character, does it? C operator precedence will treat *ss++ like *(ss++), so if ss is (for the sake of demonstration) 10, it is incremented to 11, but the postfix operator returns the old value of 10, which is then dereferenced by *. So the whole condition checks whether the first character is '/' and whether the second character is not 0. I'd probably write that as (*ss == '/' && *(++ss)), seems much clearer to me. I fail to understand why your fix should work, the expressions (*ss && *ss++ == '/') and (*ss++ == '/') on their own are logically equivalent to (*ss == '/') and have equivalent side-effects as well. Did you actually test it? ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Incorrect evaluation of ~ test in ternary conditional 2017-12-18 15:07 ` Felix Uhl @ 2017-12-30 2:40 ` Bart Schaefer 2018-01-03 10:44 ` Felix Uhl 0 siblings, 1 reply; 5+ messages in thread From: Bart Schaefer @ 2017-12-30 2:40 UTC (permalink / raw) To: Felix Uhl; +Cc: zsh-workers Catching up on some old stuff ... On Mon, Dec 18, 2017 at 7:07 AM, Felix Uhl <felix.uhl@outlook.de> wrote: > >> - if (*ss++ == '/' && *ss) >> + if (*ss && *ss++ == '/' && *ss) >> arg--; >> >> I'm not sure whether (*ss == '/' && *++ss) would be equivalent, i.e., >> I don't know why the original formulation skips over the first >> character whether or not it is a '/'. Possibly to skip a leading '~'? > > The original implementation doesn't skip the first character, does it? It does, because it increments ss regardless of whether or not the first character is '/'. So if ss = "a", (*ss++ == '/' && *ss) is false because 'a' != '/', but ss now points at '\0' instead of at 'a'. > So the whole condition checks whether the first character is '/' and > whether the second character is not 0. Correct, but it has the side-effect of always advancing ss by one position. > I'd probably write that as (*ss == '/' && *(++ss)), seems much clearer > to me. That avoids the side-effect, but I'm not sure if that side-effect was intentional. > I fail to understand why your fix should work, the expressions (*ss && > *ss++ == '/') and (*ss++ == '/') on their own are logically equivalent Not when ss = "". If ss points to empty string, the first of those does not move ss past the null byte into garbage, but the second one does. The question is what should happen when ss is neither the empty string nor begins with a slash. > to (*ss == '/') and have equivalent side-effects as well. This is incorrect with respect to the side-effects. > Did you actually test it? Yes. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Incorrect evaluation of ~ test in ternary conditional 2017-12-30 2:40 ` Bart Schaefer @ 2018-01-03 10:44 ` Felix Uhl 0 siblings, 0 replies; 5+ messages in thread From: Felix Uhl @ 2018-01-03 10:44 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-workers On 30.12.2017 03:40, Bart Schaefer wrote: > Catching up on some old stuff ... > > On Mon, Dec 18, 2017 at 7:07 AM, Felix Uhl <felix.uhl@outlook.de> wrote: >>> - if (*ss++ == '/' && *ss) >>> + if (*ss && *ss++ == '/' && *ss) >>> arg--; >>> >>> I'm not sure whether (*ss == '/' && *++ss) would be equivalent, i.e., >>> I don't know why the original formulation skips over the first >>> character whether or not it is a '/'. Possibly to skip a leading '~'? >> The original implementation doesn't skip the first character, does it? > It does, because it increments ss regardless of whether or not the > first character is '/'. So if ss = "a", (*ss++ == '/' && *ss) is > false because 'a' != '/', but ss now points at '\0' instead of at 'a'. > >> Did you actually test it? > Yes. Ah, you're absolutely correct. Thanks for the explanation! I guess the only thing left then is to find out whether your fix breaks anything, correct? ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2018-01-03 10:44 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-12-15 13:55 Incorrect evaluation of ~ test in ternary conditional Felix Uhl 2017-12-16 22:01 ` Bart Schaefer 2017-12-18 15:07 ` Felix Uhl 2017-12-30 2:40 ` Bart Schaefer 2018-01-03 10:44 ` Felix Uhl
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).