Fix: Replace bt_timegm with a thread-safe implementation
[babeltrace.git] / include / babeltrace / compat / utc-internal.h
index db3035a3ad6ec51b65270e2cbb49c062910e1d1c..3660e08ec66fc86769a1df585bd9f0174da4013a 100644 (file)
@@ -44,50 +44,60 @@ time_t bt_timegm(struct tm *tm)
 
 #else
 
-#include <string.h>
-#include <stdlib.h>
-#include <glib.h>
+#include <errno.h>
 
 /*
- * Note: Below implementation of timegm() is not thread safe
- * as it changes the environment
- * variable TZ. It is OK as long as it is kept in self-contained program,
- * but should not be used within thread-safe library code.
+ * This is a simple implementation of timegm() it just turns the "struct tm" into
+ * a GMT time_t. It does not normalize any of the fields of the "struct tm", nor
+ * does it set tm_wday or tm_yday.
  */
 
+static inline
+int bt_leapyear(int year)
+{
+    return ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0));
+}
+
 static inline
 time_t bt_timegm(struct tm *tm)
 {
-       time_t ret;
-       char *tz;
-
-       tz = getenv("TZ");
-       /*
-        * Make a temporary copy, as the environment variable will be
-        * modified.
-        */
-       if (tz) {
-               tz = strdup(tz);
-               if (!tz) {
-                       /*
-                        * Memory allocation error.
-                        */
-                       return (time_t) -1;
+       int year, month, total_days;
+
+       int monthlen[2][12] = {
+               /* Days per month for a regular year */
+               { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+               /* Days per month for a leap year */
+               { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+       };
+
+       if ((tm->tm_mon >= 12) ||
+                       (tm->tm_mday >= 32) ||
+                       (tm->tm_hour >= 24) ||
+                       (tm->tm_min >= 60) ||
+                       (tm->tm_sec >= 61)) {
+               errno = EOVERFLOW;
+               return (time_t) -1;
+       }
+
+       /* Add 365 days for each year since 1970 */
+       total_days = 365 * (tm->tm_year - 70);
+
+       /* Add one day for each leap year since 1970 */
+       for (year = 70; year < tm->tm_year; year++) {
+               if (bt_leapyear(1900 + year)) {
+                       total_days++;
                }
        }
 
-       /* Temporarily setting TZ to 1 for UTC */
-       g_setenv("TZ", "", 1);
-       tzset();
-       ret = mktime(tm);
-       if (tz) {
-               g_setenv("TZ", tz, 1);
-               free(tz);
-       } else {
-               unsetenv("TZ");
+       /* Add days for each remaining month */
+       for (month = 0; month < tm->tm_mon; month++) {
+               total_days += monthlen[bt_leapyear(1900 + year)][month];
        }
-       tzset();
-       return ret;
+
+       /* Add remaining days */
+       total_days += tm->tm_mday - 1;
+
+       return ((((total_days * 24) + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec);
 }
 
 #endif
This page took 0.02491 seconds and 4 git commands to generate.