From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7113 invoked by alias); 18 Aug 2015 14:21:55 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 36227 Received: (qmail 16174 invoked from network); 18 Aug 2015 14:21:51 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.0 X-AuditID: cbfec7f5-f794b6d000001495-64-55d33f7bcc2b Date: Tue, 18 Aug 2015 15:21:45 +0100 From: Peter Stephenson To: Zsh hackers list Subject: Re: mkdir builtin and $'\0' Message-id: <20150818152145.6ae8dc32@pwslap01u.europe.root.pri> In-reply-to: <20150818142458.3252389e@pwslap01u.europe.root.pri> References: <20150818091904.GA5389@chaz.gmail.com> <20150818104911.034b6705@pwslap01u.europe.root.pri> <20150818111134.GA5629@chaz.gmail.com> <20150818122755.39fe78c8@pwslap01u.europe.root.pri> <20150818125519.GB5629@chaz.gmail.com> <20150818142458.3252389e@pwslap01u.europe.root.pri> Organization: Samsung Cambridge Solution Centre X-Mailer: Claws Mail 3.7.9 (GTK+ 2.22.0; i386-redhat-linux-gnu) MIME-version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7bit X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrKLMWRmVeSWpSXmKPExsVy+t/xK7rV9pdDDXqaFSwONj9kcmD0WHXw A1MAYxSXTUpqTmZZapG+XQJXxtvOT6wFWx0qjtxazNjA2GbQxcjJISFgInHt5AI2CFtM4sK9 9UA2F4eQwFJGiQvzD7FDODOYJO4vW8kK4WxjlFja9hOshUVAVaK5+xQziM0mYCgxddNsRhBb REBLYsfJk0wgtrCAisTLxg6wel4Be4mva4+wg9icAg4Sbc8fMUMMXcYk8W3qVLAifgF9iat/ PzFB3GQvMfPKGUaIZkGJH5PvsYDYzEALNm9rYoWw5SU2r3kLdoSQgLrEjbu72ScwCs1C0jIL ScssJC0LGJlXMYqmliYXFCel5xrpFSfmFpfmpesl5+duYoQE7tcdjEuPWR1iFOBgVOLhrci7 FCrEmlhWXJl7iFGCg1lJhFeS93KoEG9KYmVValF+fFFpTmrxIUZpDhYlcd6Zu96HCAmkJ5ak ZqemFqQWwWSZODilGhiDDi7niu/t28SRm1/bkWx68V3iWY6DzgmFIbKOcrW7d25oZ9U8fWbZ hfWH5zz0nuXpKpXwfLbChLKy34U+u/ZufnX93LbQ1b3MrY6bJ13b+90oIjhbySN+1/MXIlM1 yqQPz6xwiF444yPbvNfMLlPUD4vOzvk169tGLie55Pp5k2WmGNSx/uRUYinOSDTUYi4qTgQA KYvVkFgCAAA= On Tue, 18 Aug 2015 14:24:58 +0100 Peter Stephenson wrote: > On Tue, 18 Aug 2015 13:55:19 +0100 > Stephane Chazelas wrote: > > 2015-08-18 12:27:55 +0100, Peter Stephenson: > > > On Tue, 18 Aug 2015 12:11:34 +0100 > > > Stephane Chazelas wrote: > > > > $ strftime $'%Y\0%m\0%d' 0 | sed -n l > > > > 1970\203 01\203 01$ > > > > > > This should fix that one. > > [...] > > > > Thanks, though it seems to have broken some internationalisation > > support. > > That was Ismail's problem, too... in fact, if I'd looked above, I'd have > seen that buffer isn't actually metafied at that point, duh. So I'll > need to look further at what's causing you're original probalem --- > looks like something metafied has crept in. I'll back off the original > change. OK, so the answer at the moment is that ztrftime() assumes everything is unmetafied. That's inevitable with the output coming out from strftime(), so what we pass in needs to be consistent. However, actually in every case fmt is passed in still metafied. So we should unmetafy it and handle appropriately internally. For example: % print -P $'%D{%Y\0%m\0%d}' 0 | sed -n l 2015\203 08\203 18 0$ The caller then needs to metafy where appropriate, so we need to use the length returned from ztrftime(). This seems to work for strftime and primt -P %D and the tests pass. One unconnected drive-by unmeta if sched output --- the ztrftime there was OK because the input is a fixed string and the output is going straight to printf --- although that means it doesn't handled embedded NULLs which probably isn't a big issue in this case. pws diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c index bcf7661..5d5dac6 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 d941667..86c61cf 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 6fc5389..3961771 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 4a97a31..572a0dd 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 9e8589d..be067ee 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 236661a..20e01a2 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 e1bdaa4..c804913 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 '%':