os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixTime.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* 
     2  * tclUnixTime.c --
     3  *
     4  *	Contains Unix specific versions of Tcl functions that
     5  *	obtain time values from the operating system.
     6  *
     7  * Copyright (c) 1995 Sun Microsystems, Inc.
     8  * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
     9  *
    10  * See the file "license.terms" for information on usage and redistribution
    11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    12  *
    13  * RCS: @(#) $Id: tclUnixTime.c,v 1.15.2.6 2007/04/21 19:52:15 kennykb Exp $
    14  */
    15 
    16 #include "tclInt.h"
    17 #include "tclPort.h"
    18 #include <locale.h>
    19 #define TM_YEAR_BASE 1900
    20 #define IsLeapYear(x)   ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0))
    21 
    22 /*
    23  * TclpGetDate is coded to return a pointer to a 'struct tm'.  For
    24  * thread safety, this structure must be in thread-specific data.
    25  * The 'tmKey' variable is the key to this buffer.
    26  */
    27 
    28 static Tcl_ThreadDataKey tmKey;
    29 typedef struct ThreadSpecificData {
    30     struct tm gmtime_buf;
    31     struct tm localtime_buf;
    32 } ThreadSpecificData;
    33 
    34 /*
    35  * If we fall back on the thread-unsafe versions of gmtime and localtime,
    36  * use this mutex to try to protect them.
    37  */
    38 
    39 TCL_DECLARE_MUTEX(tmMutex)
    40 
    41 static char* lastTZ = NULL;	/* Holds the last setting of the
    42 				 * TZ environment variable, or an
    43 				 * empty string if the variable was
    44 				 * not set. */
    45 
    46 /* Static functions declared in this file */
    47 
    48 static void SetTZIfNecessary _ANSI_ARGS_((void));
    49 static void CleanupMemory _ANSI_ARGS_((ClientData));
    50 
    51 /*
    52  *-----------------------------------------------------------------------------
    53  *
    54  * TclpGetSeconds --
    55  *
    56  *	This procedure returns the number of seconds from the epoch.  On
    57  *	most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
    58  *
    59  * Results:
    60  *	Number of seconds from the epoch.
    61  *
    62  * Side effects:
    63  *	None.
    64  *
    65  *-----------------------------------------------------------------------------
    66  */
    67 
    68 unsigned long
    69 TclpGetSeconds()
    70 {
    71     return time((time_t *) NULL);
    72 }
    73 
    74 /*
    75  *-----------------------------------------------------------------------------
    76  *
    77  * TclpGetClicks --
    78  *
    79  *	This procedure returns a value that represents the highest resolution
    80  *	clock available on the system.  There are no garantees on what the
    81  *	resolution will be.  In Tcl we will call this value a "click".  The
    82  *	start time is also system dependant.
    83  *
    84  * Results:
    85  *	Number of clicks from some start time.
    86  *
    87  * Side effects:
    88  *	None.
    89  *
    90  *-----------------------------------------------------------------------------
    91  */
    92 
    93 unsigned long
    94 TclpGetClicks()
    95 {
    96     unsigned long now;
    97 #ifdef NO_GETTOD
    98     struct tms dummy;
    99 #else
   100     struct timeval date;
   101     struct timezone tz;
   102 #endif
   103 
   104 #ifdef NO_GETTOD
   105     now = (unsigned long) times(&dummy);
   106 #else
   107     gettimeofday(&date, &tz);
   108     now = date.tv_sec*1000000 + date.tv_usec;
   109 #endif
   110 
   111     return now;
   112 }
   113 
   114 /*
   115  *----------------------------------------------------------------------
   116  *
   117  * TclpGetTimeZone --
   118  *
   119  *	Determines the current timezone.  The method varies wildly
   120  *	between different platform implementations, so its hidden in
   121  *	this function.
   122  *
   123  * Results:
   124  *	The return value is the local time zone, measured in
   125  *	minutes away from GMT (-ve for east, +ve for west).
   126  *
   127  * Side effects:
   128  *	None.
   129  *
   130  *----------------------------------------------------------------------
   131  */
   132 
   133 int
   134 TclpGetTimeZone (currentTime)
   135     Tcl_WideInt  currentTime;
   136 {
   137     /*
   138      * We prefer first to use the time zone in "struct tm" if the
   139      * structure contains such a member.  Following that, we try
   140      * to locate the external 'timezone' variable and use its value.
   141      * If both of those methods fail, we attempt to convert a known
   142      * time to local time and use the difference from UTC as the local
   143      * time zone.  In all cases, we need to undo any Daylight Saving Time
   144      * adjustment.
   145      */
   146     
   147 #if defined(HAVE_TM_TZADJ)
   148 #   define TCL_GOT_TIMEZONE
   149 
   150     /* Struct tm contains tm_tzadj - that value may be used. */
   151 
   152     time_t      curTime = (time_t) currentTime;
   153     struct tm  *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime);
   154     int         timeZone;
   155 
   156     timeZone = timeDataPtr->tm_tzadj  / 60;
   157     if (timeDataPtr->tm_isdst) {
   158         timeZone += 60;
   159     }
   160     
   161     return timeZone;
   162 
   163 #endif
   164 
   165 #if defined(HAVE_TM_GMTOFF) && !defined (TCL_GOT_TIMEZONE)
   166 #   define TCL_GOT_TIMEZONE
   167 
   168     /* Struct tm contains tm_gmtoff - that value may be used. */
   169 
   170     time_t     curTime = (time_t) currentTime;
   171     struct tm *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime);
   172     int        timeZone;
   173 
   174     timeZone = -(timeDataPtr->tm_gmtoff / 60);
   175     if (timeDataPtr->tm_isdst) {
   176         timeZone += 60;
   177     }
   178     
   179     return timeZone;
   180 
   181 #endif
   182 
   183 #if defined(HAVE_TIMEZONE_VAR) && !defined(TCL_GOT_TIMEZONE) && !defined(USE_DELTA_FOR_TZ)
   184 #   define TCL_GOT_TIMEZONE
   185 
   186     int        timeZone;
   187 
   188     /* The 'timezone' external var is present and may be used. */
   189 
   190     SetTZIfNecessary();
   191 
   192     /*
   193      * Note: this is not a typo in "timezone" below!  See tzset
   194      * documentation for details.
   195      */
   196 
   197     timeZone = timezone / 60;
   198     return timeZone;
   199 
   200 #endif
   201 
   202 #if !defined(TCL_GOT_TIMEZONE) 
   203 #define TCL_GOT_TIMEZONE 1
   204     /*
   205      * Fallback - determine time zone with a known reference time.
   206      */
   207 
   208     int timeZone;
   209     time_t tt;
   210     struct tm *stm;
   211     tt = 849268800L;      /*    1996-11-29 12:00:00  GMT */
   212     stm = TclpLocaltime((TclpTime_t) &tt); /* eg 1996-11-29  6:00:00  CST6CDT */
   213     /* The calculation below assumes a max of +12 or -12 hours from GMT */
   214     timeZone = (12 - stm->tm_hour)*60 + (0 - stm->tm_min);
   215     if ( stm -> tm_isdst ) {
   216         timeZone += 60;
   217     }
   218     return timeZone;  /* eg +360 for CST6CDT */
   219 #endif
   220 
   221 #ifndef TCL_GOT_TIMEZONE
   222     /*
   223      * Cause compile error, we don't know how to get timezone.
   224      */
   225 
   226 #error autoconf did not figure out how to determine the timezone. 
   227 
   228 #endif
   229 
   230 }
   231 
   232 /*
   233  *----------------------------------------------------------------------
   234  *
   235  * Tcl_GetTime --
   236  *
   237  *	Gets the current system time in seconds and microseconds
   238  *	since the beginning of the epoch: 00:00 UCT, January 1, 1970.
   239  *
   240  * Results:
   241  *	Returns the current time in timePtr.
   242  *
   243  * Side effects:
   244  *	None.
   245  *
   246  *----------------------------------------------------------------------
   247  */
   248 
   249 EXPORT_C void
   250 Tcl_GetTime(timePtr)
   251     Tcl_Time *timePtr;		/* Location to store time information. */
   252 {
   253     struct timeval tv;
   254     struct timezone tz;
   255     
   256     (void) gettimeofday(&tv, &tz);
   257     timePtr->sec = tv.tv_sec;
   258     timePtr->usec = tv.tv_usec;
   259 }
   260 
   261 /*
   262  *----------------------------------------------------------------------
   263  *
   264  * TclpGetDate --
   265  *
   266  *	This function converts between seconds and struct tm.  If
   267  *	useGMT is true, then the returned date will be in Greenwich
   268  *	Mean Time (GMT).  Otherwise, it will be in the local time zone.
   269  *
   270  * Results:
   271  *	Returns a static tm structure.
   272  *
   273  * Side effects:
   274  *	None.
   275  *
   276  *----------------------------------------------------------------------
   277  */
   278 
   279 struct tm *
   280 TclpGetDate(time, useGMT)
   281     TclpTime_t time;
   282     int useGMT;
   283 {
   284     if (useGMT) {
   285 	return TclpGmtime(time);
   286     } else {
   287 	return TclpLocaltime(time);
   288     }
   289 }
   290 
   291 /*
   292  *----------------------------------------------------------------------
   293  *
   294  * TclpStrftime --
   295  *
   296  *	On Unix, we can safely call the native strftime implementation,
   297  *	and also ignore the useGMT parameter.
   298  *
   299  * Results:
   300  *	The normal strftime result.
   301  *
   302  * Side effects:
   303  *	None.
   304  *
   305  *----------------------------------------------------------------------
   306  */
   307 
   308 size_t
   309 TclpStrftime(s, maxsize, format, t, useGMT)
   310     char *s;
   311     size_t maxsize;
   312     CONST char *format;
   313     CONST struct tm *t;
   314     int useGMT;
   315 {
   316     if (format[0] == '%' && format[1] == 'Q') {
   317 	/* Format as a stardate */
   318 	sprintf(s, "Stardate %2d%03d.%01d",
   319 		(((t->tm_year + TM_YEAR_BASE) + 377) - 2323),
   320 		(((t->tm_yday + 1) * 1000) /
   321 			(365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))),
   322 		(((t->tm_hour * 60) + t->tm_min)/144));
   323 	return(strlen(s));
   324     }
   325     setlocale(LC_TIME, "");
   326     return strftime(s, maxsize, format, t);
   327 }
   328 
   329 /*
   330  *----------------------------------------------------------------------
   331  *
   332  * TclpGmtime --
   333  *
   334  *	Wrapper around the 'gmtime' library function to make it thread
   335  *	safe.
   336  *
   337  * Results:
   338  *	Returns a pointer to a 'struct tm' in thread-specific data.
   339  *
   340  * Side effects:
   341  *	Invokes gmtime or gmtime_r as appropriate.
   342  *
   343  *----------------------------------------------------------------------
   344  */
   345 
   346 struct tm *
   347 TclpGmtime( tt )
   348     TclpTime_t_CONST tt;
   349 {
   350     CONST time_t *timePtr = (CONST time_t *) tt;
   351 				/* Pointer to the number of seconds
   352 				 * since the local system's epoch */
   353 
   354     /*
   355      * Get a thread-local buffer to hold the returned time.
   356      */
   357 
   358     ThreadSpecificData *tsdPtr = TCL_TSD_INIT( &tmKey );
   359 #ifdef HAVE_GMTIME_R
   360     gmtime_r(timePtr, &( tsdPtr->gmtime_buf ));
   361 #else
   362     Tcl_MutexLock( &tmMutex );
   363     memcpy( (VOID *) &( tsdPtr->gmtime_buf ),
   364 	    (VOID *) gmtime( timePtr ),
   365 	    sizeof( struct tm ) );
   366     Tcl_MutexUnlock( &tmMutex );
   367 #endif    
   368     return &( tsdPtr->gmtime_buf );
   369 }
   370 /*
   371  * Forwarder for obsolete item in Stubs
   372  */
   373 struct tm*
   374 TclpGmtime_unix( timePtr )
   375     TclpTime_t_CONST timePtr;
   376 {
   377     return TclpGmtime( timePtr );
   378 }
   379 
   380 /*
   381  *----------------------------------------------------------------------
   382  *
   383  * TclpLocaltime --
   384  *
   385  *	Wrapper around the 'localtime' library function to make it thread
   386  *	safe.
   387  *
   388  * Results:
   389  *	Returns a pointer to a 'struct tm' in thread-specific data.
   390  *
   391  * Side effects:
   392  *	Invokes localtime or localtime_r as appropriate.
   393  *
   394  *----------------------------------------------------------------------
   395  */
   396 
   397 struct tm *
   398 TclpLocaltime( tt )
   399     TclpTime_t_CONST tt;
   400 {
   401     CONST time_t *timePtr = (CONST time_t *) tt;
   402 				/* Pointer to the number of seconds
   403 				 * since the local system's epoch */
   404     /*
   405      * Get a thread-local buffer to hold the returned time.
   406      */
   407 
   408     ThreadSpecificData *tsdPtr = TCL_TSD_INIT( &tmKey );
   409     SetTZIfNecessary();
   410 #ifdef HAVE_LOCALTIME_R
   411     localtime_r( timePtr, &( tsdPtr->localtime_buf ) );
   412 #else
   413     Tcl_MutexLock( &tmMutex );
   414     memcpy( (VOID *) &( tsdPtr -> localtime_buf ),
   415 	    (VOID *) localtime( timePtr ),
   416 	    sizeof( struct tm ) );
   417     Tcl_MutexUnlock( &tmMutex );
   418 #endif    
   419     return &( tsdPtr->localtime_buf );
   420 }
   421 /*
   422  * Forwarder for obsolete item in Stubs
   423  */
   424 struct tm*
   425 TclpLocaltime_unix( timePtr )
   426     TclpTime_t_CONST timePtr;
   427 {
   428     return TclpLocaltime( timePtr );
   429 }
   430 
   431 /*
   432  *----------------------------------------------------------------------
   433  *
   434  * SetTZIfNecessary --
   435  *
   436  *	Determines whether a call to 'tzset' is needed prior to the
   437  *	next call to 'localtime' or examination of the 'timezone' variable.
   438  *
   439  * Results:
   440  *	None.
   441  *
   442  * Side effects:
   443  *	If 'tzset' has never been called in the current process, or if
   444  *	the value of the environment variable TZ has changed since the
   445  *	last call to 'tzset', then 'tzset' is called again.
   446  *
   447  *----------------------------------------------------------------------
   448  */
   449 
   450 static void
   451 SetTZIfNecessary() {
   452 
   453     CONST char* newTZ = getenv( "TZ" );
   454     Tcl_MutexLock(&tmMutex);
   455     if ( newTZ == NULL ) {
   456 	newTZ = "";
   457     }
   458     if ( lastTZ == NULL || strcmp( lastTZ, newTZ ) ) {
   459         tzset();
   460 	if ( lastTZ == NULL ) {
   461 	    Tcl_CreateExitHandler( CleanupMemory, (ClientData) NULL );
   462 	} else {
   463 	    Tcl_Free( lastTZ );
   464 	}
   465 	lastTZ = ckalloc( strlen( newTZ ) + 1 );
   466 	strcpy( lastTZ, newTZ );
   467     }
   468     Tcl_MutexUnlock(&tmMutex);
   469 
   470 }
   471 
   472 /*
   473  *----------------------------------------------------------------------
   474  *
   475  * CleanupMemory --
   476  *
   477  *	Releases the private copy of the TZ environment variable
   478  *	upon exit from Tcl.
   479  *
   480  * Results:
   481  *	None.
   482  *
   483  * Side effects:
   484  *	Frees allocated memory.
   485  *
   486  *----------------------------------------------------------------------
   487  */
   488 
   489 static void
   490 CleanupMemory( ClientData ignored )
   491 {
   492     ckfree( lastTZ );
   493 }