summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorP. J. McDermott <pj@pehjota.net>2022-03-22 18:46:20 (EDT)
committer P. J. McDermott <pj@pehjota.net>2022-03-22 18:46:20 (EDT)
commit50d117cb76883735faa8864c4978b5819cb167bd (patch)
tree4a3e2b44e66064dfffc7dc75e8fd70c954830be6
parente75ef778d29de6a66373dad8fdda32d33f0c9f52 (diff)
downloadatsign-50d117cb76883735faa8864c4978b5819cb167bd.zip
atsign-50d117cb76883735faa8864c4978b5819cb167bd.tar.gz
atsign-50d117cb76883735faa8864c4978b5819cb167bd.tar.bz2
datetime, formats: Conform to strptime() space req
-rw-r--r--TODO3
-rw-r--r--src/datetime.c45
-rw-r--r--src/formats.h30
3 files changed, 56 insertions, 22 deletions
diff --git a/TODO b/TODO
index 56d1f3e..b8f4d77 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,3 @@
-spaces between specifiers in strptime() formats -- strftime()?
- format printing: copy format to another buffer, skipping certain char
- parsing: copy format one char at a time, changing placeholder to space
test with other libc's (newlib? musl? fbsd? obsd?)
`./@ 7:00 PM` doesn't work with musl strptime()
test other times
diff --git a/src/datetime.c b/src/datetime.c
index 8f5051d..f7cdb89 100644
--- a/src/datetime.c
+++ b/src/datetime.c
@@ -43,6 +43,31 @@ static struct tm DATETIME_EPOCH_ = {
};
static void
+_datetime_buf_cpy_p(char *dst, const char *src)
+{
+ for (; *src != '\0'; ++src, ++dst) {
+ if (*src == '^') {
+ *dst = ' ';
+ } else {
+ *dst = *src;
+ }
+ }
+ *dst = '\0';
+}
+
+static void
+_datetime_buf_cpy_f(char *dst, const char *src)
+{
+ for (; *src != '\0'; ++src, ++dst) {
+ if (*src == '^') {
+ ++src;
+ }
+ *dst = *src;
+ }
+ *dst = '\0';
+}
+
+static void
_datetime_reset_tm(struct tm *tm)
{
tm->tm_year = INT_MIN;
@@ -142,7 +167,7 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec)
sec = *arg_sec; /* GCC is dumb. */
got = false;
for (t = 0; t < sizeof(FORMATS_TIME) / sizeof(FORMATS_TIME[0]) ; ++t) {
- memcpy(fmt_buf, FORMATS_TIME[t], time_fmt_len + 1);
+ _datetime_buf_cpy_p(fmt_buf, FORMATS_TIME[t]);
_datetime_reset_tm(&arg_tm);
end = strptime(input, fmt_buf, &arg_tm);
if (end != NULL && *end == '\0') {
@@ -159,11 +184,11 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec)
if (FORMATS_DATE[d][0] == '\0') {
break;
}
- memcpy(fmt_buf, FORMATS_DATE[d], date_fmt_len + 1);
+ _datetime_buf_cpy_p(fmt_buf, FORMATS_DATE[d]);
for (t = 0; t < sizeof(FORMATS_TIME) / sizeof(FORMATS_TIME[0]);
++t) {
- memcpy(fmt_buf + date_fmt_len, FORMATS_TIME[t],
- time_fmt_len + 1);
+ _datetime_buf_cpy_p(fmt_buf + date_fmt_len,
+ FORMATS_TIME[t]);
_datetime_reset_tm(&arg_tm);
end = strptime(input, fmt_buf, &arg_tm);
if (end != NULL && *end == '\0') {
@@ -178,14 +203,14 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec)
}
}
for (t = 0; t < sizeof(FORMATS_TIME) / sizeof(FORMATS_TIME[0]); ++t) {
- memcpy(fmt_buf, FORMATS_TIME[t], time_fmt_len + 1);
+ _datetime_buf_cpy_p(fmt_buf, FORMATS_TIME[t]);
for (d = 0; d < sizeof(FORMATS_DATE) / sizeof(FORMATS_DATE[0]);
++d) {
if (FORMATS_DATE[d][0] == '\0') {
break;
}
- memcpy(fmt_buf + time_fmt_len, FORMATS_DATE[d],
- date_fmt_len + 1);
+ _datetime_buf_cpy_p(fmt_buf + time_fmt_len,
+ FORMATS_DATE[d]);
_datetime_reset_tm(&arg_tm);
end = strptime(input, fmt_buf, &arg_tm);
if (end != NULL && *end == '\0') {
@@ -200,7 +225,7 @@ datetime_parse(struct tm *now_tm, const char *input, time_t *arg_sec)
}
}
for (d = 0; d < sizeof(FORMATS_MISC) / sizeof(FORMATS_MISC[0]) ; ++d) {
- memcpy(fmt_buf, FORMATS_MISC[d], misc_fmt_len + 1);
+ _datetime_buf_cpy_p(fmt_buf, FORMATS_MISC[d]);
_datetime_reset_tm(&arg_tm);
end = strptime(input, fmt_buf, &arg_tm);
if (end != NULL && *end == '\0') {
@@ -280,10 +305,12 @@ _datetime_strftime(const char *fmts[], const struct tm *tm, char **out,
++*i;
}
+ _datetime_buf_cpy_f(*out, fmts[*i]);
+
resized = 0;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
- while (strftime(*buf, *buf_sz, fmts[*i], tm) == 0) {
+ while (strftime(*buf, *buf_sz, *out, tm) == 0) {
#pragma GCC diagnostic pop
++*buf_sz;
*buf = realloc(*buf, *buf_sz * sizeof(**buf));
diff --git a/src/formats.h b/src/formats.h
index f4caccd..262912e 100644
--- a/src/formats.h
+++ b/src/formats.h
@@ -25,6 +25,16 @@
*
* All of the format strings in each array must be padded with spaces to be of
* equal lengths.
+ *
+ * Conversion specifications are used by both strptime() and strftime(). As
+ * required by the former function, there shall be "white-space or other non-
+ * alphanumeric characters between any two conversion specifications unless all
+ * of the adjacent conversion specifications convert a known, fixed number of
+ * characters." [POSIX] The "^" character may be used to separate conversion
+ * specifications that should be separated (by a space) when parsing and
+ * adjacent when formatting for printing. For example, " %I^%M %p " will be
+ * changed to " %I %M %p " when parsing and to " %I%M %p " when formatting for
+ * printing.
*/
static const char *FORMATS_DATE[] = {
@@ -220,10 +230,10 @@ static const char *FORMATS_TIME[] = {
" %H.%M.%S ", /* 19.00.01 */
" %I.%M %p ", /* 7.00 PM */
" %H.%M ", /* 19.00 */
- " %I%M%S %p ", /* 70001 PM */
- " %H%M%S ", /* 190001 */
- " %I%M %p ", /* 700 PM */
- " %H%M ", /* 1900 */
+ " %I^%M^%S %p ", /* 70001 PM */
+ " %H^%M^%S ", /* 190001 */
+ " %I^%M %p ", /* 700 PM */
+ " %H^%M ", /* 1900 */
};
static const char *FORMATS_MISC[] = {
@@ -231,13 +241,13 @@ static const char *FORMATS_MISC[] = {
" %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 ",
};