added parser for iso8601 dates

Tue, 13 Oct 2015 15:54:31 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 13 Oct 2015 15:54:31 +0200
changeset 160
ba8f1691c0ee
parent 159
7e0a8912ca25
child 161
97a52ce52b1a

added parser for iso8601 dates

libidav/utils.c file | annotate | diff | comparison | revisions
--- a/libidav/utils.c	Tue Oct 13 14:23:15 2015 +0200
+++ b/libidav/utils.c	Tue Oct 13 15:54:31 2015 +0200
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <ctype.h>
 #include <ucx/string.h>
 #include <ucx/buffer.h>
 #include <ucx/utils.h>
@@ -56,15 +57,132 @@
 #include "crypto.h"
 #include "webdav.h"
 
+static int parse_iso8601(char *str, time_t *result) {
+
+    // safety
+    if(!str || !result) {
+        return 1;
+    }
+    
+    struct tm tparts;
+    memset(&tparts, 0, sizeof(struct tm));
+    *result = 0;
+    long val;
+
+    // skip leading spaces
+    while(isspace(*str)) {
+        str++;
+    }
+
+    // ensure we have numeric values (maybe with sign)
+    if(!isdigit(*str) && *str != '-' && *str != '+') {
+        return 1;
+    }
+
+    // starting parsing the year
+    val = strtoul(str, &str, 10);
+    
+    if(*str == '-') {
+        // month (and day) seem to be dash separated
+        tparts.tm_year = val - 1900;
+        str++;
+        tparts.tm_mon = strtoul(str, &str, 10) - 1;
+
+        if (*str++ != '-') {
+            return 1;
+        }
+
+        tparts.tm_mday = strtoul(str, &str, 10);
+    } else {
+        // year, month, day was parsed as one big integer
+        tparts.tm_mday = val % 100;
+        tparts.tm_mon = (val % 10000) / 100 - 1;
+        tparts.tm_year = val / 10000 - 1900;
+    }
+
+    // time separator
+    if(*str != 'T') {
+        return 1;
+    }
+    str++;
+
+    // ensure we have numeric values (unsigned)
+    if(!isdigit(*str)) {
+        return 1;
+    }
+
+    // start parsing the hour
+    val = strtoul(str, &str, 10);
+    if(*str == ':') {
+        // minutes (and seconds) are separated by colon
+        tparts.tm_hour = val;
+        str++;
+        tparts.tm_min = strtoul(str, &str, 10);
+
+        if(*str++ != ':') {
+            return 1;
+        }
+
+        tparts.tm_sec = strtoul(str, &str, 10);
+    } else {
+        // minutes (and seconds) are one big integer
+        tparts.tm_sec = val % 100;
+        tparts.tm_min = (val % 10000) / 100;
+        tparts.tm_hour = val / 10000;
+    }
+
+    // parse fractional seconds, but skip them (we return a time_t)
+    if(*str == ',' || *str == '.') {
+        do {
+            str++;
+        } while(isdigit(*str));
+    }
+
+    // parse time zone (if any)
+    if(*str == 'Z') {
+        str++;
+        *result = mktime(&tparts) - timezone;
+    } else if (*str == '+' || *str == '-') {
+        int sign = (*str == '+') ? -1 : 1;
+
+        val = strtoul(str + 1, &str, 10);
+
+        if (*str == ':') {
+            val = 60 * val + strtoul(str + 1, &str, 10);
+        } else {
+            val = 60 * (val / 100) + (val % 100);
+        }
+
+        *result = mktime(&tparts) - timezone + (time_t) (60 * val * sign);
+    } else {
+        // local time
+        tparts.tm_isdst = -1;
+        *result = mktime(&tparts);
+    }
+
+    // skip trailing spaces
+    while(isspace(*str)) {
+        str++;
+    }
+
+    // string must be zero terminated, no further characters may follow
+    return *str != '\0'; // return zero on success
+}
+
 
 time_t util_parse_creationdate(char *str) {
-    // parse a ISO-8601 date
+    // parse a ISO-8601 date (rfc-3339)
     // example: 2012-11-29T21:35:35Z
     if(!str) {
         return 0;
     }
-    // TODO: implement
-    return 0;
+    
+    time_t result;
+    if(!parse_iso8601(str, &result)) {
+        return result;
+    } else {
+        return 0;
+    }
 }
 
 time_t util_parse_lastmodified(char *str) {

mercurial