aboutsummaryrefslogtreecommitdiff
path: root/jim-clock.c
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2017-04-16 22:17:16 +1000
committerSteve Bennett <steveb@workware.net.au>2017-04-18 11:30:34 +1000
commitf85a6e7c5a6387d721f19335984a838863237131 (patch)
treed5c8c94a2ebf37126d0cbd058b12d1d32c698fe9 /jim-clock.c
parent2ae6252ce62b018d2f46cd7fa8fb5d7628fd6de8 (diff)
downloadjimtcl-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.c143
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 }
};