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