diff options
author | sternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org> | 2020-08-21 00:03:24 +0200 |
---|---|---|
committer | sternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org> | 2020-08-21 00:06:24 +0200 |
commit | 875a5ce6222fa1027dc134b73c5cd6e8c06c1e4a (patch) | |
tree | 39bceb66616964571c0c23ac0acd3046195c8779 | |
parent | cada2ed89e5a0b68e2cfd002bf707107fb6d7111 (diff) |
feat(timeutil): output proper RFC3339 format for atom
Previously, since we used strftime %z it'd output an offset as +HHMM while RFC3339 requires +HH:MM. Currently we implement outputting this manually which proved to be non-trivial because of the tzset() API. This probably should be improved in the future since I suspect it produces incorrect results in some edge cases.
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | bitutil.c | 25 | ||||
-rw-r--r-- | bitutil.h | 1 | ||||
-rw-r--r-- | cgiutil.c | 26 | ||||
-rw-r--r-- | timeutil.c | 71 | ||||
-rw-r--r-- | timeutil.h | 2 |
7 files changed, 95 insertions, 33 deletions
diff --git a/Makefile b/Makefile index 27826c4..165bcf9 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ include config.mk ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) -sternenblog.cgi: xml.o entry.o index.o cgiutil.o timeutil.o $(TEMPLATE).o main.o +sternenblog.cgi: xml.o entry.o index.o bitutil.o cgiutil.o timeutil.o $(TEMPLATE).o main.o $(CC) $(CFLAGS) -o $@ $^ main.o: main.c core.h timeutil.h config.h diff --git a/TODO b/TODO index d89a742..f4e9b92 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,7 @@ atom feed | id:44aca4a04ff19c567e08968370cc535139807bbd add support for caching | id:472d68f1af5489020f4c5808e805822e3da77ffc rethink logging / debug output | id:5734e2717f28d80ac65d3f2123a0f46c01d4a0c1 if possible determine BLOG_SERVER_URL automatically | id:5ad1fabab42a5776ab1446d09659c7a99a104245 +rework timezone offsets without tzset() | id:64d715e826ba9fdbcc72cb1b92a77f004642d2a3 support markdown markup via lowdown | id:90c72d144f21d78d1b56790a927f6eea52df2a2c get rid of as many fixed size buffers as possible | id:9281f3a25aa08f6ba5d67c02e65cd0fb7f0a6b3c templating: give all functions context (index or not, SCRIPT_NAME, entry struct if applicable) | id:930c2e4f2c4c9ec3efef87b6ddd50a6ba6dd4903 diff --git a/bitutil.c b/bitutil.c new file mode 100644 index 0000000..8b2807f --- /dev/null +++ b/bitutil.c @@ -0,0 +1,25 @@ +char nibble_hex(short h) { + switch(h) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + return (h + 48); + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + return (h + 55); + default: + return 0; + } +} + diff --git a/bitutil.h b/bitutil.h new file mode 100644 index 0000000..57d15e6 --- /dev/null +++ b/bitutil.h @@ -0,0 +1 @@ +char nibble_hex(short h); diff --git a/cgiutil.c b/cgiutil.c index 606a10e..043dade 100644 --- a/cgiutil.c +++ b/cgiutil.c @@ -3,6 +3,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "bitutil.h" void send_header(char key[], char val[]) { fputs(key, stdout); @@ -46,31 +47,6 @@ int http_errno(int err) { } } -char nibble_hex(short h) { - switch(h) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - return (h + 48); - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - return (h + 55); - default: - return 0; - } -} - int urlencode_realloc(char **input, int size) { if(*input == NULL || size <= 0) { return -1; diff --git a/timeutil.c b/timeutil.c index 3d1cec3..c695d54 100644 --- a/timeutil.c +++ b/timeutil.c @@ -1,28 +1,89 @@ #define _POSIX_C_SOURCE 1 +#define _XOPEN_SOURCE 1 // for timezone #include <time.h> +#include <stdlib.h> +#include <string.h> #include "timeutil.h" +#include "bitutil.h" -extern long timezone; +#include <stdio.h> -char *format_string(enum time_format t, long tz) { +char *format_string(enum time_format t) { switch(t) { case RSS_TIME_FORMAT: return "%a, %d %b %Y %T %z"; + // both remaining cases still need a UTC offset + // part at the end which is not supported by + // strftime(3), so we do this ourselves in + // flocaltime case HTML_TIME_FORMAT_READABLE: - return tz == 0 ? "%Y-%m-%d %TZ" : "%Y-%m-%d %T%z"; + return "%Y-%m-%d %T"; case ATOM_TIME_FORMAT: default: - return tz == 0 ? "%Y-%m-%dT%TZ" : "%Y-%m-%dT%T%z"; + return "%Y-%m-%dT%T"; } } size_t flocaltime(char *b, enum time_format type, size_t size, const time_t *time) { tzset(); struct tm *local = localtime(time); - char *format = format_string(type, timezone); + char *format = format_string(type); size_t res = strftime(b, size, format, local); + if(type == ATOM_TIME_FORMAT || type == HTML_TIME_FORMAT_READABLE) { + // for these formats we need to append a RFC3339 UTC offset + // unfortunately it is *not* exactly provided by strftime, + // but in hindsight it might be better to do a little string + // manipulation than this madness, since the libc timezone + // API is horrible (at least POSIX / glibc) + size_t offset_size = 7; + char offset[offset_size]; + + if(timezone == 0) { + offset[0] = 'Z'; + offset[1] = '\0'; + } else { + // for some reason timezone is seconds *west* of UTC which + // is inverse to how UTC offsets are denoted + long real_offset = (-1) * timezone; + + if(daylight) { + struct tm *local = localtime(time); + + // TODO is this correct in all cases? + if(local->tm_isdst == 1) { + real_offset += 3600; + } + } + + char sign; + if(real_offset > 0) { + sign = '+'; + } else { + sign = '-'; + } + + long abso = labs(real_offset); + long hour = abso / 3600; + long minute = (abso % 3600) / 60; + + fprintf(stderr, "%ld:%ld (%ld)\n", hour, minute, real_offset); + + offset[0] = sign; + offset[1] = nibble_hex((short) hour / 10); + offset[2] = nibble_hex((short) hour % 10); + offset[3] = ':'; + offset[4] = nibble_hex((short) minute / 10); + offset[5] = nibble_hex((short) minute % 10); + offset[6] = '\0'; + } + + if(res > 0 && res + offset_size <= size) { + memcpy(b + res, offset, offset_size); + } + } + // prevent any buffer overflows b[size - 1] = '\0'; diff --git a/timeutil.h b/timeutil.h index 4659513..8ee39cc 100644 --- a/timeutil.h +++ b/timeutil.h @@ -8,7 +8,5 @@ enum time_format { // max HTML/Atom: 24 + NUL byte // max RSS: 31 + NUL byte -char *format_string(enum time_format t, long tz); - size_t flocaltime(char *b, enum time_format type, size_t size, const time_t *time); |