diff --git a/src/libiso8601/parser.c b/src/libiso8601/parser.c index 5e4b841..9b4ff7d 100644 --- a/src/libiso8601/parser.c +++ b/src/libiso8601/parser.c @@ -34,7 +34,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 div_t qr; char ch; - int num = 0, neg = 0, dig = 0, tz_neg = 0, nsec = -1, nsec_dig = -1; + int num = 0, neg = 0, dig = 0, tz_neg = 0, nsec = -1, nsec_dig = -1, leap_sec_req = 0; int y = 0, m = -1, d = -1, w = -1, wd = -1, hour = -1, min = -1, sec = -1, tz_sec = 0; double frac; @@ -47,14 +47,12 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 num *= 10; \ num += ch - '0'; \ if(num > 1000000000) { \ - errno = EDOM; \ return -1; \ } \ }while(0) #define ERROR_IF(x) do { \ if(x) { \ - errno = EILSEQ; \ return -1; \ } \ }while(0) @@ -77,7 +75,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 break; default: - errno = EILSEQ; return -1; } break; @@ -127,7 +124,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 break; default: - errno = EILSEQ; return -1; } if(!ch) goto done; @@ -162,7 +158,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 case 'W': if(dig) { - errno = EILSEQ; return -1; } state = state_week_extended; @@ -173,7 +168,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 case 2: m = num; goto done; case 3: d = num; goto done; } - errno = EILSEQ; return -1; case 'T': @@ -185,7 +179,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 break; default: - errno = EILSEQ; return -1; } break; @@ -208,7 +201,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 break; default: - errno = EILSEQ; return -1; } break; @@ -232,7 +224,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 goto done; } - errno = EILSEQ; return -1; case 'T': @@ -247,7 +238,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 break; default: - errno = EILSEQ; return -1; } break; @@ -311,7 +301,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 break; default: - errno = EILSEQ; return -1; } @@ -324,7 +313,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 case 'Z': state = state_tz_utc; break; case '+': state = state_tz_basic; break; case '-': tz_neg = 1; state = state_tz_basic; break; - default: errno = EILSEQ; return -1; + default: return -1; } break; @@ -346,7 +335,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 case 'Z': state = state_tz_utc; break; case '+': state = state_tz_hour; break; case '-': tz_neg = 1; state = state_tz_hour; break; - default: errno = EILSEQ; return -1; + default: return -1; } break; @@ -368,7 +357,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 case 'Z': state = state_tz_utc; break; case '+': state = state_tz_hour; break; case '-': tz_neg = 1; state = state_tz_hour; break; - default: errno = EILSEQ; return -1; + default: return -1; } break; @@ -389,7 +378,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 case 'Z': state = state_tz_utc; break; case '+': state = state_tz_hour; break; case '-': tz_neg = 1; state = state_tz_hour; break; - default: errno = EILSEQ; return -1; + default: return -1; } break; @@ -450,13 +439,11 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 break; default: - errno = EILSEQ; return -1; } goto done; default: - errno = EILSEQ; return -1; } break; @@ -479,7 +466,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 switch(ch) { case ':': state = state_tz_min; break; case 0: goto done; - default: errno = EILSEQ; return -1; + default: return -1; } break; @@ -497,7 +484,7 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 switch(ch) { case ':': state = state_tz_sec; break; case 0: goto done; - default: errno = EILSEQ; return -1; + default: return -1; } break; @@ -515,9 +502,6 @@ int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601 } } -#undef ERROR_IF -#undef INCNUM - done: if(neg) y *= -1; if(tz_neg) tz_sec *= -1; @@ -568,6 +552,11 @@ done: if(details) details->time_prec = iso8601_prec_none; } else if(sec != -1) { + if(sec == 60) { + leap_sec_req++; + sec = 59; + } + if(earliest && iso8601_from_clocktime(earliest, hour, min, sec)) return -1; if(latest && iso8601_from_clocktime(latest, hour, min, sec)) return -1; @@ -625,28 +614,25 @@ done: } + // correct for timezone offset (note trickery to end up at 23:59:60 iff a leap second was + // requested) if(details) details->tz_sec = tz_sec; - if(tz_sec && earliest) iso8601_add_seconds(earliest, -tz_sec); - if(tz_sec && latest) iso8601_add_seconds(latest, -tz_sec); + if(tz_sec && earliest) iso8601_add_seconds(earliest, - leap_sec_req - tz_sec); + if(tz_sec && latest) iso8601_add_seconds(latest, - leap_sec_req - tz_sec); - return 0; -} - - - -int iso8601_valid(const struct iso8601_date* date) -{ - if(date->nsec < 0 || date->nsec > 1000000000) return 0; - - switch(date->sec) { - case 0 ... 86399: - return 1; - - case 86401: /* 24:00:00 */ - return !date->nsec; + // check that, if a leap second was requested, it was a valid leap second + if(leap_sec_req) { + ERROR_IF(earliest && earliest->sec != 86400); + ERROR_IF(latest && latest->sec != 86400); } + // we can't have e.g. 240000.5 + ERROR_IF(earliest && earliest->sec == 86401 && earliest->nsec); + ERROR_IF(latest && latest->sec == 86401 && latest->nsec); + return 0; +#undef ERROR_IF +#undef INCNUM }