[core] update parse_date from cURL 7.61.0
This commit is contained in:
@@ -5,11 +5,11 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
* are also available at https://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
@@ -89,11 +89,6 @@ extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define ERRNO (errno)
|
||||
#define SET_ERRNO(x) (errno = (x))
|
||||
|
||||
|
||||
/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
|
||||
its behavior is altered by the current locale. */
|
||||
char raw_toupper(char in)
|
||||
@@ -156,16 +151,19 @@ char raw_toupper(char in)
|
||||
}
|
||||
|
||||
/*
|
||||
* raw_equal() is for doing "raw" case insensitive strings. This is meant
|
||||
* to be locale independent and only compare strings we know are safe for
|
||||
* this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
|
||||
* some further explanation to why this function is necessary.
|
||||
* strcasecompare() is for doing "raw" case insensitive strings. This is
|
||||
* meant to be locale independent and only compare strings we know are safe
|
||||
* for this. See
|
||||
* https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some
|
||||
* further explanation to why this function is necessary.
|
||||
*
|
||||
* The function is capable of comparing a-z case insensitively even for
|
||||
* non-ascii.
|
||||
*
|
||||
* @unittest: 1301
|
||||
*/
|
||||
|
||||
int raw_equal(const char *first, const char *second)
|
||||
int strcasecompare(const char *first, const char *second)
|
||||
{
|
||||
while(*first && *second) {
|
||||
if(raw_toupper(*first) != raw_toupper(*second))
|
||||
@@ -201,23 +199,25 @@ int raw_equal(const char *first, const char *second)
|
||||
#endif
|
||||
|
||||
|
||||
#define TIME_T_MIN 0
|
||||
#define TIME_T_MAX INT_MAX
|
||||
|
||||
/*
|
||||
** signed long to signed int
|
||||
*/
|
||||
|
||||
int clamp_to_int(long slnum)
|
||||
int curlx_sltosi(long slnum)
|
||||
{
|
||||
return slnum > INT_MAX ? INT_MAX : slnum < INT_MIN ? INT_MIN : (int)slnum;
|
||||
}
|
||||
|
||||
|
||||
const char * const wkday[] =
|
||||
const char * const Curl_wkday[] =
|
||||
{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
||||
static const char * const weekday[] =
|
||||
{ "Monday", "Tuesday", "Wednesday", "Thursday",
|
||||
"Friday", "Saturday", "Sunday" };
|
||||
const char * const month[]=
|
||||
const char * const Curl_month[]=
|
||||
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
|
||||
@@ -249,6 +249,7 @@ static int parsedate(const char *date, time_t *output);
|
||||
#define tDAYZONE -60 /* offset for daylight savings time */
|
||||
static const struct tzinfo tz[]= {
|
||||
{"GMT", 0}, /* Greenwich Mean */
|
||||
{"UT", 0}, /* Universal Time */
|
||||
{"UTC", 0}, /* Universal (Coordinated) */
|
||||
{"WET", 0}, /* Western European */
|
||||
{"BST", 0 tDAYZONE}, /* British Summer */
|
||||
@@ -295,20 +296,20 @@ static const struct tzinfo tz[]= {
|
||||
RFC 1123) had their signs wrong. Here we use the correct signs to match
|
||||
actual military usage.
|
||||
*/
|
||||
{"A", +1 * 60}, /* Alpha */
|
||||
{"B", +2 * 60}, /* Bravo */
|
||||
{"C", +3 * 60}, /* Charlie */
|
||||
{"D", +4 * 60}, /* Delta */
|
||||
{"E", +5 * 60}, /* Echo */
|
||||
{"F", +6 * 60}, /* Foxtrot */
|
||||
{"G", +7 * 60}, /* Golf */
|
||||
{"H", +8 * 60}, /* Hotel */
|
||||
{"I", +9 * 60}, /* India */
|
||||
{"A", 1 * 60}, /* Alpha */
|
||||
{"B", 2 * 60}, /* Bravo */
|
||||
{"C", 3 * 60}, /* Charlie */
|
||||
{"D", 4 * 60}, /* Delta */
|
||||
{"E", 5 * 60}, /* Echo */
|
||||
{"F", 6 * 60}, /* Foxtrot */
|
||||
{"G", 7 * 60}, /* Golf */
|
||||
{"H", 8 * 60}, /* Hotel */
|
||||
{"I", 9 * 60}, /* India */
|
||||
/* "J", Juliet is not used as a timezone, to indicate the observer's local
|
||||
time */
|
||||
{"K", +10 * 60}, /* Kilo */
|
||||
{"L", +11 * 60}, /* Lima */
|
||||
{"M", +12 * 60}, /* Mike */
|
||||
{"K", 10 * 60}, /* Kilo */
|
||||
{"L", 11 * 60}, /* Lima */
|
||||
{"M", 12 * 60}, /* Mike */
|
||||
{"N", -1 * 60}, /* November */
|
||||
{"O", -2 * 60}, /* Oscar */
|
||||
{"P", -3 * 60}, /* Papa */
|
||||
@@ -333,14 +334,14 @@ static int checkday(const char *check, size_t len)
|
||||
{
|
||||
int i;
|
||||
const char * const *what;
|
||||
bool found= FALSE;
|
||||
bool found = FALSE;
|
||||
if(len > 3)
|
||||
what = &weekday[0];
|
||||
else
|
||||
what = &wkday[0];
|
||||
for(i=0; i<7; i++) {
|
||||
if(raw_equal(check, what[0])) {
|
||||
found=TRUE;
|
||||
what = &Curl_wkday[0];
|
||||
for(i = 0; i<7; i++) {
|
||||
if(strcasecompare(check, what[0])) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
what++;
|
||||
@@ -352,12 +353,12 @@ static int checkmonth(const char *check)
|
||||
{
|
||||
int i;
|
||||
const char * const *what;
|
||||
bool found= FALSE;
|
||||
bool found = FALSE;
|
||||
|
||||
what = &month[0];
|
||||
for(i=0; i<12; i++) {
|
||||
if(raw_equal(check, what[0])) {
|
||||
found=TRUE;
|
||||
what = &Curl_month[0];
|
||||
for(i = 0; i<12; i++) {
|
||||
if(strcasecompare(check, what[0])) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
what++;
|
||||
@@ -372,12 +373,12 @@ static int checktz(const char *check)
|
||||
{
|
||||
unsigned int i;
|
||||
const struct tzinfo *what;
|
||||
bool found= FALSE;
|
||||
bool found = FALSE;
|
||||
|
||||
what = tz;
|
||||
for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) {
|
||||
if(raw_equal(check, what->name)) {
|
||||
found=TRUE;
|
||||
for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
|
||||
if(strcasecompare(check, what->name)) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
what++;
|
||||
@@ -406,26 +407,23 @@ struct my_tm {
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_year; /* full year */
|
||||
};
|
||||
|
||||
/* struct tm to time since epoch in GMT time zone.
|
||||
* This is similar to the standard mktime function but for GMT only, and
|
||||
* doesn't suffer from the various bugs and portability problems that
|
||||
* some systems' implementations have.
|
||||
*
|
||||
* Returns 0 on success, otherwise non-zero.
|
||||
*/
|
||||
static time_t my_timegm(struct my_tm *tm)
|
||||
static void my_timegm(struct my_tm *tm, time_t *t)
|
||||
{
|
||||
static const int month_days_cumulative [12] =
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||
int month_, year, leap_days;
|
||||
|
||||
if(tm->tm_year < 70)
|
||||
/* we don't support years before 1970 as they will cause this function
|
||||
to return a negative value */
|
||||
return -1;
|
||||
|
||||
year = tm->tm_year + 1900;
|
||||
year = tm->tm_year;
|
||||
month_ = tm->tm_mon;
|
||||
if(month_ < 0) {
|
||||
year += (11 - month_) / 12;
|
||||
@@ -440,9 +438,9 @@ static time_t my_timegm(struct my_tm *tm)
|
||||
leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
|
||||
- (1969 / 4) + (1969 / 100) - (1969 / 400));
|
||||
|
||||
return ((((time_t) (year - 1970) * 365
|
||||
+ leap_days + month_days_cumulative [month_] + tm->tm_mday - 1) * 24
|
||||
+ tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
|
||||
*t = ((((time_t) (year - 1970) * 365
|
||||
+ leap_days + month_days_cumulative[month_] + tm->tm_mday - 1) * 24
|
||||
+ tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -459,21 +457,21 @@ static time_t my_timegm(struct my_tm *tm)
|
||||
static int parsedate(const char *date, time_t *output)
|
||||
{
|
||||
time_t t = 0;
|
||||
int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */
|
||||
int monnum=-1; /* month of the year number, 0-11 */
|
||||
int mdaynum=-1; /* day of month, 1 - 31 */
|
||||
int hournum=-1;
|
||||
int minnum=-1;
|
||||
int secnum=-1;
|
||||
int yearnum=-1;
|
||||
int tzoff=-1;
|
||||
int wdaynum = -1; /* day of the week number, 0-6 (mon-sun) */
|
||||
int monnum = -1; /* month of the year number, 0-11 */
|
||||
int mdaynum = -1; /* day of month, 1 - 31 */
|
||||
int hournum = -1;
|
||||
int minnum = -1;
|
||||
int secnum = -1;
|
||||
int yearnum = -1;
|
||||
int tzoff = -1;
|
||||
struct my_tm tm;
|
||||
enum assume dignext = DATE_MDAY;
|
||||
const char *indate = date; /* save the original pointer */
|
||||
int part = 0; /* max 6 parts */
|
||||
|
||||
while(*date && (part < 6)) {
|
||||
bool found=FALSE;
|
||||
bool found = FALSE;
|
||||
|
||||
skip(&date);
|
||||
|
||||
@@ -514,15 +512,17 @@ static int parsedate(const char *date, time_t *output)
|
||||
/* a digit */
|
||||
int val;
|
||||
char *end;
|
||||
int len = 0;
|
||||
if((secnum == -1) &&
|
||||
(3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) {
|
||||
(3 == sscanf(date, "%02d:%02d:%02d%n",
|
||||
&hournum, &minnum, &secnum, &len))) {
|
||||
/* time stamp! */
|
||||
date += 8;
|
||||
date += len;
|
||||
}
|
||||
else if((secnum == -1) &&
|
||||
(2 == sscanf(date, "%02d:%02d", &hournum, &minnum))) {
|
||||
(2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) {
|
||||
/* time stamp without seconds */
|
||||
date += 5;
|
||||
date += len;
|
||||
secnum = 0;
|
||||
}
|
||||
else {
|
||||
@@ -530,12 +530,12 @@ static int parsedate(const char *date, time_t *output)
|
||||
int error;
|
||||
int old_errno;
|
||||
|
||||
old_errno = ERRNO;
|
||||
SET_ERRNO(0);
|
||||
old_errno = errno;
|
||||
errno = 0;
|
||||
lval = strtol(date, &end, 10);
|
||||
error = ERRNO;
|
||||
if(error != old_errno)
|
||||
SET_ERRNO(old_errno);
|
||||
error = errno;
|
||||
if(errno != old_errno)
|
||||
errno = old_errno;
|
||||
|
||||
if(error)
|
||||
return PARSEDATE_FAIL;
|
||||
@@ -545,7 +545,7 @@ static int parsedate(const char *date, time_t *output)
|
||||
return PARSEDATE_FAIL;
|
||||
#endif
|
||||
|
||||
val = clamp_to_int(lval);
|
||||
val = curlx_sltosi(lval);
|
||||
|
||||
if((tzoff == -1) &&
|
||||
((end - date) == 4) &&
|
||||
@@ -564,7 +564,7 @@ static int parsedate(const char *date, time_t *output)
|
||||
tzoff = (val/100 * 60 + val%100)*60;
|
||||
|
||||
/* the + and - prefix indicates the local time compared to GMT,
|
||||
this we need ther reversed math to get what we want */
|
||||
this we need their reversed math to get what we want */
|
||||
tzoff = date[-1]=='+'?-tzoff:tzoff;
|
||||
}
|
||||
|
||||
@@ -590,7 +590,7 @@ static int parsedate(const char *date, time_t *output)
|
||||
if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
|
||||
yearnum = val;
|
||||
found = TRUE;
|
||||
if(yearnum < 1900) {
|
||||
if(yearnum < 100) {
|
||||
if(yearnum > 70)
|
||||
yearnum += 1900;
|
||||
else
|
||||
@@ -619,19 +619,18 @@ static int parsedate(const char *date, time_t *output)
|
||||
/* lacks vital info, fail */
|
||||
return PARSEDATE_FAIL;
|
||||
|
||||
#if SIZEOF_TIME_T < 5
|
||||
/* 32 bit time_t can only hold dates to the beginning of 2038 */
|
||||
if(yearnum > 2037) {
|
||||
*output = 0x7fffffff;
|
||||
return PARSEDATE_LATER;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(yearnum < 1970) {
|
||||
*output = 0;
|
||||
/* only positive numbers cannot return earlier */
|
||||
*output = TIME_T_MIN;
|
||||
return PARSEDATE_SOONER;
|
||||
}
|
||||
|
||||
/* a signed 32 bit time_t can only hold dates to the beginning of 2038 */
|
||||
if(yearnum > 2037) {
|
||||
*output = TIME_T_MAX;
|
||||
return PARSEDATE_LATER;
|
||||
}
|
||||
|
||||
if((mdaynum > 31) || (monnum > 11) ||
|
||||
(hournum > 23) || (minnum > 59) || (secnum > 60))
|
||||
return PARSEDATE_FAIL; /* clearly an illegal date */
|
||||
@@ -641,29 +640,25 @@ static int parsedate(const char *date, time_t *output)
|
||||
tm.tm_hour = hournum;
|
||||
tm.tm_mday = mdaynum;
|
||||
tm.tm_mon = monnum;
|
||||
tm.tm_year = yearnum - 1900;
|
||||
tm.tm_year = yearnum;
|
||||
|
||||
/* my_timegm() returns a time_t. time_t is often 32 bits, even on many
|
||||
architectures that feature 64 bit 'long'.
|
||||
|
||||
Some systems have 64 bit time_t and deal with years beyond 2038. However,
|
||||
even on some of the systems with 64 bit time_t mktime() returns -1 for
|
||||
dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
|
||||
/* my_timegm() returns a time_t. time_t is often 32 bits, sometimes even on
|
||||
architectures that feature 64 bit 'long' but ultimately time_t is the
|
||||
correct data type to use.
|
||||
*/
|
||||
t = my_timegm(&tm);
|
||||
my_timegm(&tm, &t);
|
||||
|
||||
/* time zone adjust (cast t to int to compare to negative one) */
|
||||
if(-1 != (int)t) {
|
||||
/* Add the time zone diff between local time zone and GMT. */
|
||||
if(tzoff == -1)
|
||||
tzoff = 0;
|
||||
|
||||
/* Add the time zone diff between local time zone and GMT. */
|
||||
long delta = (long)(tzoff!=-1?tzoff:0);
|
||||
|
||||
if((delta>0) && (t > LONG_MAX - delta))
|
||||
return -1; /* time_t overflow */
|
||||
|
||||
t += delta;
|
||||
if((tzoff > 0) && (t > TIME_T_MAX - tzoff)) {
|
||||
*output = TIME_T_MAX;
|
||||
return PARSEDATE_LATER; /* time_t overflow */
|
||||
}
|
||||
|
||||
t += tzoff;
|
||||
|
||||
*output = t;
|
||||
|
||||
return PARSEDATE_OK;
|
||||
@@ -674,10 +669,10 @@ time_t parse_date(const char *p)
|
||||
time_t parsed = -1;
|
||||
int rc = parsedate(p, &parsed);
|
||||
|
||||
switch(rc) {
|
||||
case PARSEDATE_OK:
|
||||
case PARSEDATE_LATER:
|
||||
case PARSEDATE_SOONER:
|
||||
if(rc == PARSEDATE_OK) {
|
||||
if(parsed == -1)
|
||||
/* avoid returning -1 for a working scenario */
|
||||
parsed++;
|
||||
return parsed;
|
||||
}
|
||||
/* everything else is fail */
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#ifndef HEADER_PARSEDATE_H
|
||||
#define HEADER_PARSEDATE_H
|
||||
#pragma once
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
@@ -11,7 +10,7 @@
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
* are also available at https://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
@@ -34,5 +33,3 @@ time_t parse_date(const char *p);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_PARSEDATE_H */
|
||||
|
||||
Reference in New Issue
Block a user