[core] update parse_date from cURL 7.61.0

This commit is contained in:
Konstantin Käfer
2018-07-31 12:53:01 +02:00
parent 2c5bebbdd8
commit c77aa79f51
2 changed files with 100 additions and 108 deletions

View File

@@ -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 */

View File

@@ -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 */