aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/exess/src/year.c
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/exess/src/year.c')
-rw-r--r--subprojects/exess/src/year.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/subprojects/exess/src/year.c b/subprojects/exess/src/year.c
new file mode 100644
index 00000000..e268ff80
--- /dev/null
+++ b/subprojects/exess/src/year.c
@@ -0,0 +1,98 @@
+/*
+ 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 "int_math.h"
+#include "macros.h"
+#include "read_utils.h"
+#include "write_utils.h"
+
+#include "exess/exess.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+ExessResult
+read_year_number(int16_t* const out, const char* const str)
+{
+ *out = 0;
+
+ // Read leading sign if present
+ size_t i = 0;
+ int sign = 1;
+ if (str[i] == '-') {
+ sign = -1;
+ ++i;
+ }
+
+ // Read digits
+ uint64_t magnitude = 0;
+ ExessResult r = exess_read_ulong(&magnitude, str + i);
+ if (r.status > EXESS_EXPECTED_END) {
+ return result(r.status, i + r.count);
+ }
+
+ i += r.count;
+
+ if (sign > 0) {
+ if (magnitude > (uint16_t)INT16_MAX) {
+ return result(EXESS_OUT_OF_RANGE, i);
+ }
+
+ *out = (int16_t)magnitude;
+ } else {
+ const uint16_t min_magnitude = (uint16_t)(-(INT16_MIN + 1)) + 1;
+ if (magnitude > min_magnitude) {
+ return result(EXESS_OUT_OF_RANGE, i);
+ }
+
+ if (magnitude == min_magnitude) {
+ *out = INT16_MIN;
+ } else {
+ *out = (int16_t)-magnitude;
+ }
+ }
+
+ return result(r.count >= 4 ? EXESS_SUCCESS : EXESS_EXPECTED_DIGIT, i);
+}
+
+ExessResult
+write_year_number(const int16_t value, const size_t buf_size, char* const buf)
+{
+ const uint32_t abs_year = (uint32_t)abs(value);
+ const uint8_t n_digits = exess_num_digits(abs_year);
+ const bool is_negative = value < 0;
+
+ if (!buf) {
+ return result(EXESS_SUCCESS, is_negative + MAX(4u, n_digits));
+ }
+
+ // Write sign
+ size_t i = 0;
+ if (is_negative) {
+ i += write_char('-', buf_size, buf, i);
+ }
+
+ // Write leading zeros to ensure we have at least 4 year digits
+ for (size_t j = n_digits; j < 4; ++j) {
+ i += write_char('0', buf_size, buf, i);
+ }
+
+ const ExessResult yr = exess_write_uint(abs_year, buf_size - i, buf + i);
+
+ return end_write(yr.status, buf_size, buf, i + yr.count);
+}