Browse Source

replace gmtime with a clean implementation

On windows, gmtime may return NULL if it doesn't like the date.
The replacement is added as an external dependency
Julius Pfrommer 9 years ago
parent
commit
e452dcf8e3
4 changed files with 98 additions and 1 deletions
  1. 2 0
      CMakeLists.txt
  2. 85 0
      deps/libc_time.c
  3. 8 0
      deps/libc_time.h
  4. 3 1
      src/ua_types.c

+ 2 - 0
CMakeLists.txt

@@ -182,6 +182,7 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/src_extra/logger_stdout.h)
 set(internal_headers ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
+                     ${PROJECT_SOURCE_DIR}/deps/libc_time.h
                      ${PROJECT_SOURCE_DIR}/src/ua_util.h
                      ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
@@ -219,6 +220,7 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel.c
                 ${PROJECT_SOURCE_DIR}/src_extra/networklayer_tcp.c
                 ${PROJECT_SOURCE_DIR}/src_extra/logger_stdout.c
+                ${PROJECT_SOURCE_DIR}/deps/libc_time.c
                 ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
                 ##TODO: make client stuff optional
 

+ 85 - 0
deps/libc_time.c

@@ -0,0 +1,85 @@
+/*
+ * Originally released by the musl project (http://www.musl-libc.org/) under the
+ * MIT license. Taken from the file /src/time/__secs_to_tm.c
+ */
+
+#include "libc_time.h"
+
+/* 2000-03-01 (mod 400 year, immediately after feb29 */
+#define LEAPOCH (946684800LL + 86400*(31+29))
+
+#define DAYS_PER_400Y (365*400 + 97)
+#define DAYS_PER_100Y (365*100 + 24)
+#define DAYS_PER_4Y   (365*4   + 1)
+
+int __secs_to_tm(long long t, struct tm *tm)
+{
+    long long days, secs, years;
+    int remdays, remsecs, remyears;
+    int qc_cycles, c_cycles, q_cycles;
+    int months;
+    int wday, yday, leap;
+    static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29};
+
+    /* Reject time_t values whose year would overflow int */
+    if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
+        return -1;
+
+    secs = t - LEAPOCH;
+    days = secs / 86400LL;
+    remsecs = (int)(secs % 86400);
+    if (remsecs < 0) {
+        remsecs += 86400;
+        days--;
+    }
+
+    wday = (int)((3+days)%7);
+    if (wday < 0) wday += 7;
+
+    qc_cycles = (int)(days / DAYS_PER_400Y);
+    remdays = (int)(days % DAYS_PER_400Y);
+    if (remdays < 0) {
+        remdays += DAYS_PER_400Y;
+        qc_cycles--;
+    }
+
+    c_cycles = remdays / DAYS_PER_100Y;
+    if (c_cycles == 4) c_cycles--;
+    remdays -= c_cycles * DAYS_PER_100Y;
+
+    q_cycles = remdays / DAYS_PER_4Y;
+    if (q_cycles == 25) q_cycles--;
+    remdays -= q_cycles * DAYS_PER_4Y;
+
+    remyears = remdays / 365;
+    if (remyears == 4) remyears--;
+    remdays -= remyears * 365;
+
+    leap = !remyears && (q_cycles || !c_cycles);
+    yday = remdays + 31 + 28 + leap;
+    if (yday >= 365+leap) yday -= 365+leap;
+
+    years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles;
+
+    for (months=0; days_in_month[months] <= remdays; months++)
+        remdays -= days_in_month[months];
+
+    if (years+100 > INT_MAX || years+100 < INT_MIN)
+        return -1;
+
+    tm->tm_year = (int)(years + 100);
+    tm->tm_mon = months + 2;
+    if (tm->tm_mon >= 12) {
+        tm->tm_mon -=12;
+        tm->tm_year++;
+    }
+    tm->tm_mday = remdays + 1;
+    tm->tm_wday = wday;
+    tm->tm_yday = yday;
+
+    tm->tm_hour = remsecs / 3600;
+    tm->tm_min = remsecs / 60 % 60;
+    tm->tm_sec = remsecs % 60;
+
+    return 0;
+}

+ 8 - 0
deps/libc_time.h

@@ -0,0 +1,8 @@
+#ifndef LIBC_TIME_H_
+#define LIBC_TIME_H_
+
+#include <limits.h>
+#include <time.h>
+int __secs_to_tm(long long t, struct tm *tm);
+
+#endif /* LIBC_TIME_H_ */

+ 3 - 1
src/ua_types.c

@@ -4,6 +4,7 @@
 #include "ua_types_generated.h"
 
 #include "pcg_basic.h"
+#include "libc_time.h"
 
 /* static variables */
 UA_EXPORT const UA_String UA_STRING_NULL = {.length = 0, .data = NULL };
@@ -106,7 +107,8 @@ UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t) {
 
     /* Calculating the unix time with #include <time.h> */
     time_t secSinceUnixEpoch = (time_t)((t - UA_DATETIME_UNIX_EPOCH) / UA_SEC_TO_DATETIME);
-    struct tm ts = *gmtime(&secSinceUnixEpoch);
+    struct tm ts = {0};
+    __secs_to_tm(secSinceUnixEpoch, &ts);
     dateTimeStruct.sec    = (UA_UInt16)ts.tm_sec;
     dateTimeStruct.min    = (UA_UInt16)ts.tm_min;
     dateTimeStruct.hour   = (UA_UInt16)ts.tm_hour;