From d0b9eddd9a320bed6d87c07d26048bbf6816115c Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 17 Aug 2006 15:28:11 +0000 Subject: 22613: add strftime -r to use strptime() if available --- ChangeLog | 6 ++++- Doc/Zsh/mod_datetime.yo | 21 +++++++++++++--- Src/Modules/datetime.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++- configure.ac | 3 ++- 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index ef0d8f7c7..e80bf8314 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2006-08-17 Peter Stephenson + * 22613: configure.ac, Doc/Zsh/mod_datetime.yo, + Src/Modules/datetime.c: add strftime -r to use strptime() + if available. + * 22612: Src/Zle/complist.c: comment the static variables. 2006-08-16 Peter Stephenson @@ -19,7 +23,7 @@ 2006-08-14 Peter Stephenson - * 22608: Doc/Zsh/contrib.yo: improvments on 22606. + * 22608: Doc/Zsh/contrib.yo: improvements on 22606. * 22606: Doc/Zsh/contrib.yo, Functions/Zle/match-word-context, Functions/Zle/match-words-by-style, Functions/Zle/.distfiles: new diff --git a/Doc/Zsh/mod_datetime.yo b/Doc/Zsh/mod_datetime.yo index b006baf89..145d4a181 100644 --- a/Doc/Zsh/mod_datetime.yo +++ b/Doc/Zsh/mod_datetime.yo @@ -6,12 +6,27 @@ The tt(zsh/datetime) module makes available one builtin command: startitem() findex(strftime) cindex(date string, printing) -item(tt(strftime) [ tt(-s) var(scalar) ] var(format) var(epochtime) )( +xitem(tt(strftime) [ tt(-s) var(scalar) ] var(format) var(epochtime) ) +item(tt(strftime) tt(-r) [ tt(-q) ] [ tt(-s) var(scalar) ] var(format) var(timestring) )( Output the date denoted by var(epochtime) in the var(format) specified. -If tt(-s) var(scalar) is given, assign the date to var(scalar) instead -of printing it. +With the option tt(-r) (reverse), use the format var(format) to parse the +input string var(timestring) and output the number of seconds since the +epoch at which the time occurred. If no timezone is parsed, the current +timezone is used; other parameters are set to zero if not present. If +var(timestring) does not match var(format) the command returns status 1; it +will additionally print an error message unless the option tt(-q) (quiet) +is given. If var(timestring) matches var(format) but not all characters in +var(timestring) were used, the conversion succeeds; however, a warning is +issued unless the option tt(-q) is given. The matching is implemented by +the system function tt(strptime); see manref(strptime)(3). This means that +zsh format extensions are not available, however for reverse lookup they +are not required. If the function is not implemented, the command returns +status 2 and (unless tt(-q) is given) prints a message. + +If tt(-s) var(scalar) is given, assign the date string (or epoch time +in seconds if tt(-r) is given) to var(scalar) instead of printing it. ) enditem() 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 +#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 = diff --git a/configure.ac b/configure.ac index 75f4d7687..21e7764e2 100644 --- a/configure.ac +++ b/configure.ac @@ -1096,7 +1096,8 @@ dnl --------------- dnl need to integrate this function dnl AC_FUNC_STRFTIME -AC_CHECK_FUNCS(strftime difftime gettimeofday \ +AC_CHECK_FUNCS(strftime strptime mktime timelocal \ + difftime gettimeofday \ select poll \ readlink faccessx fchdir ftruncate \ fstat lstat lchown fchown fchmod \ -- cgit 1.4.1