Branch data Line data Source code
1 : : // Copyright 2019-2026 David Robillard <d@drobilla.net>
2 : : // SPDX-License-Identifier: ISC
3 : :
4 : : #include "timezone.h"
5 : : #include "number_utils.h"
6 : : #include "result.h"
7 : : #include "write_utils.h"
8 : :
9 : : #include <exess/exess.h>
10 : :
11 : : #include <stdint.h>
12 : : #include <stdlib.h>
13 : :
14 : : EXESS_NONBLOCKING ExessTimezone
15 : 130 : exess_timezone(const int8_t hours, const int8_t minutes)
16 : : {
17 [ + + + + ]: 130 : if (hours < -14 || hours > 14) {
18 : 2 : return EXESS_TIMEZONE_LOCAL;
19 : : }
20 : :
21 [ + + + + : 128 : if (hours < 0 && minutes != 0 && minutes != -15 && minutes != -30 &&
+ + + + +
+ ]
22 : : minutes != -45) {
23 : 2 : return EXESS_TIMEZONE_LOCAL;
24 : : }
25 : :
26 [ + + + + : 126 : if (hours > 0 && minutes != 0 && minutes != 15 && minutes != 30 &&
+ + + + +
+ ]
27 : : minutes != 45) {
28 : 2 : return EXESS_TIMEZONE_LOCAL;
29 : : }
30 : :
31 : 124 : return (int8_t)((4 * hours) + (minutes / 15));
32 : : }
33 : :
34 : : EXESS_NONBLOCKING ExessResult
35 : 6555 : read_optional_timezone(ExessTimezone* const out,
36 : : const char* const str,
37 : : ExessResult r)
38 : : {
39 : 6555 : *out = EXESS_TIMEZONE_LOCAL;
40 : :
41 [ + + ]: 6555 : if (r.status) {
42 : 56 : return r;
43 : : }
44 : :
45 : : // Handle UTC special case
46 : 6499 : size_t i = r.count;
47 [ + + ]: 6499 : if (str[i] == 'Z') {
48 : 188 : *out = 0;
49 : 188 : return RESULT(EXESS_SUCCESS, i + 1);
50 : : }
51 : :
52 : : // Read leading sign
53 : 6311 : int sign = 1;
54 [ + + ]: 6311 : if (str[i] == '-') {
55 : 2212 : sign = -1;
56 [ + + ]: 4099 : } else if (str[i] != '+') {
57 : 1761 : return RESULT(EXESS_SUCCESS, i);
58 : : }
59 : :
60 : 4550 : ++i;
61 : :
62 : : // Read hour digits
63 : 4550 : uint8_t hh = 0U;
64 : 4550 : r = read_two_digit_number(&hh, 0U, 14U, str + i);
65 [ + + ]: 4550 : if (r.status) {
66 : 8 : return RESULT(r.status, i + r.count);
67 : : }
68 : :
69 : 4542 : i += 2U;
70 : :
71 : : // Check colon
72 [ + + ]: 4542 : if (str[i] != ':') {
73 : 1 : return RESULT(EXESS_EXPECTED_COLON, i);
74 : : }
75 : :
76 : 4541 : ++i;
77 : :
78 : : // Read minute digits
79 : 4541 : uint8_t mm = 0U;
80 : 4541 : r = read_two_digit_number(&mm, 0U, 59U, str + i);
81 [ + + ]: 4541 : if (r.status) {
82 : 4 : return RESULT(r.status, i + r.count);
83 : : }
84 : :
85 : 4537 : i += 2U;
86 : :
87 : : // Calculate signed hour and minute
88 : 4537 : const int8_t hour = (int8_t)(sign * hh);
89 : 4537 : const int8_t minute = (int8_t)(sign * mm);
90 [ + + ]: 4537 : if (minute % 15) {
91 : 1 : return RESULT(EXESS_UNSUPPORTED, i);
92 : : }
93 : :
94 : : // Convert to quarter hours
95 : 4536 : const int8_t quarters = (int8_t)((4 * hour) + (minute / 15));
96 [ + + + + ]: 4536 : if (quarters < -56 || quarters > 56) {
97 : 2 : return RESULT(EXESS_OUT_OF_RANGE, i);
98 : : }
99 : :
100 : 4534 : *out = quarters;
101 : 4534 : return RESULT(EXESS_SUCCESS, i);
102 : : }
103 : :
104 : : EXESS_NONBLOCKING ExessResult
105 : 6284 : write_timezone(const ExessTimezone value,
106 : : const size_t buf_size,
107 : : char* const buf,
108 : : const ExessResult r)
109 : : {
110 : 6284 : size_t o = r.count;
111 : :
112 [ + + ]: 6284 : if (value == EXESS_TIMEZONE_LOCAL) {
113 : 1645 : return end_write(r.status, buf_size, buf, o);
114 : : }
115 : :
116 [ + + + + ]: 4639 : if (value < -56 || value > 56) {
117 : 4 : return end_write(EXESS_BAD_VALUE, buf_size, buf, o);
118 : : }
119 : :
120 [ + + ]: 4635 : if (value == 0) {
121 : 131 : write_char('Z', buf_size, buf, o);
122 : 131 : return end_write(r.status, buf_size, buf, o + 1U);
123 : : }
124 : :
125 : 4504 : const uint8_t abs_quarters = (uint8_t)abs(value);
126 : 4504 : const uint8_t abs_hour = abs_quarters / 4;
127 : 4504 : const uint8_t abs_minute = (uint8_t)(15U * (abs_quarters % 4U));
128 : :
129 [ + + ]: 4504 : o += write_char(value < 0 ? '-' : '+', buf_size, buf, o);
130 : 4504 : o += write_two_digit_number(abs_hour, buf_size, buf, o);
131 : 4504 : o += write_char(':', buf_size, buf, o);
132 : 4504 : o += write_two_digit_number(abs_minute, buf_size, buf, o);
133 : :
134 : 4504 : return end_write(EXESS_SUCCESS, buf_size, buf, o);
135 : : }
|