summaryrefslogtreecommitdiffstats
path: root/src/datetime.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/datetime.c')
-rw-r--r--src/datetime.c124
1 files changed, 116 insertions, 8 deletions
diff --git a/src/datetime.c b/src/datetime.c
index 0056017..1a3bbba 100644
--- a/src/datetime.c
+++ b/src/datetime.c
@@ -19,8 +19,10 @@
#define _XOPEN_SOURCE
+#include <ctype.h>
#include <errno.h>
#include <limits.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -87,16 +89,16 @@ static const char *DATETIME_TIME_FMTS_[] = {
};
static const char *DATETIME_MISC_FMTS_[] = {
/* ISO 8601: 1969-12-31 delimited by "T" */
- " %Y-%m-%dT%H:%M:%S ",
- " %Y-%m-%dT%H:%M ",
+ " %Y-%m-%dT%H:%M:%S ",
+ " %Y-%m-%dT%H:%M ",
/* ISO 8601: 19691231 delimited by "T" */
- " %Y%m%dT%H%M%S ",
- " %Y%m%dT%H%M ",
+ " %Y%m%dT%H%M%S ",
+ " %Y%m%dT%H%M ",
/* 19691231 */
- " %Y%m%d %I%M%S %p ",
- " %Y%m%d %H%M%S ",
- " %Y%m%d %I%M %p ",
- " %Y%m%d %H%M ",
+ " %Y%m%d %I%M%S %p ",
+ " %Y%m%d %H%M%S ",
+ " %Y%m%d %I%M %p ",
+ " %Y%m%d %H%M ",
/* Wed Dec 31 19:00:01 1969 */
" %a %b %d %H:%M:%S %Y ",
};
@@ -244,3 +246,109 @@ datetime_parse(const char *input, time_t *arg_sec)
fputs("Unknown date format\n", stderr);
return -1;
}
+
+static void
+_datetime_copy_trim_fmt(char *buf, const char *fmt)
+{
+ int buf_i;
+ int l;
+ bool was_space;
+ int i;
+
+ buf_i = 0;
+ l = strlen(fmt);
+ was_space = true;
+ for (i = 0; i < l; ++i) {
+ if (isspace(fmt[i]) != 0) {
+ if (was_space == false) {
+ buf[buf_i++] = ' ';
+ was_space = true;
+ }
+ } else {
+ buf[buf_i++] = fmt[i];
+ was_space = false;
+ }
+ }
+ if (buf_i > 0) {
+ buf[buf_i - 1] = '\0';
+ } else {
+ buf[0] = '\0';
+ }
+}
+
+static int
+_datetime_strftime(const char *fmts[], const struct tm *tm, char **out,
+ size_t *out_sz, char **buf, size_t *i)
+{
+ if (*buf == NULL) {
+ *buf = calloc(strlen(fmts[0]), sizeof(**buf));
+ if (*buf == NULL) {
+ fprintf(stderr, "Failed to allocate buffer: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ }
+ if (*out == NULL) {
+ *out_sz = strlen(fmts[0]);
+ *out = calloc(*out_sz, sizeof(**out));
+ if (*out == NULL) {
+ fprintf(stderr, "Failed to allocate buffer: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ }
+
+ *buf[0] = '\0';
+ while (*buf[0] == '\0') {
+ _datetime_copy_trim_fmt(*buf, fmts[*i]);
+ ++*i;
+ }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ while (strftime(*out, *out_sz, *buf, tm) == 0) {
+#pragma GCC diagnostic pop
+ ++*out_sz;
+ *out = realloc(*out, *out_sz * sizeof(**out));
+ if (*out == NULL) {
+ fprintf(stderr, "Failed to allocate buffer: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+int
+datetime_strftime_date(const struct tm *tm, char **out, size_t *out_sz,
+ char **buf, size_t *i)
+{
+ if (*i >= sizeof(DATETIME_DATE_FMTS_) / sizeof(DATETIME_DATE_FMTS_[0])){
+ return 0;
+ }
+
+ return _datetime_strftime(DATETIME_DATE_FMTS_, tm, out, out_sz, buf, i);
+}
+
+int
+datetime_strftime_time(const struct tm *tm, char **out, size_t *out_sz,
+ char **buf, size_t *i)
+{
+ if (*i >= sizeof(DATETIME_TIME_FMTS_) / sizeof(DATETIME_TIME_FMTS_[0])){
+ return 0;
+ }
+
+ return _datetime_strftime(DATETIME_TIME_FMTS_, tm, out, out_sz, buf, i);
+}
+
+int
+datetime_strftime_misc(const struct tm *tm, char **out, size_t *out_sz,
+ char **buf, size_t *i)
+{
+ if (*i >= sizeof(DATETIME_MISC_FMTS_) / sizeof(DATETIME_MISC_FMTS_[0])){
+ return 0;
+ }
+
+ return _datetime_strftime(DATETIME_MISC_FMTS_, tm, out, out_sz, buf, i);
+}