summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorP. J. McDermott <pj@pehjota.net>2021-08-31 20:54:28 (EDT)
committer P. J. McDermott <pj@pehjota.net>2021-08-31 21:08:05 (EDT)
commite130ed9b3a982b36b75d4fbb225ad1fe8e16a7de (patch)
tree81af948fb54e87494fdc7c8a73bca5161d29b656
parent81f7ae4233b919c0c7aa055cb3a376c4cc4456d9 (diff)
downloadatsign-e130ed9b3a982b36b75d4fbb225ad1fe8e16a7de.zip
atsign-e130ed9b3a982b36b75d4fbb225ad1fe8e16a7de.tar.gz
atsign-e130ed9b3a982b36b75d4fbb225ad1fe8e16a7de.tar.bz2
Add option to list supported formats
-rw-r--r--configure.ac4
-rw-r--r--src/datetime.c124
-rw-r--r--src/datetime.h12
-rw-r--r--src/main.c78
4 files changed, 204 insertions, 14 deletions
diff --git a/configure.ac b/configure.ac
index cb2f4da..131540e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,8 +38,8 @@ test -d "${srcdir}/.git" || CFLAGS="${save_CFLAGS}"
funcs_missing=false
AC_CHECK_FUNCS(
[\
- calloc fprintf fputs free localtime mktime printf setvbuf \
- sleep strerror strlen strptime time
+ calloc fprintf fputs free isspace localtime mktime printf \
+ realloc setvbuf sleep strerror strlen strftime strptime time
],
[],
[funcs_missing=true])
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);
+}
diff --git a/src/datetime.h b/src/datetime.h
index 49a86a5..edff8f7 100644
--- a/src/datetime.h
+++ b/src/datetime.h
@@ -25,4 +25,16 @@
int
datetime_parse(const char *input, time_t *arg_sec);
+int
+datetime_strftime_date(const struct tm *tm, char **out, size_t *out_sz,
+ char **buf, size_t *i);
+
+int
+datetime_strftime_time(const struct tm *tm, char **out, size_t *out_sz,
+ char **buf, size_t *i);
+
+int
+datetime_strftime_misc(const struct tm *tm, char **out, size_t *out_sz,
+ char **buf, size_t *i);
+
#endif /* DATETIME_H_ */
diff --git a/src/main.c b/src/main.c
index 81096a5..f450281 100644
--- a/src/main.c
+++ b/src/main.c
@@ -36,6 +36,12 @@ extern const char *PACKAGE_VERSION_GIT;
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
struct option LONGOPTS_[] = {
{
+ .name = "list-formats",
+ .has_arg = 0,
+ .flag = NULL,
+ .val = 'F',
+ },
+ {
.name = "help",
.has_arg = 0,
.flag = NULL,
@@ -62,15 +68,76 @@ _print_help(const char *program_name)
_print_usage(stdout, program_name);
puts("Options:");
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
- puts("\t-h, --help Show this help information");
- puts("\t-V, --version Show version information");
+ puts("\t-F, --list-formats List all supported date and time formats");
+ puts("\t-h, --help Show this help information");
+ puts("\t-V, --version Show version information");
#else
+ puts("\t-F List all supported date and time formats");
puts("\t-h Show this help information");
puts("\t-V Show version information");
#endif
}
static void
+_list_formats(void)
+{
+ time_t tim;
+ struct tm *tm;
+ char *out;
+ size_t out_sz;
+ char *buf;
+ size_t i;
+
+ tim = time(NULL);
+ tm = localtime(&tim);
+
+ puts("Time formats:");
+ out = NULL;
+ out_sz = 0;
+ buf = NULL;
+ i = 0;
+ while (datetime_strftime_time(tm, &out, &out_sz, &buf, &i) > 0) {
+ printf(" * %s\n", out);
+ }
+ if (out != NULL) {
+ free(out);
+ }
+ if (buf != NULL) {
+ free(buf);
+ }
+
+ puts("Date formats:");
+ out = NULL;
+ out_sz = 0;
+ buf = NULL;
+ i = 0;
+ while (datetime_strftime_date(tm, &out, &out_sz, &buf, &i) > 0) {
+ printf(" * %s\n", out);
+ }
+ if (out != NULL) {
+ free(out);
+ }
+ if (buf != NULL) {
+ free(buf);
+ }
+
+ puts("Additional formats:");
+ out = NULL;
+ out_sz = 0;
+ buf = NULL;
+ i = 0;
+ while (datetime_strftime_misc(tm, &out, &out_sz, &buf, &i) > 0) {
+ printf(" * %s\n", out);
+ }
+ if (out != NULL) {
+ free(out);
+ }
+ if (buf != NULL) {
+ free(buf);
+ }
+}
+
+static void
_print_version(void)
{
printf("@ (atsign) %s%s\n", PACKAGE_VERSION, PACKAGE_VERSION_GIT);
@@ -128,11 +195,14 @@ main(int argc, char * const argv[])
optind = 1;
opterr = 0;
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
- while ((opt = getopt_long(argc, argv, "hV", LONGOPTS_, NULL)) > 0) {
+ while ((opt = getopt_long(argc, argv, "FhV", LONGOPTS_, NULL)) > 0) {
#else
- while ((opt = getopt(argc, argv, "hV")) > 0) {
+ while ((opt = getopt(argc, argv, "FhV")) > 0) {
#endif
switch (opt) {
+ case 'F':
+ _list_formats();
+ return EXIT_SUCCESS;
case 'h':
_print_help(argv[0]);
return EXIT_SUCCESS;