diff -r 7fbcdbad0baa -r 136a76e293b5 src/server/util/util.c --- a/src/server/util/util.c Sat Oct 17 21:17:34 2015 +0200 +++ b/src/server/util/util.c Sat Oct 17 22:24:38 2015 +0200 @@ -529,7 +529,7 @@ } -// new - code in parts from params.cpp +// new - code from params.cpp NSAPI_PUBLIC pblock* util_parse_param(pool_handle_t *pool, char *query) { pblock *pb = pblock_create_pool(pool, 32); if(!pb) { @@ -600,3 +600,307 @@ return newstring; } + + + +/* ---------------------------- util_mstr2num ----------------------------- */ + +static const int MSTR2NUM_HT_MASK = 0xf; + +static const struct { + unsigned ucmstr; // Uppercase 3 character month string in a machine word + int mnum; // 0-based month number for this month string +} MSTR2NUM_HT[MSTR2NUM_HT_MASK + 1] = { + { 'A' << 16 | 'P' << 8 | 'R', 3 }, + { 'S' << 16 | 'E' << 8 | 'P', 8 }, + { 'M' << 16 | 'A' << 8 | 'Y', 4 }, + { 0, -1 }, + { 'M' << 16 | 'A' << 8 | 'R', 2 }, + { 'F' << 16 | 'E' << 8 | 'B', 1 }, + { 0, -1 }, + { 'D' << 16 | 'E' << 8 | 'C', 11 }, + { 'O' << 16 | 'C' << 8 | 'T', 9 }, + { 'J' << 16 | 'U' << 8 | 'N', 5 }, + { 0, -1 }, + { 'A' << 16 | 'U' << 8 | 'G', 7 }, + { 'J' << 16 | 'A' << 8 | 'N', 0 }, + { 'J' << 16 | 'U' << 8 | 'L', 6 }, + { 0, -1 }, + { 'N' << 16 | 'O' << 8 | 'V', 10 } +}; + +static inline int _mstr2num(const char *s) +{ + const unsigned char *mstr = (const unsigned char *) s; + + /* + * We compute ucmstr (an uppercase 3 character month string stored in a + * machine word) and hash (a perfect hash based on the last 2 characters + * of the 3 character uppercase month string) from the input string s. + * Note that each character from the input string is masked by 0xdf; in + * ASCII, this has the effect of converting alphabetic characters to + * uppercase while 1. not changing any nonalphabetic characters into + * alphabetic characters and 2. leaving any nul characters unchanged. + * + * The hash value is used as an index into the MSTR2NUM_HT[] hash table. + * If the ucmstr at that index matches our computed ucmstr, the mnum at + * that index is the 0-based month number corresponding to the input + * string. + * + * Note that we never read past the end of the input string and always + * return -1 if the input string doesn't begin with a valid 3 character + * month string. + */ + + unsigned char ucmstr0 = mstr[0] & 0xdf; + unsigned ucmstr = ucmstr0 << 16; + if (ucmstr0 != '\0') { + unsigned char ucmstr1 = mstr[1] & 0xdf; + ucmstr |= ucmstr1 << 8; + if (ucmstr1 != '\0') { + unsigned char ucmstr2 = mstr[2] & 0xdf; + ucmstr |= ucmstr2; + + unsigned hash = (ucmstr1 >> 2) ^ (ucmstr2 << 1); + + int i = hash & MSTR2NUM_HT_MASK; + + if (MSTR2NUM_HT[i].ucmstr == ucmstr) + return MSTR2NUM_HT[i].mnum; + } + } + + return -1; +} + +NSAPI_PUBLIC int util_mstr2num(const char *s) +{ + return _mstr2num(s); +} + + +/* ------------------------- util_str_time_equal -------------------------- */ + +/* + * Function to compare if two time strings are equal + * + * Acceptable date formats: + * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + * + * Return 0 if equal, -1 if not equal. + */ + +static inline const char * _parse_day_month(const char *p, int *day, int *month) +{ + *day = 0; + + if (*p == ',') { + // Parse day and month: ", 06 Nov", ", 06-Nov" + p++; + if (*p == ' ') + p++; + while (*p >= '0' && *p <= '9') + *day = *day * 10 + (*p++ - '0'); + if (*p == ' ' || *p == '-') + p++; + *month = _mstr2num(p); + if (*month != -1) + p += 3; + } else { + // Parse month and day: " Nov 6" + if (*p == ' ') + p++; + *month = _mstr2num(p); + if (*month != -1) + p += 3; + while (*p == ' ') + p++; + while (*p >= '0' && *p <= '9') + *day = *day * 10 + (*p++ - '0'); + } + + return p; +} + +static inline void _parse_year_time(const char *p, int *year, const char ** time) +{ + int _year = 0; + + if (*p == '-') { + // Parse year and time: "-94 08:49:37" + p++; + while (*p >= '0' && *p <= '9') + _year = _year * 10 + (*p++ - '0'); + if (_year < 70) { + _year += 2000; + } else { + _year += 1900; + } + if (*p == ' ') + p++; + *time = p; + } else { + // Parse year and time or time and year + if (*p == ' ') + p++; + if (p[0] && p[1] && p[2] == ':') { + // Parse time and year: "08:49:37 1994" + *time = p; + p += 3; + while (*p && *p != ' ') + p++; + if (*p == ' ') + p++; + while (*p >= '0' && *p <= '9') + _year = _year * 10 + (*p++ - '0'); + } else { + // Parse year and time: "1994 08:49:37" + while (*p >= '0' && *p <= '9') + _year = _year * 10 + (*p++ - '0'); + if (*p == ' ') + p++; + *time = p; + } + } + + *year = _year; +} + +NSAPI_PUBLIC int util_str_time_equal(const char *t1, const char *t2) +{ + // Skip leading whitespace and day of week + while (isspace(*t1)) + t1++; + while (isalpha(*t1)) + t1++; + while (isspace(*t2)) + t2++; + while (isalpha(*t2)) + t2++; + + // Day and month: ", 06 Nov", ", 06-Nov", or " Nov 6" + int day1; + int month1; + t1 = _parse_day_month(t1, &day1, &month1); + int day2; + int month2; + t2 = _parse_day_month(t2, &day2, &month2); + if (day1 != day2) + return -1; + if (month1 != month2) + return -1; + + // Year and time: " 1994 08:49:37", "-94 08:49:37", or " 08:49:37 1994" + int year1; + const char *time1; + _parse_year_time(t1, &year1, &time1); + int year2; + const char *time2; + _parse_year_time(t2, &year2, &time2); + if (year1 != year2) + return -1; + while (*time1 && *time1 != ' ' && *time1 == *time2) { + time1++; + time2++; + } + if (*time2 && *time2 != ' ') + return -1; + + return 0; +} + + +/* --------------------------- util_later_than ---------------------------- */ + +static int _time_compare(const struct tm *lms, const char *ims) +{ + while (isspace(*ims)) + ims++; + while (isalpha(*ims)) + ims++; + + int day; + int month; + ims = _parse_day_month(ims, &day, &month); + if (month == -1) + return 1; + + int year; + const char *time; + _parse_year_time(ims, &year, &time); + + int rv; + + rv = (lms->tm_year + 1900) - year; + if (rv) + return rv; + + rv = lms->tm_mon - month; + if (rv) + return rv; + + rv = lms->tm_mday - day; + if (rv) + return rv; + + const char *p = time; + + int hour = 0; + while (*p >= '0' && *p <= '9') + hour = hour * 10 + (*p++ - '0'); + if (*p == ':') + p++; + + rv = lms->tm_hour - hour; + if (rv) + return rv; + + int minutes = 0; + while (*p >= '0' && *p <= '9') + minutes = minutes * 10 + (*p++ - '0'); + if (*p == ':') + p++; + + rv = lms->tm_min - minutes; + if (rv) + return rv; + + int seconds = 0; + while (*p >= '0' && *p <= '9') + seconds = seconds * 10 + (*p++ - '0'); + if (*p == ':') + p++; + + rv = lms->tm_sec - seconds; + if (rv) + return rv; + + return 0; +} + +NSAPI_PUBLIC int util_later_than(const struct tm *lms, const char *ims) +{ + /* + * Returns 0 if lms later than ims + * 0 if ims is malformed + * 1 if ims later than lms + * 1 if equal + */ + + return _time_compare(lms, ims) <= 0; +} + +NSAPI_PUBLIC int util_time_equal(const struct tm *lms, const char *ims) +{ + return _time_compare(lms, ims) == 0; +} + + +NSAPI_PUBLIC struct tm * +util_gmtime(const time_t *clock, struct tm *res) +{ + return gmtime_r(clock, res); +} +