@@ -67,19 +67,15 @@ This file implements string parsing and creation for NumPy datetime.
67
67
* Returns 0 on success, -1 on failure.
68
68
*/
69
69
70
- #define FORMAT_STARTSWITH (ch ) \
71
- /* Always error on character mismatch conditioned on non-exhausted format, \
72
- or when format is exhausted in the exact case. */ \
73
- if ((format_len && *format != ch) || (exact && !format_len)){ \
74
- goto parse_error; \
75
- } \
76
- /* Advance if format is not exhausted */ \
77
- if (format_len ) { \
78
- ++ format ; \
79
- -- format_len ; \
80
- } \
70
+ int format_startswith (char ch , int format_len , char format , int exact ) {
71
+ if ((format_len && format != ch ) || (exact && !format_len )) {
72
+ return 0 ;
73
+ }
74
+ return 1 ;
75
+ }
81
76
82
77
int parse_iso_8601_datetime (const char * str , int len , int want_exc ,
78
+
83
79
npy_datetimestruct * out ,
84
80
NPY_DATETIMEUNIT * out_bestunit ,
85
81
int * out_local , int * out_tzoffset ,
@@ -118,18 +114,22 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
118
114
while (sublen > 0 && isspace (* substr )) {
119
115
++ substr ;
120
116
-- sublen ;
121
- FORMAT_STARTSWITH (' ' );
117
+ if (!format_startswith (' ' , format_len , * format , exact )) goto parse_error ;
118
+ if (format_len ) {++ format ; -- format_len ;}
122
119
}
123
120
124
121
/* Leading '-' sign for negative year */
125
122
if (* substr == '-' ) {
126
123
++ substr ;
127
124
-- sublen ;
128
- FORMAT_STARTSWITH ('-' );
125
+ if (!format_startswith ('-' , format_len , * format , exact )) goto parse_error ;
126
+ if (format_len ) {++ format ; -- format_len ;}
129
127
}
130
128
131
- FORMAT_STARTSWITH ('%' );
132
- FORMAT_STARTSWITH ('Y' );
129
+ if (!format_startswith ('%' , format_len , * format , exact )) goto parse_error ;
130
+ if (format_len ) {++ format ; -- format_len ;}
131
+ if (!format_startswith ('Y' , format_len , * format , exact )) goto parse_error ;
132
+ if (format_len ) {++ format ; -- format_len ;}
133
133
134
134
if (sublen == 0 ) {
135
135
goto parse_error ;
@@ -178,7 +178,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
178
178
ymd_sep = valid_ymd_sep [i ];
179
179
++ substr ;
180
180
-- sublen ;
181
- FORMAT_STARTSWITH (ymd_sep );
181
+ if (!format_startswith (ymd_sep , format_len , * format , exact )) goto parse_error ;
182
+ if (format_len ) {++ format ; -- format_len ;}
182
183
/* Cannot have trailing separator */
183
184
if (sublen == 0 || !isdigit (* substr )) {
184
185
goto parse_error ;
@@ -190,8 +191,10 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
190
191
out -> month = (* substr - '0' );
191
192
++ substr ;
192
193
-- sublen ;
193
- FORMAT_STARTSWITH ('%' );
194
- FORMAT_STARTSWITH ('m' );
194
+ if (!format_startswith ('%' , format_len , * format , exact )) goto parse_error ;
195
+ if (format_len ) {++ format ; -- format_len ;}
196
+ if (!format_startswith ('m' , format_len , * format , exact )) goto parse_error ;
197
+ if (format_len ) {++ format ; -- format_len ;}
195
198
/* Second digit optional if there was a separator */
196
199
if (isdigit (* substr )) {
197
200
out -> month = 10 * out -> month + (* substr - '0' );
@@ -231,7 +234,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
231
234
}
232
235
++ substr ;
233
236
-- sublen ;
234
- FORMAT_STARTSWITH (ymd_sep );
237
+ if (!format_startswith (ymd_sep , format_len , * format , exact )) goto parse_error ;
238
+ if (format_len ) {++ format ; -- format_len ;}
235
239
}
236
240
237
241
/* PARSE THE DAY */
@@ -242,8 +246,10 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
242
246
out -> day = (* substr - '0' );
243
247
++ substr ;
244
248
-- sublen ;
245
- FORMAT_STARTSWITH ('%' );
246
- FORMAT_STARTSWITH ('d' );
249
+ if (!format_startswith ('%' , format_len , * format , exact )) goto parse_error ;
250
+ if (format_len ) {++ format ; -- format_len ;}
251
+ if (!format_startswith ('d' , format_len , * format , exact )) goto parse_error ;
252
+ if (format_len ) {++ format ; -- format_len ;}
247
253
/* Second digit optional if there was a separator */
248
254
if (isdigit (* substr )) {
249
255
out -> day = 10 * out -> day + (* substr - '0' );
@@ -276,7 +282,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
276
282
if ((* substr != 'T' && * substr != ' ' ) || sublen == 1 ) {
277
283
goto parse_error ;
278
284
}
279
- FORMAT_STARTSWITH (* substr );
285
+ if (!format_startswith (* substr , format_len , * format , exact )) goto parse_error ;
286
+ if (format_len ) {++ format ; -- format_len ;}
280
287
++ substr ;
281
288
-- sublen ;
282
289
@@ -285,8 +292,10 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
285
292
if (!isdigit (* substr )) {
286
293
goto parse_error ;
287
294
}
288
- FORMAT_STARTSWITH ('%' );
289
- FORMAT_STARTSWITH ('H' );
295
+ if (!format_startswith ('%' , format_len , * format , exact )) goto parse_error ;
296
+ if (format_len ) {++ format ; -- format_len ;}
297
+ if (!format_startswith ('H' , format_len , * format , exact )) goto parse_error ;
298
+ if (format_len ) {++ format ; -- format_len ;}
290
299
out -> hour = (* substr - '0' );
291
300
++ substr ;
292
301
-- sublen ;
@@ -326,7 +335,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
326
335
if (sublen == 0 || !isdigit (* substr )) {
327
336
goto parse_error ;
328
337
}
329
- FORMAT_STARTSWITH (':' );
338
+ if (!format_startswith (':' , format_len , * format , exact )) goto parse_error ;
339
+ if (format_len ) {++ format ; -- format_len ;}
330
340
} else if (!isdigit (* substr )) {
331
341
if (!hour_was_2_digits ) {
332
342
goto parse_error ;
@@ -339,8 +349,10 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
339
349
out -> min = (* substr - '0' );
340
350
++ substr ;
341
351
-- sublen ;
342
- FORMAT_STARTSWITH ('%' );
343
- FORMAT_STARTSWITH ('M' );
352
+ if (!format_startswith ('%' , format_len , * format , exact )) goto parse_error ;
353
+ if (format_len ) {++ format ; -- format_len ;}
354
+ if (!format_startswith ('M' , format_len , * format , exact )) goto parse_error ;
355
+ if (format_len ) {++ format ; -- format_len ;}
344
356
/* Second digit optional if there was a separator */
345
357
if (isdigit (* substr )) {
346
358
out -> min = 10 * out -> min + (* substr - '0' );
@@ -369,7 +381,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
369
381
/* If we make it through this condition block, then the next
370
382
* character is a digit. */
371
383
if (has_hms_sep && * substr == ':' ) {
372
- FORMAT_STARTSWITH (':' );
384
+ if (!format_startswith (':' , format_len , * format , exact )) goto parse_error ;
385
+ if (format_len ) {++ format ; -- format_len ;}
373
386
++ substr ;
374
387
-- sublen ;
375
388
/* Cannot have a trailing ':' */
@@ -386,8 +399,10 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
386
399
out -> sec = (* substr - '0' );
387
400
++ substr ;
388
401
-- sublen ;
389
- FORMAT_STARTSWITH ('%' );
390
- FORMAT_STARTSWITH ('S' );
402
+ if (!format_startswith ('%' , format_len , * format , exact )) goto parse_error ;
403
+ if (format_len ) {++ format ; -- format_len ;}
404
+ if (!format_startswith ('S' , format_len , * format , exact )) goto parse_error ;
405
+ if (format_len ) {++ format ; -- format_len ;}
391
406
/* Second digit optional if there was a separator */
392
407
if (isdigit (* substr )) {
393
408
out -> sec = 10 * out -> sec + (* substr - '0' );
@@ -409,15 +424,18 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
409
424
if (sublen > 0 && * substr == '.' ) {
410
425
++ substr ;
411
426
-- sublen ;
412
- FORMAT_STARTSWITH ('.' );
427
+ if (!format_startswith ('.' , format_len , * format , exact )) goto parse_error ;
428
+ if (format_len ) {++ format ; -- format_len ;}
413
429
} else {
414
430
bestunit = NPY_FR_s ;
415
431
goto parse_timezone ;
416
432
}
417
433
418
434
/* PARSE THE MICROSECONDS (0 to 6 digits) */
419
- FORMAT_STARTSWITH ('%' );
420
- FORMAT_STARTSWITH ('f' );
435
+ if (!format_startswith ('%' , format_len , * format , exact )) goto parse_error ;
436
+ if (format_len ) {++ format ; -- format_len ;}
437
+ if (!format_startswith ('f' , format_len , * format , exact )) goto parse_error ;
438
+ if (format_len ) {++ format ; -- format_len ;}
421
439
numdigits = 0 ;
422
440
for (i = 0 ; i < 6 ; ++ i ) {
423
441
out -> us *= 10 ;
@@ -482,7 +500,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
482
500
while (sublen > 0 && isspace (* substr )) {
483
501
++ substr ;
484
502
-- sublen ;
485
- FORMAT_STARTSWITH (' ' );
503
+ if (!format_startswith (' ' , format_len , * format , exact )) goto parse_error ;
504
+ if (format_len ) {++ format ; -- format_len ;}
486
505
}
487
506
488
507
if (sublen == 0 ) {
@@ -495,8 +514,10 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
495
514
496
515
/* UTC specifier */
497
516
if (* substr == 'Z' ) {
498
- FORMAT_STARTSWITH ('%' );
499
- FORMAT_STARTSWITH ('Z' );
517
+ if (!format_startswith ('%' , format_len , * format , exact )) goto parse_error ;
518
+ if (format_len ) {++ format ; -- format_len ;}
519
+ if (!format_startswith ('Z' , format_len , * format , exact )) goto parse_error ;
520
+ if (format_len ) {++ format ; -- format_len ;}
500
521
501
522
/* "Z" should be equivalent to tz offset "+00:00" */
502
523
if (out_local != NULL ) {
@@ -517,8 +538,10 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
517
538
-- sublen ;
518
539
}
519
540
} else if (* substr == '-' || * substr == '+' ) {
520
- FORMAT_STARTSWITH ('%' );
521
- FORMAT_STARTSWITH ('z' );
541
+ if (!format_startswith ('%' , format_len , * format , exact )) goto parse_error ;
542
+ if (format_len ) {++ format ; -- format_len ;}
543
+ if (!format_startswith ('z' , format_len , * format , exact )) goto parse_error ;
544
+ if (format_len ) {++ format ; -- format_len ;}
522
545
/* Time zone offset */
523
546
int offset_neg = 0 , offset_hour = 0 , offset_minute = 0 ;
524
547
@@ -602,7 +625,8 @@ int parse_iso_8601_datetime(const char *str, int len, int want_exc,
602
625
while (sublen > 0 && isspace (* substr )) {
603
626
++ substr ;
604
627
-- sublen ;
605
- FORMAT_STARTSWITH (' ' );
628
+ if (!format_startswith (' ' , format_len , * format , exact )) goto parse_error ;
629
+ if (format_len ) {++ format ; -- format_len ;}
606
630
}
607
631
608
632
if ((sublen != 0 ) || (format_len != 0 )) {
0 commit comments