From 33c7ffa3039511384012296d05a9f227269f7797 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 24 May 2016 10:58:52 +0200 Subject: [PATCH] include/timeutils: rewrite iso formatting functions - use buffers rather than allocate memory - support .usec and ,usec convention - use strftime for timezone (we need to care about daylight saving time) Signed-off-by: Karel Zak --- include/timeutils.h | 16 +++++--- lib/timeutils.c | 98 +++++++++++++++++++++++++++++---------------- 2 files changed, 74 insertions(+), 40 deletions(-) diff --git a/include/timeutils.h b/include/timeutils.h index a1cd1b3530..2ec193a094 100644 --- a/include/timeutils.h +++ b/include/timeutils.h @@ -58,12 +58,16 @@ int parse_timestamp(const char *t, usec_t *usec); enum { ISO_8601_DATE = (1 << 1), ISO_8601_TIME = (1 << 2), - ISO_8601_USEC = (1 << 3), - ISO_8601_TIMEZONE = (1 << 4), - ISO_8601_SPACE = (1 << 5) + ISO_8601_DOTUSEC = (1 << 3), + ISO_8601_COMMAUSEC = (1 << 4), + ISO_8601_TIMEZONE = (1 << 5), + ISO_8601_SPACE = (1 << 6) }; -char *strtimeval_iso(struct timeval *tv, int flags); -char *strtm_iso(struct tm *tm, int flags); -char *strtime_iso(const time_t *t, int flags); + +#define ISO_8601_BUFSIZ 32 + +int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz); +int strtm_iso(struct tm *tm, int flags, char *buf, size_t bufsz); +int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz); #endif /* UTIL_LINUX_TIME_UTIL_H */ diff --git a/lib/timeutils.c b/lib/timeutils.c index bdc00d3375..fdf0024edb 100644 --- a/lib/timeutils.c +++ b/lib/timeutils.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "c.h" #include "nls.h" @@ -339,47 +340,77 @@ int parse_timestamp(const char *t, usec_t *usec) return 0; } -static char *format_iso_time(struct tm *tm, suseconds_t usec, int flags) +static int format_iso_time(struct tm *tm, suseconds_t usec, int flags, char *buf, size_t bufsz) { - char *s = NULL; + char *p = buf; + int len; - if (flags & ISO_8601_DATE) - s = strfappend(s, "%4d-%.2d-%.2d", tm->tm_year + 1900, + if (flags & ISO_8601_DATE) { + len = snprintf(p, bufsz, "%4d-%.2d-%.2d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); - if ((flags & ISO_8601_DATE) && (flags & ISO_8601_TIME)) - s = strnappend(s, (flags & ISO_8601_SPACE) ? " " : "T", 1); + if (len < 0 || (size_t) len > bufsz) + return -1; + bufsz -= len; + p += len; + } + + if ((flags & ISO_8601_DATE) && (flags & ISO_8601_TIME)) { + if (bufsz < 1) + return -1; + *p++ = (flags & ISO_8601_SPACE) ? ' ' : 'T'; + bufsz--; + } - if (flags & ISO_8601_TIME) - s = strfappend(s, "%02d:%02d:%02d", tm->tm_hour, + if (flags & ISO_8601_TIME) { + len = snprintf(p, bufsz, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); - if (flags & ISO_8601_USEC) - s = strfappend(s, ".%06ld", (long) usec); + if (len < 0 || (size_t) len > bufsz) + return -1; + bufsz -= len; + p += len; + } - if (flags & ISO_8601_TIMEZONE) { - int zhour = - timezone / 60 / 60; - int zmin = labs(timezone / 60 % 60); + if (flags & ISO_8601_DOTUSEC) { + len = snprintf(p, bufsz, ".%06ld", (long) usec); + if (len < 0 || (size_t) len > bufsz) + return -1; + bufsz -= len; + p += len; + + } else if (flags & ISO_8601_COMMAUSEC) { + len = snprintf(p, bufsz, ",%06ld", (long) usec); + if (len < 0 || (size_t) len > bufsz) + return -1; + bufsz -= len; + p += len; + } - s = strfappend(s, "%+02d:%02d", zhour, zmin); + if (flags & ISO_8601_TIMEZONE) { + if (strftime(p, bufsz, "%z", tm) <= 0) + return -1; } - return s; + return 0; } -char *strtimeval_iso(struct timeval *tv, int flags) +/* timeval to ISO 8601 */ +int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz) { struct tm tm = *localtime(&tv->tv_sec); - return format_iso_time(&tm, tv->tv_usec, flags); + return format_iso_time(&tm, tv->tv_usec, flags, buf, bufsz); } -char *strtm_iso(struct tm *tm, int flags) +/* struct tm to ISO 8601 */ +int strtm_iso(struct tm *tm, int flags, char *buf, size_t bufsz) { - return format_iso_time(tm, 0, flags); + return format_iso_time(tm, 0, flags, buf, bufsz); } -char *strtime_iso(const time_t *t, int flags) +/* time_t to ISO 8601 */ +int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz) { struct tm tm = *localtime(t); - return format_iso_time(&tm, 0, flags); + return format_iso_time(&tm, 0, flags, buf, bufsz); } @@ -388,7 +419,7 @@ char *strtime_iso(const time_t *t, int flags) int main(int argc, char *argv[]) { struct timeval tv = { 0 }; - char *p; + char buf[ISO_8601_BUFSIZ]; if (argc < 2) { fprintf(stderr, "usage: %s