Include config.h to get HAVE_LOCALTIME_R macro.
[platform/upstream/glib.git] / gdate.c
diff --git a/gdate.c b/gdate.c
index c8569fb..44a6bad 100644 (file)
--- a/gdate.c
+++ b/gdate.c
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/* 
+ * MT safe
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include "glib.h"
 
 #include <time.h>
@@ -383,6 +392,8 @@ g_date_clear (GDate       *d, guint ndates)
   memset (d, 0x0, ndates*sizeof (GDate)); 
 }
 
+G_LOCK_DECLARE_STATIC (g_date_global);
+
 /* These are for the parser, output to the user should use *
  * g_date_strftime () - this creates more never-freed memory to annoy
  * all those memory debugger users. :-) 
@@ -429,6 +440,7 @@ typedef struct _GDateParseTokens GDateParseTokens;
 
 #define NUM_LEN 10
 
+/* HOLDS: g_date_global_lock */
 static void
 g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
 {
@@ -488,7 +500,7 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
               if (found != NULL)
                 {
                   pt->month = i;
-                  return;
+                 return;
                 }
             }
          
@@ -502,12 +514,13 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
                   return;
                 }
             }
-         
+
           ++i;
-        }
+        }      
     }
 }
 
+/* HOLDS: g_date_global_lock */
 static void
 g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt)
 {
@@ -557,7 +570,9 @@ g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt)
       
       /* Determine DMY order */
       
-      g_date_set_dmy (&d, 4, 7, 1776); /* had to pick a random day */
+      /* had to pick a random day - don't change this, some strftimes
+       * are broken on some days, and this one is good so far. */
+      g_date_set_dmy (&d, 4, 7, 1976);
       
       g_date_strftime (buf, 127, "%x", &d);
       
@@ -576,7 +591,7 @@ g_date_prepare_to_parse (const gchar *str, GDateParseTokens *pt)
               break;
             case 76:
               using_twodigit_years = TRUE; /* FALL THRU */
-            case 1776:
+            case 1976:
               dmy_order[i] = G_DATE_YEAR;
               break;
             default:
@@ -641,6 +656,8 @@ g_date_set_parse (GDate       *d,
   /* set invalid */
   g_date_clear (d, 1);
   
+  G_LOCK (g_date_global);
+
   g_date_prepare_to_parse (str, &pt);
   
 #ifdef G_ENABLE_DEBUG
@@ -649,7 +666,11 @@ g_date_set_parse (GDate       *d,
 #endif
   
   
-  if (pt.num_ints == 4) return; /* presumably a typo; bail out. */
+  if (pt.num_ints == 4) 
+    {
+      G_UNLOCK (g_date_global);
+      return; /* presumably a typo; bail out. */
+    }
   
   if (pt.num_ints > 1)
     {
@@ -765,6 +786,7 @@ g_date_set_parse (GDate       *d,
   else 
     g_message ("Rejected DMY %u %u %u", day, m, y);
 #endif
+  G_UNLOCK (g_date_global);
 }
 
 void         
@@ -772,28 +794,33 @@ g_date_set_time (GDate *d,
                 GTime  time)
 {
   time_t t = time;
-  struct tm *tm;
+  struct tm tm;
   
   g_return_if_fail (d != NULL);
   
-  tm = localtime (&t);
+#ifdef HAVE_LOCALTIME_R
+  localtime_r (&t, &tm);
+#else
+#  ifdef G_THREADS_ENABLED
+#  warning "the `g_date_set_time' function will not be MT-safe"
+#  warning "because there is no `localtime_r' on your system."
+#  endif
+  {
+    struct tm *ptm = localtime (&t);
+    g_assert (ptm);
+    memcpy ((void *) &tm, (void *) ptm, sizeof(struct tm));
+  }
+#endif
   
-  if (tm) 
-    {
-      d->julian = FALSE;
-      
-      d->month = tm->tm_mon + 1;
-      d->day   = tm->tm_mday;
-      d->year  = tm->tm_year + 1900;
-      
-      g_return_if_fail (g_date_valid_dmy (d->day, d->month, d->year));
-      
-      d->dmy    = TRUE;
-    }
-  else 
-    {
-      g_date_clear (d, 1);
-    }
+  d->julian = FALSE;
+  
+  d->month = tm.tm_mon + 1;
+  d->day   = tm.tm_mday;
+  d->year  = tm.tm_year + 1900;
+  
+  g_return_if_fail (g_date_valid_dmy (d->day, d->month, d->year));
+  
+  d->dmy    = TRUE;
 }
 
 void         
@@ -802,7 +829,8 @@ g_date_set_month (GDate     *d,
 {
   g_return_if_fail (d != NULL);
   g_return_if_fail (g_date_valid_month (m));
-  
+
+  if (d->julian && !d->dmy) g_date_update_dmy(d);
   d->julian = FALSE;
   
   d->month = m;
@@ -820,6 +848,7 @@ g_date_set_day (GDate     *d,
   g_return_if_fail (d != NULL);
   g_return_if_fail (g_date_valid_day (day));
   
+  if (d->julian && !d->dmy) g_date_update_dmy(d);
   d->julian = FALSE;
   
   d->day = day;
@@ -837,6 +866,7 @@ g_date_set_year (GDate     *d,
   g_return_if_fail (d != NULL);
   g_return_if_fail (g_date_valid_year (y));
   
+  if (d->julian && !d->dmy) g_date_update_dmy(d);
   d->julian = FALSE;
   
   d->year = y;