blob: 4044fc9e58b06c7dd775a95f333b4ae9dd565e99 [file] [log] [blame]
Jan Kundráta5a7e292021-12-10 17:37:46 +01001/*
2 * This comes from the musl C library which has been licensed under the permissive MIT license.
3 *
4 * Downloaded from https://git.musl-libc.org/cgit/musl/plain/src/time/strptime.c,
5 * commit 98e688a9da5e7b2925dda17a2d6820dddf1fb287.
Jan Kundrát3b30ba12021-12-11 00:46:58 +01006 *
7 * Lobotomized to remove references to nl_langinfo().
Jan Kundrát7e462e42021-12-16 02:01:26 +01008 * Adjusted coding style to fit libyang's uncrustify rules.
Jan Kundráta5a7e292021-12-10 17:37:46 +01009 * */
10
Jan Kundráta5a7e292021-12-10 17:37:46 +010011#include <ctype.h>
12#include <stddef.h>
Jan Kundrát7e462e42021-12-16 02:01:26 +010013#include <stdio.h>
14#include <stdlib.h>
Jan Kundráta5a7e292021-12-10 17:37:46 +010015#include <string.h>
Jan Kundrát7e462e42021-12-16 02:01:26 +010016#include <time.h>
Jan Kundráta5a7e292021-12-10 17:37:46 +010017
Jan Kundrát7e462e42021-12-16 02:01:26 +010018char *
19strptime(const char * restrict s, const char * restrict f, struct tm * restrict tm)
Jan Kundráta5a7e292021-12-10 17:37:46 +010020{
Jan Kundrát7e462e42021-12-16 02:01:26 +010021 int i, w, neg, adj, min, range, *dest, dummy;
22 int want_century = 0, century = 0, relyear = 0;
23
24 while (*f) {
25 if (*f != '%') {
26 if (isspace(*f)) {
27 for ( ; *s && isspace(*s); s++) {}
28 } else if (*s != *f) {
29 return 0;
30 } else {
31 s++;
32 }
33 f++;
34 continue;
35 }
36 f++;
37 if (*f == '+') {
38 f++;
39 }
40 if (isdigit(*f)) {
41 char *new_f;
Michal Vasko26bbb272022-08-02 14:54:33 +020042
Jan Kundrát7e462e42021-12-16 02:01:26 +010043 w = strtoul(f, &new_f, 10);
44 f = new_f;
45 } else {
46 w = -1;
47 }
48 adj = 0;
49 switch (*f++) {
50 case 'a':
51 case 'A':
52 case 'b':
53 case 'B':
54 case 'h':
55 case 'c':
56 goto fail_nl_langinfo;
57 case 'C':
58 dest = &century;
59 if (w < 0) {
60 w = 2;
61 }
62 want_century |= 2;
63 goto numeric_digits;
64 case 'd':
65 case 'e':
66 dest = &tm->tm_mday;
67 min = 1;
68 range = 31;
69 goto numeric_range;
70 case 'D':
71 s = strptime(s, "%m/%d/%y", tm);
72 if (!s) {
73 return 0;
74 }
75 break;
76 case 'H':
77 dest = &tm->tm_hour;
78 min = 0;
79 range = 24;
80 goto numeric_range;
81 case 'I':
82 dest = &tm->tm_hour;
83 min = 1;
84 range = 12;
85 goto numeric_range;
86 case 'j':
87 dest = &tm->tm_yday;
88 min = 1;
89 range = 366;
90 adj = 1;
91 goto numeric_range;
92 case 'm':
93 dest = &tm->tm_mon;
94 min = 1;
95 range = 12;
96 adj = 1;
97 goto numeric_range;
98 case 'M':
99 dest = &tm->tm_min;
100 min = 0;
101 range = 60;
102 goto numeric_range;
103 case 'n':
104 case 't':
105 for ( ; *s && isspace(*s); s++) {}
106 break;
107 case 'p':
108 case 'r':
109 goto fail_nl_langinfo;
110 case 'R':
111 s = strptime(s, "%H:%M", tm);
112 if (!s) {
113 return 0;
114 }
115 break;
116 case 'S':
117 dest = &tm->tm_sec;
118 min = 0;
119 range = 61;
120 goto numeric_range;
121 case 'T':
122 s = strptime(s, "%H:%M:%S", tm);
123 if (!s) {
124 return 0;
125 }
126 break;
127 case 'U':
128 case 'W':
129 /* Throw away result, for now. (FIXME?) */
130 dest = &dummy;
131 min = 0;
132 range = 54;
133 goto numeric_range;
134 case 'w':
135 dest = &tm->tm_wday;
136 min = 0;
137 range = 7;
138 goto numeric_range;
139 case 'x':
140 case 'X':
141 goto fail_nl_langinfo;
142 case 'y':
143 dest = &relyear;
144 w = 2;
145 want_century |= 1;
146 goto numeric_digits;
147 case 'Y':
148 dest = &tm->tm_year;
149 if (w < 0) {
150 w = 4;
151 }
152 adj = 1900;
153 want_century = 0;
154 goto numeric_digits;
155 case '%':
156 if (*s++ != '%') {
157 return 0;
158 }
159 break;
160 default:
161 return 0;
162numeric_range:
163 if (!isdigit(*s)) {
164 return 0;
165 }
166 *dest = 0;
167 for (i = 1; i <= min + range && isdigit(*s); i *= 10) {
168 *dest = *dest * 10 + *s++ - '0';
169 }
Donatas Abraitisd21d2572022-06-09 19:14:42 +0300170 if (*dest - min >= range) {
Jan Kundrát7e462e42021-12-16 02:01:26 +0100171 return 0;
172 }
173 *dest -= adj;
174 switch ((char *)dest - (char *)tm) {
175 case offsetof(struct tm, tm_yday):
176 ;
177 }
178 goto update;
179numeric_digits:
180 neg = 0;
181 if (*s == '+') {
182 s++;
183 } else if (*s == '-') {
184 neg = 1, s++;
185 }
186 if (!isdigit(*s)) {
187 return 0;
188 }
189 for (*dest = i = 0; i < w && isdigit(*s); i++) {
190 *dest = *dest * 10 + *s++ - '0';
191 }
192 if (neg) {
193 *dest = -*dest;
194 }
195 *dest -= adj;
196 goto update;
197update:
198 // FIXME
199 ;
200 }
201 }
202 if (want_century) {
203 tm->tm_year = relyear;
204 if (want_century & 2) {
205 tm->tm_year += century * 100 - 1900;
206 } else if (tm->tm_year <= 68) {
207 tm->tm_year += 100;
208 }
209 }
210 return (char *)s;
Jan Kundrát3b30ba12021-12-11 00:46:58 +0100211fail_nl_langinfo:
Jan Kundrát7e462e42021-12-16 02:01:26 +0100212 fprintf(stderr, "strptime: nl_langinfo not available");
213 return NULL;
Jan Kundráta5a7e292021-12-10 17:37:46 +0100214}