diff options
author | Steve Bennett <steveb@workware.net.au> | 2017-04-16 22:17:16 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2017-04-18 11:30:34 +1000 |
commit | f85a6e7c5a6387d721f19335984a838863237131 (patch) | |
tree | d5c8c94a2ebf37126d0cbd058b12d1d32c698fe9 /jim-clock.c | |
parent | 2ae6252ce62b018d2f46cd7fa8fb5d7628fd6de8 (diff) | |
download | jimtcl-f85a6e7c5a6387d721f19335984a838863237131.zip jimtcl-f85a6e7c5a6387d721f19335984a838863237131.tar.gz jimtcl-f85a6e7c5a6387d721f19335984a838863237131.tar.bz2 |
clock: Add -gmt option to format and scan
Signed-off-by: Steve Bennett <steveb@workware.net.au>
Diffstat (limited to 'jim-clock.c')
-rw-r--r-- | jim-clock.c | 143 |
1 files changed, 108 insertions, 35 deletions
diff --git a/jim-clock.c b/jim-clock.c index 69fb966..979b13f 100644 --- a/jim-clock.c +++ b/jim-clock.c @@ -4,46 +4,88 @@ * Implements the clock command */ -/* For strptime() */ +#include "jimautoconf.h" + +/* For strptime() - currently nothing sets this */ +#ifdef STRPTIME_NEEDS_XOPEN_SOURCE #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif +#endif + +/* For timegm() */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif #include <stdlib.h> #include <string.h> #include <stdio.h> #include <time.h> -#include "jimautoconf.h" #include <jim-subcmd.h> #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif +struct clock_options { + int gmt; + const char *format; +}; + +/* Parses the options ?-format string? ?-gmt boolean? and fills in *opts. + * Any options not present are not set. + * argc must be even. + * + * Returns JIM_OK or JIM_ERR and sets an error result. + */ +static int parse_clock_options(Jim_Interp *interp, int argc, Jim_Obj *const *argv, struct clock_options *opts) +{ + static const char * const options[] = { "-gmt", "-format", NULL }; + enum { OPT_GMT, OPT_FORMAT, }; + int i; + + for (i = 0; i < argc; i += 2) { + int option; + if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { + return JIM_ERR; + } + switch (option) { + case OPT_GMT: + if (Jim_GetBoolean(interp, argv[i + 1], &opts->gmt) != JIM_OK) { + return JIM_ERR; + } + break; + case OPT_FORMAT: + opts->format = Jim_String(argv[i + 1]); + break; + } + } + return JIM_OK; +} + static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { /* How big is big enough? */ char buf[100]; time_t t; - long seconds; + jim_wide seconds; + struct clock_options options = { 0, "%a %b %d %H:%M:%S %Z %Y" }; - const char *format = "%a %b %d %H:%M:%S %Z %Y"; - - if (argc == 2 || (argc == 3 && !Jim_CompareStringImmediate(interp, argv[1], "-format"))) { - return -1; + if (Jim_GetWide(interp, argv[0], &seconds) != JIM_OK) { + return JIM_ERR; } + t = seconds; - if (argc == 3) { - format = Jim_String(argv[2]); + if (argc % 2 == 0) { + return -1; } - - if (Jim_GetLong(interp, argv[0], &seconds) != JIM_OK) { + if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) { return JIM_ERR; } - t = seconds; - if (strftime(buf, sizeof(buf), format, localtime(&t)) == 0) { + if (strftime(buf, sizeof(buf), options.format, options.gmt ? gmtime(&t) : localtime(&t)) == 0) { Jim_SetResultString(interp, "format string too long", -1); return JIM_ERR; } @@ -54,27 +96,58 @@ static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } #ifdef HAVE_STRPTIME +#ifndef HAVE_TIMEGM +/* Implement a basic timegm() for system's that don't have it */ +static time_t timegm(struct tm *tm) +{ + time_t t; + const char *tz = getenv("TZ"); + setenv("TZ", "", 1); + tzset(); + t = mktime(tm); + if (tz) { + setenv("TZ", tz, 1); + } + else { + unsetenv("TZ"); + } + tzset(); + return t; +} +#endif + static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { char *pt; struct tm tm; - time_t now = time(0); + /*time_t now = time(NULL);*/ + /* No default format */ + struct clock_options options = { 0, NULL }; + + if (argc % 2 == 0) { + return -1; + } - if (!Jim_CompareStringImmediate(interp, argv[1], "-format")) { + if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) { + return JIM_ERR; + } + if (options.format == NULL) { return -1; } - /* Initialise with the current date/time */ - localtime_r(&now, &tm); + /* Set unspecified fields to 0, e.g. HH:MM becomes 00:00 */ + memset(&tm, 0, sizeof(tm)); + /* But this is 1-based */ + tm.tm_mday = 1; - pt = strptime(Jim_String(argv[0]), Jim_String(argv[2]), &tm); + pt = strptime(Jim_String(argv[0]), options.format, &tm); if (pt == 0 || *pt != 0) { Jim_SetResultString(interp, "Failed to parse time according to format", -1); return JIM_ERR; } /* Now convert into a time_t */ - Jim_SetResultInt(interp, mktime(&tm)); + Jim_SetResultInt(interp, options.gmt ? timegm(&tm) : mktime(&tm)); return JIM_OK; } @@ -110,13 +183,6 @@ static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } static const jim_subcmd_type clock_command_table[] = { - { "seconds", - NULL, - clock_cmd_seconds, - 0, - 0, - /* Description: Returns the current time as seconds since the epoch */ - }, { "clicks", NULL, clock_cmd_micros, @@ -124,6 +190,13 @@ static const jim_subcmd_type clock_command_table[] = { 0, /* Description: Returns the current time in 'clicks' */ }, + { "format", + "seconds ?-format string? ?-gmt boolean?", + clock_cmd_format, + 1, + 5, + /* Description: Format the given time */ + }, { "microseconds", NULL, clock_cmd_micros, @@ -138,22 +211,22 @@ static const jim_subcmd_type clock_command_table[] = { 0, /* Description: Returns the current time in milliseconds */ }, - { "format", - "seconds ?-format format?", - clock_cmd_format, - 1, - 3, - /* Description: Format the given time */ - }, #ifdef HAVE_STRPTIME { "scan", - "str -format format", + "str -format format ?-gmt boolean?", clock_cmd_scan, 3, - 3, + 5, /* Description: Determine the time according to the given format */ }, #endif + { "seconds", + NULL, + clock_cmd_seconds, + 0, + 0, + /* Description: Returns the current time as seconds since the epoch */ + }, { NULL } }; |