zsh-workers
 help / color / mirror / code / Atom feed
From: Peter Stephenson <p.stephenson@samsung.com>
To: Zsh hackers list <zsh-workers@zsh.org>
Subject: Re: mkdir builtin and $'\0'
Date: Tue, 18 Aug 2015 15:21:45 +0100	[thread overview]
Message-ID: <20150818152145.6ae8dc32@pwslap01u.europe.root.pri> (raw)
In-Reply-To: <20150818142458.3252389e@pwslap01u.europe.root.pri>

On Tue, 18 Aug 2015 14:24:58 +0100
Peter Stephenson <p.stephenson@samsung.com> wrote:
> On Tue, 18 Aug 2015 13:55:19 +0100
> Stephane Chazelas <stephane.chazelas@gmail.com> wrote:
> > 2015-08-18 12:27:55 +0100, Peter Stephenson:
> > > On Tue, 18 Aug 2015 12:11:34 +0100
> > > Stephane Chazelas <stephane.chazelas@gmail.com> 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 '%':


  reply	other threads:[~2015-08-18 14:21 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-18  9:19 Stephane Chazelas
2015-08-18  9:49 ` Peter Stephenson
2015-08-18 11:11   ` Stephane Chazelas
2015-08-18 11:27     ` Peter Stephenson
2015-08-18 12:55       ` Stephane Chazelas
2015-08-18 13:24         ` Peter Stephenson
2015-08-18 14:21           ` Peter Stephenson [this message]
2015-08-18 15:07             ` Peter Stephenson
2015-08-18 15:18               ` Peter Stephenson
2015-08-18 15:19               ` Mikael Magnusson
2015-08-19  9:52             ` Peter Stephenson
2015-08-19 13:10               ` Stephane Chazelas
2015-08-18 11:06 ` Peter Stephenson
2015-08-18 16:20 ` Stephane Chazelas
2015-08-18 16:37   ` Peter Stephenson
2015-08-21  6:20     ` Mikael Magnusson
2015-08-21  8:57       ` Peter Stephenson
2015-08-21 14:09         ` Peter Stephenson
2015-08-20 11:15 Recommend latex surgical gloves ED
2015-08-20 16:42 ` 5.0.9 / 5.1 agani (ws Re: Recommend latex surgical gloves) Peter Stephenson
2015-08-21  3:38   ` Mikael Magnusson
2015-09-04 13:44     ` mkdir builtin and $'\0' Oliver Kiddle

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150818152145.6ae8dc32@pwslap01u.europe.root.pri \
    --to=p.stephenson@samsung.com \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).