/src/tarantool/third_party/c-dt/dt_parse_iso.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2012-2015 Christian Hansen <chansen@cpan.org> |
3 | | * <https://github.com/chansen/c-dt> |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions are met: |
8 | | * |
9 | | * 1. Redistributions of source code must retain the above copyright notice, this |
10 | | * list of conditions and the following disclaimer. |
11 | | * 2. Redistributions in binary form must reproduce the above copyright notice, |
12 | | * this list of conditions and the following disclaimer in the documentation |
13 | | * and/or other materials provided with the distribution. |
14 | | * |
15 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
16 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
17 | | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
18 | | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
19 | | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
20 | | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
21 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
22 | | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
24 | | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | | */ |
26 | | #include <stddef.h> |
27 | | #include "dt_core.h" |
28 | | #include "dt_valid.h" |
29 | | |
30 | | static size_t |
31 | 5.36k | count_digits(const unsigned char * const p, size_t i, const size_t len) { |
32 | 5.36k | const size_t n = i; |
33 | | |
34 | 17.5M | for(; i < len; i++) { |
35 | 17.5M | const unsigned char c = p[i] - '0'; |
36 | 17.5M | if (c > 9) |
37 | 4.93k | break; |
38 | 17.5M | } |
39 | 5.36k | return i - n; |
40 | 5.36k | } |
41 | | |
42 | | static int |
43 | 6.38k | parse_number(const unsigned char * const p, size_t i, const size_t len) { |
44 | 6.38k | int v = 0; |
45 | | |
46 | 6.38k | switch (len) { |
47 | 94 | case 9: v += (p[i++] - '0') * 100000000; |
48 | 102 | case 8: v += (p[i++] - '0') * 10000000; |
49 | 327 | case 7: v += (p[i++] - '0') * 1000000; |
50 | 384 | case 6: v += (p[i++] - '0') * 100000; |
51 | 467 | case 5: v += (p[i++] - '0') * 10000; |
52 | 1.45k | case 4: v += (p[i++] - '0') * 1000; |
53 | 3.38k | case 3: v += (p[i++] - '0') * 100; |
54 | 5.91k | case 2: v += (p[i++] - '0') * 10; |
55 | 6.38k | case 1: v += (p[i++] - '0'); |
56 | 6.38k | } |
57 | 6.38k | return v; |
58 | 6.38k | } |
59 | | |
60 | | static const int pow_10[10] = { |
61 | | 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, |
62 | | }; |
63 | | |
64 | | /* |
65 | | * fffffffff |
66 | | */ |
67 | | |
68 | | static size_t |
69 | 178 | parse_fraction_digits(const unsigned char *p, size_t i, size_t len, int *fp) { |
70 | 178 | size_t n, ndigits; |
71 | | |
72 | 178 | ndigits = n = count_digits(p, i, len); |
73 | 178 | if (ndigits < 1) |
74 | 4 | return 0; |
75 | 174 | if (ndigits > 9) |
76 | 88 | ndigits = 9; |
77 | 174 | if (fp) |
78 | 174 | *fp = parse_number(p, i, ndigits) * pow_10[9 - ndigits]; |
79 | 174 | return n; |
80 | 178 | } |
81 | | |
82 | | /* |
83 | | * hh |
84 | | * hhmm |
85 | | * hhmmss |
86 | | * hhmmss.fffffffff |
87 | | * hhmmss,fffffffff |
88 | | */ |
89 | | |
90 | | size_t |
91 | 1.08k | dt_parse_iso_time_basic(const char *str, size_t len, int *sp, int *fp) { |
92 | 1.08k | const unsigned char *p; |
93 | 1.08k | int h, m, s, f; |
94 | 1.08k | size_t n; |
95 | | |
96 | 1.08k | p = (const unsigned char *)str; |
97 | 1.08k | n = count_digits(p, 0, len); |
98 | 1.08k | m = s = f = 0; |
99 | 1.08k | switch (n) { |
100 | 858 | case 2: /* hh */ |
101 | 858 | h = parse_number(p, 0, 2); |
102 | 858 | goto hms; |
103 | 53 | case 4: /* hhmm */ |
104 | 53 | h = parse_number(p, 0, 2); |
105 | 53 | m = parse_number(p, 2, 2); |
106 | 53 | goto hms; |
107 | 148 | case 6: /* hhmmss */ |
108 | 148 | h = parse_number(p, 0, 2); |
109 | 148 | m = parse_number(p, 2, 2); |
110 | 148 | s = parse_number(p, 4, 2); |
111 | 148 | break; |
112 | 21 | default: |
113 | 21 | return 0; |
114 | 1.08k | } |
115 | | |
116 | | /* hhmmss.fffffffff */ |
117 | 148 | if (n < len && (p[n] == '.' || p[n] == ',')) { |
118 | 94 | size_t r = parse_fraction_digits(p, ++n, len, &f); |
119 | 94 | if (!r) |
120 | 2 | return 0; |
121 | 92 | n += r; |
122 | 92 | } |
123 | | |
124 | 1.05k | hms: |
125 | 1.05k | if (h > 23 || m > 59 || s > 59) { |
126 | 141 | if (!(h == 24 && m == 0 && s == 0 && f == 0)) |
127 | 84 | return 0; |
128 | 141 | } |
129 | | |
130 | 973 | if (sp) |
131 | 973 | *sp = h * 3600 + m * 60 + s; |
132 | 973 | if (fp) |
133 | 973 | *fp = f; |
134 | 973 | return n; |
135 | 1.05k | } |
136 | | |
137 | | /* |
138 | | * Z |
139 | | * ±hh |
140 | | * ±hhmm |
141 | | */ |
142 | | |
143 | | size_t |
144 | 0 | dt_parse_iso_zone_basic(const char *str, size_t len, int *op) { |
145 | 0 | const unsigned char *p; |
146 | 0 | int o, h, m, sign; |
147 | 0 | size_t n; |
148 | |
|
149 | 0 | if (len < 1) |
150 | 0 | return 0; |
151 | | |
152 | 0 | p = (const unsigned char *)str; |
153 | 0 | switch (*p) { |
154 | 0 | case 'Z': |
155 | 0 | o = 0; |
156 | 0 | n = 1; |
157 | 0 | goto zulu; |
158 | 0 | case '+': |
159 | 0 | sign = 1; |
160 | 0 | break; |
161 | 0 | case '-': |
162 | 0 | sign = -1; |
163 | 0 | break; |
164 | 0 | default: |
165 | 0 | return 0; |
166 | 0 | } |
167 | | |
168 | 0 | if (len < 3) |
169 | 0 | return 0; |
170 | | |
171 | 0 | n = count_digits(p, 1, len); |
172 | 0 | m = 0; |
173 | 0 | switch (n) { |
174 | 0 | case 2: /* ±hh */ |
175 | 0 | h = parse_number(p, 1, 2); |
176 | 0 | n = 3; |
177 | 0 | break; |
178 | 0 | case 4: /* ±hhmm */ |
179 | 0 | h = parse_number(p, 1, 2); |
180 | 0 | m = parse_number(p, 3, 2); |
181 | 0 | n = 5; |
182 | 0 | break; |
183 | 0 | default: |
184 | 0 | return 0; |
185 | 0 | } |
186 | | |
187 | 0 | if (h > 23 || m > 59) |
188 | 0 | return 0; |
189 | 0 | o = sign * (h * 60 + m); |
190 | | #ifdef DT_PARSE_ISO_STRICT |
191 | | if (o == 0 && sign < 0) |
192 | | return 0; |
193 | | #endif |
194 | |
|
195 | 0 | zulu: |
196 | 0 | if (op) |
197 | 0 | *op = o; |
198 | 0 | return n; |
199 | 0 | } |
200 | | |
201 | | /* |
202 | | * hh |
203 | | * hh:mm |
204 | | * hh:mm:ss |
205 | | * hh:mm:ss.fffffffff |
206 | | * hh:mm:ss,fffffffff |
207 | | */ |
208 | | |
209 | | size_t |
210 | 189 | dt_parse_iso_time_extended(const char *str, size_t len, int *sp, int *fp) { |
211 | 189 | const unsigned char *p; |
212 | 189 | int h, m, s, f; |
213 | 189 | size_t n; |
214 | | |
215 | 189 | p = (const unsigned char *)str; |
216 | 189 | if (count_digits(p, 0, len) != 2) |
217 | 2 | return 0; |
218 | | |
219 | 187 | h = parse_number(p, 0, 2); |
220 | 187 | m = s = f = 0; |
221 | 187 | n = 2; |
222 | | |
223 | 187 | if (len < 3 || p[2] != ':') |
224 | 0 | goto hms; |
225 | | |
226 | 187 | if (count_digits(p, 3, len) != 2) |
227 | 6 | return 0; |
228 | | |
229 | 181 | m = parse_number(p, 3, 2); |
230 | 181 | n = 5; |
231 | | |
232 | 181 | if (len < 6 || p[5] != ':') |
233 | 39 | goto hms; |
234 | | |
235 | 142 | if (count_digits(p, 6, len) != 2) |
236 | 32 | return 0; |
237 | | |
238 | 110 | s = parse_number(p, 6, 2); |
239 | 110 | n = 8; |
240 | | |
241 | | /* hh:mm:ss.fffffffff */ |
242 | 110 | if (n < len && (p[n] == '.' || p[n] == ',')) { |
243 | 84 | size_t r = parse_fraction_digits(p, ++n, len, &f); |
244 | 84 | if (!r) |
245 | 2 | return 0; |
246 | 82 | n += r; |
247 | 82 | } |
248 | | |
249 | 147 | hms: |
250 | 147 | if (h > 23 || m > 59 || s > 59) { |
251 | 81 | if (!(h == 24 && m == 0 && s == 0 && f == 0)) |
252 | 61 | return 0; |
253 | 81 | } |
254 | | |
255 | 86 | if (sp) |
256 | 86 | *sp = h * 3600 + m * 60 + s; |
257 | 86 | if (fp) |
258 | 86 | *fp = f; |
259 | 86 | return n; |
260 | 147 | } |
261 | | |
262 | | /* |
263 | | * Z |
264 | | * ±hh |
265 | | * ±hh:mm |
266 | | */ |
267 | | |
268 | | size_t |
269 | 0 | dt_parse_iso_zone_extended(const char *str, size_t len, int *op) { |
270 | 0 | const unsigned char *p; |
271 | 0 | int o, h, m, sign; |
272 | 0 | size_t n; |
273 | |
|
274 | 0 | if (len < 1) |
275 | 0 | return 0; |
276 | | |
277 | 0 | p = (const unsigned char *)str; |
278 | 0 | switch (*p) { |
279 | 0 | case 'Z': |
280 | 0 | o = 0; |
281 | 0 | n = 1; |
282 | 0 | goto zulu; |
283 | 0 | case '+': |
284 | 0 | sign = 1; |
285 | 0 | break; |
286 | 0 | case '-': |
287 | 0 | sign = -1; |
288 | 0 | break; |
289 | 0 | default: |
290 | 0 | return 0; |
291 | 0 | } |
292 | | |
293 | 0 | if (len < 3 || count_digits(p, 1, len) != 2) |
294 | 0 | return 0; |
295 | | |
296 | 0 | h = parse_number(p, 1, 2); |
297 | 0 | m = 0; |
298 | 0 | n = 3; |
299 | |
|
300 | 0 | if (len < 4 || p[3] != ':') |
301 | 0 | goto hm; |
302 | | |
303 | 0 | if (count_digits(p, 4, len) != 2) |
304 | 0 | return 0; |
305 | | |
306 | 0 | m = parse_number(p, 4, 2); |
307 | 0 | n = 6; |
308 | |
|
309 | 0 | hm: |
310 | 0 | if (h > 23 || m > 59) |
311 | 0 | return 0; |
312 | 0 | o = sign * (h * 60 + m); |
313 | | #ifdef DT_PARSE_ISO_STRICT |
314 | | if (o == 0 && sign < 0) |
315 | | return 0; |
316 | | #endif |
317 | |
|
318 | 0 | zulu: |
319 | 0 | if (op) |
320 | 0 | *op = o; |
321 | 0 | return n; |
322 | 0 | } |
323 | | |
324 | | /* |
325 | | * z |
326 | | * Z |
327 | | * GMT |
328 | | * GMT±h |
329 | | * GMT±hhmm |
330 | | * GMT±h:mm |
331 | | * GMT±hh:mm |
332 | | * UTC |
333 | | * UTC±h |
334 | | * UTC±hhmm |
335 | | * UTC±h:mm |
336 | | * UTC±hh:mm |
337 | | * ±h |
338 | | * ±hh |
339 | | * ±hhmm |
340 | | * ±h:mm |
341 | | * ±hh:mm |
342 | | */ |
343 | | |
344 | | size_t |
345 | 234 | dt_parse_iso_zone_lenient(const char *str, size_t len, int *op) { |
346 | 234 | const unsigned char *p; |
347 | 234 | int o, h, m, sign; |
348 | 234 | size_t n; |
349 | | |
350 | 234 | if (len < 1) |
351 | 0 | return 0; |
352 | | |
353 | 234 | p = (const unsigned char *)str; |
354 | 234 | switch (*p) { |
355 | 2 | case 'z': |
356 | 3 | case 'Z': |
357 | 3 | o = 0; |
358 | 3 | n = 1; |
359 | 3 | goto zulu; |
360 | 34 | case 'G': |
361 | 34 | if (len < 3 || p[1] != 'M' || p[2] != 'T') |
362 | 34 | return 0; |
363 | 0 | if (len > 3 && (p[3] == '+' || p[3] == '-')) { |
364 | 0 | if (!(n = dt_parse_iso_zone_lenient(str + 3, len - 3, op))) |
365 | 0 | return 0; |
366 | 0 | return n + 3; |
367 | 0 | } |
368 | 0 | o = 0; |
369 | 0 | n = 3; |
370 | 0 | goto zulu; |
371 | 6 | case 'U': |
372 | 6 | if (len < 3 || p[1] != 'T' || p[2] != 'C') |
373 | 6 | return 0; |
374 | 0 | if (len > 3 && (p[3] == '+' || p[3] == '-')) { |
375 | 0 | if (!(n = dt_parse_iso_zone_lenient(str + 3, len - 3, op))) |
376 | 0 | return 0; |
377 | 0 | return n + 3; |
378 | 0 | } |
379 | 0 | o = 0; |
380 | 0 | n = 3; |
381 | 0 | goto zulu; |
382 | 19 | case '+': |
383 | 19 | sign = 1; |
384 | 19 | break; |
385 | 107 | case '-': |
386 | 107 | sign = -1; |
387 | 107 | break; |
388 | 65 | default: |
389 | 65 | return 0; |
390 | 234 | } |
391 | | |
392 | 126 | if (len < 2) |
393 | 3 | return 0; |
394 | | |
395 | 123 | n = count_digits(p, 1, len); |
396 | 123 | m = 0; |
397 | 123 | switch (n) { |
398 | 49 | case 1: /* ±h */ |
399 | 49 | h = parse_number(p, 1, 1); |
400 | 49 | n = 2; |
401 | 49 | break; |
402 | 59 | case 2: /* ±hh */ |
403 | 59 | h = parse_number(p, 1, 2); |
404 | 59 | n = 3; |
405 | 59 | break; |
406 | 10 | case 4: /* ±hhmm */ |
407 | 10 | h = parse_number(p, 1, 2); |
408 | 10 | m = parse_number(p, 3, 2); |
409 | 10 | n = 5; |
410 | 10 | goto hm; |
411 | 5 | default: |
412 | 5 | return 0; |
413 | 123 | } |
414 | | |
415 | 108 | if (len < n + 1 || p[n] != ':') |
416 | 49 | goto hm; |
417 | | |
418 | 59 | if (count_digits(p, ++n, len) != 2) |
419 | 16 | return 0; |
420 | | |
421 | 43 | m = parse_number(p, n, 2); |
422 | 43 | n += 2; |
423 | | |
424 | 102 | hm: |
425 | 102 | if (h > 23 || m > 59) |
426 | 18 | return 0; |
427 | 84 | o = sign * (h * 60 + m); |
428 | | |
429 | 87 | zulu: |
430 | 87 | if (op) |
431 | 87 | *op = o; |
432 | 87 | return n; |
433 | 84 | } |
434 | | |
435 | | #ifdef DT_PARSE_ISO_TNT |
436 | | /* |
437 | | * Count number of delimiting dashes, Ws or Qs in date string like |
438 | | * 5879611-07-11, or 2012-Q4-85, or 10000W521 |
439 | | * Allows both ISO8601 and extended Tarantool datetime formats |
440 | | */ |
441 | | static size_t |
442 | 2.10k | count_delims(const unsigned char *p, size_t i, size_t len) { |
443 | 2.10k | size_t n = 0; |
444 | | |
445 | 15.0M | for (; i < len; i++) { |
446 | 15.0M | switch (p[i]) { |
447 | 11.6M | case '0': case '1': case '2': case '3': case '4': |
448 | 11.6M | case '5': case '6': case '7': case '8': case '9': |
449 | 11.6M | continue; |
450 | 78.8k | case 'Q': case 'W': |
451 | 3.33M | case '-': |
452 | 3.33M | n++; |
453 | 3.33M | continue; |
454 | 15.0M | } |
455 | 1.42k | break; |
456 | 15.0M | } |
457 | 2.10k | return n; |
458 | 2.10k | } |
459 | | #endif |
460 | | /* |
461 | | * Basic Extended |
462 | | * 20121224 2012-12-24 Calendar date (ISO 8601) |
463 | | * 2012359 2012-359 Ordinal date (ISO 8601) |
464 | | * 2012W521 2012-W52-1 Week date (ISO 8601) |
465 | | * 2012Q485 2012-Q4-85 Quarter date |
466 | | * |
467 | | * Tarantool extended ranges |
468 | | * #ifdef DT_PARSE_ISO_TNT |
469 | | * -001-12-31 0000-01-01 |
470 | | * -5879610-06-22 5879611-07-11 |
471 | | * #endif |
472 | | */ |
473 | | size_t |
474 | 2.10k | dt_parse_iso_date(const char *str, size_t len, dt_t *dtp) { |
475 | 2.10k | const unsigned char *p = (const unsigned char *)str; |
476 | 2.10k | int y, x, d; |
477 | 2.10k | size_t n; |
478 | 2.10k | dt_t dt; |
479 | 2.10k | int head_n; |
480 | 2.10k | #ifdef DT_PARSE_ISO_TNT |
481 | 2.10k | int sign = +1; |
482 | 2.10k | int dashes_n; |
483 | | |
484 | 2.10k | if (p[0] == '-') { |
485 | 219 | sign = -1; |
486 | 219 | p++; |
487 | 219 | len--; |
488 | 219 | } |
489 | 2.10k | dashes_n = count_delims(p, 0, len); |
490 | 2.10k | #endif |
491 | | |
492 | 2.10k | head_n = n = count_digits(p, 0, len); |
493 | 2.10k | switch (n) { |
494 | 0 | #ifdef DT_PARSE_ISO_TNT |
495 | 678 | case 3: /* -001-01-01 | 100W521 (extended Tarantool range) */ |
496 | 678 | if (!dashes_n) |
497 | 10 | return 0; |
498 | 668 | y = parse_number(p, 0, 3); |
499 | 668 | break; |
500 | 31 | case 4: /* -2001 (extended Tarantool range) | 2001-01-01 | 1000W521 */ |
501 | 31 | y = parse_number(p, 0, 4); |
502 | 31 | break; |
503 | 78 | case 5: /* 10000-01-01 | 10000W521 (extended Tarantool range) */ |
504 | 124 | case 6: /* 109000-01-01 | 109000W521 (extended Tarantool range) */ |
505 | 124 | if (!dashes_n) |
506 | 2 | return 0; |
507 | 122 | y = parse_number(p, 0, n); |
508 | 122 | break; |
509 | 1.12k | case 7: /* 5879611-07-11 | 1000000W521 (extended Tarantool range) */ |
510 | 1.12k | if (dashes_n > 0) { |
511 | 218 | y = parse_number(p, 0, 7); |
512 | 218 | break; |
513 | 218 | } |
514 | | /* 2012359 (basic ordinal date) */ |
515 | 906 | y = parse_number(p, 0, 4); |
516 | 906 | d = parse_number(p, 4, 3); |
517 | 906 | p += 7; |
518 | 906 | goto yd; |
519 | | #else |
520 | | case 4: /* 2012 (year) */ |
521 | | y = parse_number(p, 0, 4); |
522 | | break; |
523 | | case 7: /* 2012359 (basic ordinal date) */ |
524 | | y = parse_number(p, 0, 4); |
525 | | d = parse_number(p, 4, 3); |
526 | | p += 7; |
527 | | goto yd; |
528 | | #endif |
529 | 45 | case 8: /* 20121224 (basic calendar date) */ |
530 | 45 | y = parse_number(p, 0, 4); |
531 | 45 | x = parse_number(p, 4, 2); |
532 | 45 | d = parse_number(p, 6, 2); |
533 | 45 | p += 8; |
534 | 45 | goto ymd; |
535 | 102 | default: |
536 | 102 | return 0; |
537 | 2.10k | } |
538 | | |
539 | 1.03k | if (len < (n + 4)) |
540 | 18 | return 0; |
541 | | |
542 | 1.02k | p += n; |
543 | 1.02k | n = count_digits(p, 1, len); |
544 | 1.02k | switch (p[0]) { |
545 | 585 | case '-': /* 2012-359 | 2012-12-24 | 2012-W52-1 | 2012-Q4-85 */ |
546 | 585 | break; |
547 | 0 | #ifndef DT_PARSE_ISO_STRICT |
548 | 187 | case 'Q': /* 2012Q485 */ |
549 | 187 | if (n != 3) |
550 | 20 | return 0; |
551 | 167 | x = parse_number(p, 1, 1); |
552 | 167 | d = parse_number(p, 2, 2); |
553 | 167 | p += 4; |
554 | 167 | goto yqd; |
555 | 0 | #endif |
556 | 248 | case 'W': /* 2012W521 */ |
557 | 248 | if (n != 3) |
558 | 9 | return 0; |
559 | 239 | x = parse_number(p, 1, 2); |
560 | 239 | d = parse_number(p, 3, 1); |
561 | 239 | p += 4; |
562 | 239 | goto ywd; |
563 | 1 | default: |
564 | 1 | return 0; |
565 | 1.02k | } |
566 | | |
567 | 585 | switch (n) { |
568 | 207 | case 0: /* 2012-Q4-85 | 2012-W52-1 */ |
569 | 207 | break; |
570 | 32 | case 2: /* 2012-12-24 */ |
571 | 32 | if (p[3] != '-' || count_digits(p, 4, len) != 2) |
572 | 31 | return 0; |
573 | 1 | x = parse_number(p, 1, 2); |
574 | 1 | d = parse_number(p, 4, 2); |
575 | 1 | p += 6; |
576 | 1 | goto ymd; |
577 | 344 | case 3: /* 2012-359 */ |
578 | 344 | d = parse_number(p, 1, 3); |
579 | 344 | p += 4; |
580 | 344 | goto yd; |
581 | 2 | default: |
582 | 2 | return 0; |
583 | 585 | } |
584 | | |
585 | 207 | if (len < (head_n + 6)) |
586 | 3 | return 0; |
587 | | |
588 | 204 | n = count_digits(p, 2, len); |
589 | 204 | switch (p[1]) { |
590 | 0 | #ifndef DT_PARSE_ISO_STRICT |
591 | 58 | case 'Q': /* 2012-Q4-85 */ |
592 | 58 | if (n != 1 || p[3] != '-' || count_digits(p, 4, len) != 2) |
593 | 57 | return 0; |
594 | 1 | x = parse_number(p, 2, 1); |
595 | 1 | d = parse_number(p, 4, 2); |
596 | 1 | p += 6; |
597 | 1 | goto yqd; |
598 | 0 | #endif |
599 | 68 | case 'W': /* 2012-W52-1 */ |
600 | 68 | if (n != 2 || p[4] != '-' || count_digits(p, 5, len) != 1) |
601 | 65 | return 0; |
602 | 3 | x = parse_number(p, 2, 2); |
603 | 3 | d = parse_number(p, 5, 1); |
604 | 3 | p += 6;; |
605 | 3 | goto ywd; |
606 | 78 | default: |
607 | 78 | return 0; |
608 | 204 | } |
609 | | |
610 | 1.25k | yd: |
611 | 1.25k | #ifdef DT_PARSE_ISO_TNT |
612 | 1.25k | if (!dt_from_yd_checked(sign * y, d, &dt)) |
613 | 37 | return 0; |
614 | | #else |
615 | | if (!dt_valid_yd(y, d)) |
616 | | return 0; |
617 | | dt = dt_from_yd(y, d); |
618 | | #endif |
619 | 1.21k | goto finish; |
620 | | |
621 | 1.21k | ymd: |
622 | 46 | #ifdef DT_PARSE_ISO_TNT |
623 | 46 | if (!dt_from_ymd_checked(sign * y, x, d, &dt)) |
624 | 26 | return 0;; |
625 | | #else |
626 | | if (!dt_valid_ymd(y, x, d)) |
627 | | return 0; |
628 | | dt = dt_from_ymd(y, x, d); |
629 | | #endif |
630 | 26 | goto finish; |
631 | | |
632 | 0 | #ifndef DT_PARSE_ISO_STRICT |
633 | 168 | yqd: |
634 | 168 | #ifdef DT_PARSE_ISO_TNT |
635 | 168 | if (!dt_from_yqd_checked(sign * y, x, d, &dt)) |
636 | 20 | return 0; |
637 | | #else |
638 | | if (!dt_valid_yqd(y, x, d)) |
639 | | return 0; |
640 | | dt = dt_from_yqd(y, x, d); |
641 | | #endif |
642 | 148 | goto finish; |
643 | 148 | #endif |
644 | | |
645 | 242 | ywd: |
646 | 242 | #ifdef DT_PARSE_ISO_TNT |
647 | 242 | if (!dt_from_ywd_checked(sign * y, x, d, &dt)) |
648 | 49 | return 0; |
649 | | #else |
650 | | if (!dt_valid_ywd(y, x, d)) |
651 | | return 0; |
652 | | dt = dt_from_ywd(y, x, d); |
653 | | #endif |
654 | | |
655 | 1.58k | finish: |
656 | | #ifndef DT_PARSE_ISO_YEAR0 |
657 | | if (y < 1) |
658 | | return 0; |
659 | | #endif |
660 | 1.58k | if (dtp) |
661 | 1.58k | *dtp = dt; |
662 | 1.58k | return (p - (const unsigned char *)str); |
663 | 242 | } |
664 | | |
665 | | /* |
666 | | * Basic Extended |
667 | | * T12 N/A |
668 | | * T1230 T12:30 |
669 | | * T123045 T12:30:45 |
670 | | * T123045.123456789 T12:30:45.123456789 |
671 | | * T123045,123456789 T12:30:45,123456789 |
672 | | * |
673 | | * The time designator [T] may be omitted. |
674 | | */ |
675 | | |
676 | | size_t |
677 | 1.27k | dt_parse_iso_time(const char *str, size_t len, int *sod, int *nsec) { |
678 | 1.27k | size_t n, r; |
679 | | |
680 | 1.27k | if (len < 2) |
681 | 1 | return 0; |
682 | | |
683 | 1.26k | if (str[0] == 'T') |
684 | 4 | r = 1, ++str, --len; |
685 | 1.26k | else |
686 | 1.26k | r = 0; |
687 | | |
688 | 1.26k | if (len < 2 || str[2] == ':') |
689 | 189 | n = dt_parse_iso_time_extended(str, len, sod, nsec); |
690 | 1.08k | else |
691 | 1.08k | n = dt_parse_iso_time_basic(str, len, sod, nsec); |
692 | | |
693 | 1.26k | if (!n) |
694 | 210 | return 0; |
695 | 1.05k | return r + n; |
696 | 1.26k | } |
697 | | |
698 | | /* |
699 | | * Basic Extended |
700 | | * Z N/A |
701 | | * ±hh N/A |
702 | | * ±hhmm ±hh:mm |
703 | | */ |
704 | | |
705 | | size_t |
706 | 0 | dt_parse_iso_zone(const char *str, size_t len, int *offset) { |
707 | 0 | if (len < 3 || str[3] == ':') |
708 | 0 | return dt_parse_iso_zone_extended(str, len, offset); |
709 | 0 | else |
710 | 0 | return dt_parse_iso_zone_basic(str, len, offset); |
711 | 0 | } |
712 | | |