about summary refs log tree commit diff
path: root/Src/Modules/datetime.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2006-08-17 15:28:11 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2006-08-17 15:28:11 +0000
commitd0b9eddd9a320bed6d87c07d26048bbf6816115c (patch)
tree10759c39d2a13bd1d4749e6fd5da87c3eb94c643 /Src/Modules/datetime.c
parent1a42aadd81240fdb7f0acc38ddeef38898b705ab (diff)
downloadzsh-d0b9eddd9a320bed6d87c07d26048bbf6816115c.tar.gz
zsh-d0b9eddd9a320bed6d87c07d26048bbf6816115c.tar.xz
zsh-d0b9eddd9a320bed6d87c07d26048bbf6816115c.zip
22613: add strftime -r to use strptime() if available
Diffstat (limited to 'Src/Modules/datetime.c')
-rw-r--r--Src/Modules/datetime.c66
1 files changed, 65 insertions, 1 deletions
diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c
index 8b5ff5d68..add4b303b 100644
--- a/Src/Modules/datetime.c
+++ b/Src/Modules/datetime.c
@@ -31,6 +31,68 @@
 #include "datetime.pro"
 #include <time.h>
 
+#ifndef HAVE_MKTIME
+#ifdef HAVE_TIMELOCAL
+#define	mktime(x)	timelocal(x)
+#define HAVE_MKTIME	1
+#endif
+#endif
+
+static int
+reverse_strftime(char *nam, char **argv, char *scalar, int quiet)
+{
+#if defined(HAVE_STRPTIME) && defined(HAVE_MKTIME)
+    struct tm tm;
+    zlong mytime;
+    char *endp;
+
+    /*
+     * Initialise all parameters to zero; there's no floating point
+     * so memset() will do the trick.  The exception is that tm_isdst
+     * is set to -1 which, if not overridden, will cause mktime()
+     * to use the current timezone.  This is probably the best guess;
+     * it's the one that will cause dates and times output by strftime
+     * without the -r option and without an explicit timezone to be
+     * converted back correctly.
+     */
+    (void)memset(&tm, 0, sizeof(tm));
+    tm.tm_isdst = -1;
+    endp = strptime(argv[1], argv[0], &tm);
+
+    if (!endp) {
+	/* Conversion failed completely. */
+	if (!quiet)
+	    zwarnnam(nam, "format not matched");
+	return 1;
+    }
+
+    mytime = (zlong)mktime(&tm);
+
+    if (scalar)
+	setiparam(scalar, mytime);
+    else {
+	char buf[DIGBUFSIZE];
+	convbase(buf, mytime, 10);
+	printf("%s\n", buf);
+    }
+
+    if (*endp && !quiet) {
+	/*
+	 * Not everything in the input string was converted.
+	 * This is probably benign, since the format has been satisfied,
+	 * but issue a warning unless the quiet flag is set.
+	 */
+	zwarnnam(nam, "warning: input string not completely matched");
+    }
+
+    return 0;
+#else
+    if (!quiet)
+	zwarnnam(nam, "not implemented on this system");
+    return 2;
+#endif
+}
+
 static int
 bin_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
 {
@@ -46,6 +108,8 @@ bin_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
 	    return 1;
 	}
     }
+    if (OPT_ISSET(ops, 'r'))
+	return reverse_strftime(nam, argv, scalar, OPT_ISSET(ops, 'q'));
 
     secs = (time_t)strtoul(argv[1], &endptr, 10);
     if (secs == (time_t)ULONG_MAX) {
@@ -83,7 +147,7 @@ getcurrentsecs()
 }
 
 static struct builtin bintab[] = {
-    BUILTIN("strftime",    0, bin_strftime,    2,   2, 0, "s:", NULL),
+    BUILTIN("strftime",    0, bin_strftime,    2,   2, 0, "qrs:", NULL),
 };
 
 static const struct gsu_integer epochseconds_gsu =