src/server/util/util.c

changeset 102
136a76e293b5
parent 99
b9a6af0ae41a
child 103
d3b514e2ddbd
--- 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);
+}
+

mercurial