#include "config.h"
#ifndef HAVE_CONFIG_H
#include <time.h>
#endif
#ifndef STRPTIME_WORKS
#define TM_YEAR_BASE 1900
#include <ctype.h>
#include <string.h>
static const char *abb_weekdays[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
};
static const char *full_weekdays[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", NULL
};
static const char *abb_months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
};
static const char *full_months[] = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December", NULL
};
static const char *ampm[] = {
"am", "pm", NULL
};
static int
match_string(const char **buf, const char **strs)
{
int i = 0;
for (i = 0; strs[i] != NULL; i++) {
int len = strlen(strs[i]);
if (strncasecmp (*buf, strs[i], len) == 0) {
*buf += len;
return i;
}
}
return -1;
}
static int
str2int(const char **buf, int max)
{
int ret=0, count=0;
while (*buf[0] != '\0' && isdigit((unsigned char)*buf[0]) && count<max) {
ret = ret*10 + (*buf[0] - '0');
(*buf)++;
count++;
}
if (!count)
return -1;
return ret;
}
char *
unbound_strptime(const char *s, const char *format, struct tm *tm)
{
int c, ret;
int split_year = 0;
while ((c = *format) != '\0') {
if (isspace((unsigned char)c)) {
while (isspace((unsigned char)*s))
s++;
}
else if (c == '%') {
format++;
c = *format;
switch (c) {
case '%':
if (*s != c) {
return NULL;
}
s++;
break;
case 'a':
case 'A':
ret = match_string(&s, full_weekdays);
if (ret < 0)
ret = match_string(&s, abb_weekdays);
if (ret < 0) {
return NULL;
}
tm->tm_wday = ret;
break;
case 'b':
case 'B':
case 'h':
ret = match_string(&s, full_months);
if (ret < 0)
ret = match_string(&s, abb_months);
if (ret < 0) {
return NULL;
}
tm->tm_mon = ret;
break;
case 'c':
if (!(s = unbound_strptime(s, "%x %X", tm))) {
return NULL;
}
break;
case 'C':
ret = str2int(&s, 2);
if (ret < 0 || ret > 99) {
return NULL;
}
if (split_year) {
tm->tm_year = ret*100 + (tm->tm_year%100);
}
else {
tm->tm_year = ret*100 - TM_YEAR_BASE;
split_year = 1;
}
break;
case 'd':
case 'e':
ret = str2int(&s, 2);
if (ret < 1 || ret > 31) {
return NULL;
}
tm->tm_mday = ret;
break;
case 'D':
if (!(s = unbound_strptime(s, "%m/%d/%y", tm))) {
return NULL;
}
break;
case 'H':
ret = str2int(&s, 2);
if (ret < 0 || ret > 23) {
return NULL;
}
tm->tm_hour = ret;
break;
case 'I':
ret = str2int(&s, 2);
if (ret < 1 || ret > 12) {
return NULL;
}
if (ret == 12)
ret = 0;
tm->tm_hour = ret;
break;
case 'j':
ret = str2int(&s, 2);
if (ret < 1 || ret > 366) {
return NULL;
}
tm->tm_yday = ret;
break;
case 'm':
ret = str2int(&s, 2);
if (ret < 1 || ret > 12) {
return NULL;
}
tm->tm_mon = (ret-1);
break;
case 'M':
ret = str2int(&s, 2);
if (ret < 0 || ret > 59) {
return NULL;
}
tm->tm_min = ret;
break;
case 'n':
case 't':
while (isspace((unsigned char)*s))
s++;
break;
case 'p':
ret = match_string(&s, ampm);
if (ret < 0) {
return NULL;
}
if (tm->tm_hour < 0 || tm->tm_hour > 11) {
return NULL;
}
if (ret == 1)
tm->tm_hour += 12;
break;
case 'r':
if (!(s = unbound_strptime(s, "%I:%M:%S %p", tm))) {
return NULL;
}
break;
case 'R':
if (!(s = unbound_strptime(s, "%H:%M", tm))) {
return NULL;
}
break;
case 'S':
ret = str2int(&s, 2);
if (ret < 0 || ret > 60) {
return NULL;
}
tm->tm_sec = ret;
break;
case 'T':
if (!(s = unbound_strptime(s, "%H:%M:%S", tm))) {
return NULL;
}
break;
case 'U':
ret = str2int(&s, 2);
if (ret < 0 || ret > 53) {
return NULL;
}
break;
case 'w':
ret = str2int(&s, 1);
if (ret < 0 || ret > 6) {
return NULL;
}
tm->tm_wday = ret;
break;
case 'W':
ret = str2int(&s, 2);
if (ret < 0 || ret > 53) {
return NULL;
}
break;
case 'x':
if (!(s = unbound_strptime(s, "%m/%d/%y", tm))) {
return NULL;
}
break;
case 'X':
if (!(s = unbound_strptime(s, "%H:%M:%S", tm))) {
return NULL;
}
break;
case 'y':
ret = str2int(&s, 2);
if (ret < 0 || ret > 99) {
return NULL;
}
if (split_year) {
tm->tm_year = ((tm->tm_year/100) * 100) + ret;
}
else {
split_year = 1;
if (ret < 69)
ret += 100;
tm->tm_year = ret;
}
break;
case 'Y':
ret = str2int(&s, 4);
if (ret < 0 || ret > 9999) {
return NULL;
}
tm->tm_year = ret - TM_YEAR_BASE;
break;
case '\0':
default:
return NULL;
break;
}
}
else {
if (*s != c)
return NULL;
s++;
}
format++;
}
return (char*) s;
}
#endif