aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/exess/src/date.c
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/exess/src/date.c')
-rw-r--r--subprojects/exess/src/date.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/subprojects/exess/src/date.c b/subprojects/exess/src/date.c
new file mode 100644
index 00000000..77b336f7
--- /dev/null
+++ b/subprojects/exess/src/date.c
@@ -0,0 +1,112 @@
+/*
+ Copyright 2019-2021 David Robillard <d@drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "date_utils.h"
+#include "read_utils.h"
+#include "timezone.h"
+#include "write_utils.h"
+
+#include "exess/exess.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+ExessResult
+read_date_numbers(ExessDate* const out, const char* const str)
+{
+ // Read year at the beginning
+ size_t i = skip_whitespace(str);
+ ExessResult r = read_year_number(&out->year, str + i);
+ if (r.status) {
+ return result(r.status, i + r.count);
+ }
+
+ // Read year-month delimiter
+ i += r.count;
+ if (str[i] != '-') {
+ return result(EXESS_EXPECTED_DASH, i);
+ }
+
+ // Read month
+ ++i;
+ if ((r = read_two_digit_number(&out->month, 1, 12, str + i)).status) {
+ return result(r.status, i + r.count);
+ }
+
+ // Read month-day delimiter
+ i += r.count;
+ if (str[i] != '-') {
+ return result(EXESS_EXPECTED_DASH, i);
+ }
+
+ // Read day
+ ++i;
+ if ((r = read_two_digit_number(&out->day, 1, 31, str + i)).status) {
+ return result(r.status, i + r.count);
+ }
+
+ // Check that day is in range
+ i += r.count;
+ if (out->day > days_in_month(out->year, out->month)) {
+ return result(EXESS_OUT_OF_RANGE, i);
+ }
+
+ return result(EXESS_SUCCESS, i);
+}
+
+ExessResult
+exess_read_date(ExessDate* const out, const char* const str)
+{
+ memset(out, 0, sizeof(*out));
+
+ // Read YYYY-MM-DD numbers
+ size_t i = skip_whitespace(str);
+ ExessResult r = read_date_numbers(out, str + i);
+
+ i += r.count;
+ if (r.status || is_end(str[i])) {
+ out->zone.quarter_hours = EXESS_LOCAL;
+ return result(r.status, i);
+ }
+
+ // Read timezone
+ r = exess_read_timezone(&out->zone, str + i);
+
+ return result(r.status, i + r.count);
+}
+
+ExessResult
+exess_write_date(const ExessDate value, const size_t buf_size, char* const buf)
+{
+ if (value.month < 1 || value.month > 12 || value.day < 1 || value.day > 31) {
+ return end_write(EXESS_BAD_VALUE, buf_size, buf, 0);
+ }
+
+ ExessResult r = write_year_number(value.year, buf_size, buf);
+ size_t o = r.count;
+ if (r.status) {
+ return end_write(r.status, buf_size, buf, o);
+ }
+
+ o += write_char('-', buf_size, buf, o);
+ o += write_two_digit_number(value.month, buf_size, buf, o);
+ o += write_char('-', buf_size, buf, o);
+ o += write_two_digit_number(value.day, buf_size, buf, o);
+
+ r = write_timezone(value.zone, buf_size, buf, o);
+
+ return end_write(r.status, buf_size, buf, o + r.count);
+}