summary refs log tree commit diff
diff options
context:
space:
mode:
authorMikael Magnusson <mikachu@gmail.com>2015-07-09 11:51:57 +0200
committerMikael Magnusson <mikachu@gmail.com>2015-07-09 15:32:55 +0200
commite402747dd6450cafaf1ca6c01671a5adf1595d02 (patch)
treea16468124c2c4e1d2489ba9a41a56c10fb59aabf
parent5951ac13ed0fee0352a6bfcbcc78ea8c0ec8ad5f (diff)
downloadzsh-e402747dd6450cafaf1ca6c01671a5adf1595d02.tar.gz
zsh-e402747dd6450cafaf1ca6c01671a5adf1595d02.tar.xz
zsh-e402747dd6450cafaf1ca6c01671a5adf1595d02.zip
35745: ztrftime: Pass everything unhandled to the system strftime()
-rw-r--r--ChangeLog5
-rw-r--r--Src/utils.c79
-rw-r--r--Test/V09datetime.ztst63
3 files changed, 122 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index 5dcc1e266..d36a73639 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2015-07-09  Mikael Magnusson  <mikachu@gmail.com>
+
+	* 35745: Src/utils.c, Test/V09datetime.ztst: ztrftime: Pass
+	everything unhandled to the system strftime()
+
 2015-07-09  Oliver Kiddle  <opk@zsh.org>
 
 	* 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