mirror of
https://github.com/curl/curl.git
synced 2026-08-25 00:03:33 +03:00
parsedate: parse strings without using sscanf()
- sscanf is slow and complex, avoid it - give up already if the string is 12 bytes or longer as no valid string can be that long - this can now be done without copy Closes #10547
This commit is contained in:
parent
cbf5717615
commit
ba9a4e9bd8
1 changed files with 50 additions and 48 deletions
|
|
@ -212,56 +212,55 @@ static int checkday(const char *check, size_t len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
const char * const *what;
|
const char * const *what;
|
||||||
bool found = FALSE;
|
|
||||||
if(len > 3)
|
if(len > 3)
|
||||||
what = &weekday[0];
|
what = &weekday[0];
|
||||||
else
|
else if(len == 3)
|
||||||
what = &Curl_wkday[0];
|
what = &Curl_wkday[0];
|
||||||
|
else
|
||||||
|
return -1; /* too short */
|
||||||
for(i = 0; i<7; i++) {
|
for(i = 0; i<7; i++) {
|
||||||
if(strcasecompare(check, what[0])) {
|
size_t ilen = strlen(what[0]);
|
||||||
found = TRUE;
|
if((ilen == len) &&
|
||||||
break;
|
strncasecompare(check, what[0], len))
|
||||||
}
|
return i;
|
||||||
what++;
|
what++;
|
||||||
}
|
}
|
||||||
return found?i:-1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checkmonth(const char *check)
|
static int checkmonth(const char *check, size_t len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
const char * const *what;
|
const char * const *what = &Curl_month[0];
|
||||||
bool found = FALSE;
|
if(len != 3)
|
||||||
|
return -1; /* not a month */
|
||||||
|
|
||||||
what = &Curl_month[0];
|
|
||||||
for(i = 0; i<12; i++) {
|
for(i = 0; i<12; i++) {
|
||||||
if(strcasecompare(check, what[0])) {
|
if(strncasecompare(check, what[0], 3))
|
||||||
found = TRUE;
|
return i;
|
||||||
break;
|
|
||||||
}
|
|
||||||
what++;
|
what++;
|
||||||
}
|
}
|
||||||
return found?i:-1; /* return the offset or -1, no real offset is -1 */
|
return -1; /* return the offset or -1, no real offset is -1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the time zone offset between GMT and the input one, in number
|
/* return the time zone offset between GMT and the input one, in number
|
||||||
of seconds or -1 if the timezone wasn't found/legal */
|
of seconds or -1 if the timezone wasn't found/legal */
|
||||||
|
|
||||||
static int checktz(const char *check)
|
static int checktz(const char *check, size_t len)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
const struct tzinfo *what;
|
const struct tzinfo *what = tz;
|
||||||
bool found = FALSE;
|
if(len > 4) /* longer than any valid timezone */
|
||||||
|
return -1;
|
||||||
|
|
||||||
what = tz;
|
|
||||||
for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
|
for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
|
||||||
if(strcasecompare(check, what->name)) {
|
size_t ilen = strlen(what->name);
|
||||||
found = TRUE;
|
if((ilen == len) &&
|
||||||
break;
|
strncasecompare(check, what->name, len))
|
||||||
}
|
return what->offset*60;
|
||||||
what++;
|
what++;
|
||||||
}
|
}
|
||||||
return found?what->offset*60:-1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void skip(const char **date)
|
static void skip(const char **date)
|
||||||
|
|
@ -305,6 +304,9 @@ static time_t time2epoch(int sec, int min, int hour,
|
||||||
* PARSEDATE_SOONER - time underflow at the low end of time_t
|
* PARSEDATE_SOONER - time underflow at the low end of time_t
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Wednesday is the longest name this parser knows about */
|
||||||
|
#define NAME_LEN 12
|
||||||
|
|
||||||
static int parsedate(const char *date, time_t *output)
|
static int parsedate(const char *date, time_t *output)
|
||||||
{
|
{
|
||||||
time_t t = 0;
|
time_t t = 0;
|
||||||
|
|
@ -327,32 +329,32 @@ static int parsedate(const char *date, time_t *output)
|
||||||
|
|
||||||
if(ISALPHA(*date)) {
|
if(ISALPHA(*date)) {
|
||||||
/* a name coming up */
|
/* a name coming up */
|
||||||
char buf[32]="";
|
size_t len = 0;
|
||||||
size_t len;
|
const char *p = date;
|
||||||
if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
while(ISALPHA(*p) && (len < NAME_LEN)) {
|
||||||
"abcdefghijklmnopqrstuvwxyz]", buf))
|
p++;
|
||||||
len = strlen(buf);
|
len++;
|
||||||
else
|
|
||||||
len = 0;
|
|
||||||
|
|
||||||
if(wdaynum == -1) {
|
|
||||||
wdaynum = checkday(buf, len);
|
|
||||||
if(wdaynum != -1)
|
|
||||||
found = TRUE;
|
|
||||||
}
|
|
||||||
if(!found && (monnum == -1)) {
|
|
||||||
monnum = checkmonth(buf);
|
|
||||||
if(monnum != -1)
|
|
||||||
found = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!found && (tzoff == -1)) {
|
if(len != NAME_LEN) {
|
||||||
/* this just must be a time zone string */
|
if(wdaynum == -1) {
|
||||||
tzoff = checktz(buf);
|
wdaynum = checkday(date, len);
|
||||||
if(tzoff != -1)
|
if(wdaynum != -1)
|
||||||
found = TRUE;
|
found = TRUE;
|
||||||
}
|
}
|
||||||
|
if(!found && (monnum == -1)) {
|
||||||
|
monnum = checkmonth(date, len);
|
||||||
|
if(monnum != -1)
|
||||||
|
found = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!found && (tzoff == -1)) {
|
||||||
|
/* this just must be a time zone string */
|
||||||
|
tzoff = checktz(date, len);
|
||||||
|
if(tzoff != -1)
|
||||||
|
found = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(!found)
|
if(!found)
|
||||||
return PARSEDATE_FAIL; /* bad string */
|
return PARSEDATE_FAIL; /* bad string */
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue