blob: 38e9d03169f257cc00e8051a87c40a73a7611ae3 [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;
42 w = strtoul(f, &new_f, 10);
43 f = new_f;
44 } else {
45 w = -1;
46 }
47 adj = 0;
48 switch (*f++) {
49 case 'a':
50 case 'A':
51 case 'b':
52 case 'B':
53 case 'h':
54 case 'c':
55 goto fail_nl_langinfo;
56 case 'C':
57 dest = &century;
58 if (w < 0) {
59 w = 2;
60 }
61 want_century |= 2;
62 goto numeric_digits;
63 case 'd':
64 case 'e':
65 dest = &tm->tm_mday;
66 min = 1;
67 range = 31;
68 goto numeric_range;
69 case 'D':
70 s = strptime(s, "%m/%d/%y", tm);
71 if (!s) {
72 return 0;
73 }
74 break;
75 case 'H':
76 dest = &tm->tm_hour;
77 min = 0;
78 range = 24;
79 goto numeric_range;
80 case 'I':
81 dest = &tm->tm_hour;
82 min = 1;
83 range = 12;
84 goto numeric_range;
85 case 'j':
86 dest = &tm->tm_yday;
87 min = 1;
88 range = 366;
89 adj = 1;
90 goto numeric_range;
91 case 'm':
92 dest = &tm->tm_mon;
93 min = 1;
94 range = 12;
95 adj = 1;
96 goto numeric_range;
97 case 'M':
98 dest = &tm->tm_min;
99 min = 0;
100 range = 60;
101 goto numeric_range;
102 case 'n':
103 case 't':
104 for ( ; *s && isspace(*s); s++) {}
105 break;
106 case 'p':
107 case 'r':
108 goto fail_nl_langinfo;
109 case 'R':
110 s = strptime(s, "%H:%M", tm);
111 if (!s) {
112 return 0;
113 }
114 break;
115 case 'S':
116 dest = &tm->tm_sec;
117 min = 0;
118 range = 61;
119 goto numeric_range;
120 case 'T':
121 s = strptime(s, "%H:%M:%S", tm);
122 if (!s) {
123 return 0;
124 }
125 break;
126 case 'U':
127 case 'W':
128 /* Throw away result, for now. (FIXME?) */
129 dest = &dummy;
130 min = 0;
131 range = 54;
132 goto numeric_range;
133 case 'w':
134 dest = &tm->tm_wday;
135 min = 0;
136 range = 7;
137 goto numeric_range;
138 case 'x':
139 case 'X':
140 goto fail_nl_langinfo;
141 case 'y':
142 dest = &relyear;
143 w = 2;
144 want_century |= 1;
145 goto numeric_digits;
146 case 'Y':
147 dest = &tm->tm_year;
148 if (w < 0) {
149 w = 4;
150 }
151 adj = 1900;
152 want_century = 0;
153 goto numeric_digits;
154 case '%':
155 if (*s++ != '%') {
156 return 0;
157 }
158 break;
159 default:
160 return 0;
161numeric_range:
162 if (!isdigit(*s)) {
163 return 0;
164 }
165 *dest = 0;
166 for (i = 1; i <= min + range && isdigit(*s); i *= 10) {
167 *dest = *dest * 10 + *s++ - '0';
168 }
169 if (*dest - min >= (unsigned)range) {
170 return 0;
171 }
172 *dest -= adj;
173 switch ((char *)dest - (char *)tm) {
174 case offsetof(struct tm, tm_yday):
175 ;
176 }
177 goto update;
178numeric_digits:
179 neg = 0;
180 if (*s == '+') {
181 s++;
182 } else if (*s == '-') {
183 neg = 1, s++;
184 }
185 if (!isdigit(*s)) {
186 return 0;
187 }
188 for (*dest = i = 0; i < w && isdigit(*s); i++) {
189 *dest = *dest * 10 + *s++ - '0';
190 }
191 if (neg) {
192 *dest = -*dest;
193 }
194 *dest -= adj;
195 goto update;
196update:
197 // FIXME
198 ;
199 }
200 }
201 if (want_century) {
202 tm->tm_year = relyear;
203 if (want_century & 2) {
204 tm->tm_year += century * 100 - 1900;
205 } else if (tm->tm_year <= 68) {
206 tm->tm_year += 100;
207 }
208 }
209 return (char *)s;
Jan Kundrát3b30ba12021-12-11 00:46:58 +0100210fail_nl_langinfo:
Jan Kundrát7e462e42021-12-16 02:01:26 +0100211 fprintf(stderr, "strptime: nl_langinfo not available");
212 return NULL;
Jan Kundráta5a7e292021-12-10 17:37:46 +0100213}