os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacTime.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* 
     2  * tclMacTime.c --
     3  *
     4  *	Contains Macintosh specific versions of Tcl functions that
     5  *	obtain time values from the operating system.
     6  *
     7  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
     8  *
     9  * See the file "license.terms" for information on usage and redistribution
    10  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    11  *
    12  * RCS: @(#) $Id: tclMacTime.c,v 1.7 2002/01/04 11:21:05 das Exp $
    13  */
    14 
    15 #include "tclInt.h"
    16 #include "tclPort.h"
    17 #include "tclMacInt.h"
    18 #include <OSUtils.h>
    19 #include <Timer.h>
    20 #include <time.h>
    21 
    22 /*
    23  * Static variables used by the Tcl_GetTime function.
    24  */
    25  
    26 static int initalized = false;
    27 static unsigned long baseSeconds;
    28 static UnsignedWide microOffset;
    29 
    30 static int gmt_initialized = false;
    31 static long gmt_offset;
    32 static int gmt_isdst;
    33 TCL_DECLARE_MUTEX(gmtMutex)
    34 
    35 static int gmt_lastGetDateUseGMT = 0;
    36 
    37 typedef struct _TABLE {
    38     char        *name;
    39     int         type;
    40     time_t      value;
    41 } TABLE;
    42 
    43 
    44 #define HOUR(x)         ((time_t) (3600 * x))
    45 
    46 #define tZONE 0
    47 #define tDAYZONE 1
    48 
    49 
    50 /*
    51  * inverse timezone table, adapted from tclDate.c by removing duplicates and
    52  * adding some made up names for unusual daylight savings
    53  */
    54 static TABLE    invTimezoneTable[] = {
    55     { "Z",    -1,     HOUR( 36) },      /* Unknown */
    56     { "GMT",    tZONE,     HOUR( 0) },      /* Greenwich Mean */
    57     { "BST",    tDAYZONE,  HOUR( 0) },      /* British Summer */
    58     { "WAT",    tZONE,     HOUR( 1) },      /* West Africa */
    59     { "WADST",  tDAYZONE,  HOUR( 1) },      /* West Africa Daylight*/
    60     { "AT",     tZONE,     HOUR( 2) },      /* Azores Daylight*/
    61     { "ADST",   tDAYZONE,  HOUR( 2) },      /* Azores */
    62     { "NFT",    tZONE,     HOUR( 7/2) },    /* Newfoundland */
    63     { "NDT",    tDAYZONE,  HOUR( 7/2) },    /* Newfoundland Daylight */
    64     { "AST",    tZONE,     HOUR( 4) },      /* Atlantic Standard */
    65     { "ADT",    tDAYZONE,  HOUR( 4) },      /* Atlantic Daylight */
    66     { "EST",    tZONE,     HOUR( 5) },      /* Eastern Standard */
    67     { "EDT",    tDAYZONE,  HOUR( 5) },      /* Eastern Daylight */
    68     { "CST",    tZONE,     HOUR( 6) },      /* Central Standard */
    69     { "CDT",    tDAYZONE,  HOUR( 6) },      /* Central Daylight */
    70     { "MST",    tZONE,     HOUR( 7) },      /* Mountain Standard */
    71     { "MDT",    tDAYZONE,  HOUR( 7) },      /* Mountain Daylight */
    72     { "PST",    tZONE,     HOUR( 8) },      /* Pacific Standard */
    73     { "PDT",    tDAYZONE,  HOUR( 8) },      /* Pacific Daylight */
    74     { "YST",    tZONE,     HOUR( 9) },      /* Yukon Standard */
    75     { "YDT",    tDAYZONE,  HOUR( 9) },      /* Yukon Daylight */
    76     { "HST",    tZONE,     HOUR(10) },      /* Hawaii Standard */
    77     { "HDT",    tDAYZONE,  HOUR(10) },      /* Hawaii Daylight */
    78     { "NT",     tZONE,     HOUR(11) },      /* Nome */
    79     { "NST",    tDAYZONE,  HOUR(11) },      /* Nome Daylight*/
    80     { "IDLW",   tZONE,     HOUR(12) },      /* International Date Line West */
    81     { "CET",    tZONE,    -HOUR( 1) },      /* Central European */
    82     { "CEST",   tDAYZONE, -HOUR( 1) },      /* Central European Summer */
    83     { "EET",    tZONE,    -HOUR( 2) },      /* Eastern Europe, USSR Zone 1 */
    84     { "EEST",   tDAYZONE, -HOUR( 2) },      /* Eastern Europe, USSR Zone 1 Daylight*/
    85     { "BT",     tZONE,    -HOUR( 3) },      /* Baghdad, USSR Zone 2 */
    86     { "BDST",   tDAYZONE, -HOUR( 3) },      /* Baghdad, USSR Zone 2 Daylight*/
    87     { "IT",     tZONE,    -HOUR( 7/2) },    /* Iran */
    88     { "IDST",   tDAYZONE, -HOUR( 7/2) },    /* Iran Daylight*/
    89     { "ZP4",    tZONE,    -HOUR( 4) },      /* USSR Zone 3 */
    90     { "ZP4S",   tDAYZONE, -HOUR( 4) },      /* USSR Zone 3 */
    91     { "ZP5",    tZONE,    -HOUR( 5) },      /* USSR Zone 4 */
    92     { "ZP5S",   tDAYZONE, -HOUR( 5) },      /* USSR Zone 4 */
    93     { "IST",    tZONE,    -HOUR(11/2) },    /* Indian Standard */
    94     { "ISDST",  tDAYZONE, -HOUR(11/2) },    /* Indian Standard */
    95     { "ZP6",    tZONE,    -HOUR( 6) },      /* USSR Zone 5 */
    96     { "ZP6S",   tDAYZONE, -HOUR( 6) },      /* USSR Zone 5 */
    97     { "WAST",   tZONE,    -HOUR( 7) },      /* West Australian Standard */
    98     { "WADT",   tDAYZONE, -HOUR( 7) },      /* West Australian Daylight */
    99     { "JT",     tZONE,    -HOUR(15/2) },    /* Java (3pm in Cronusland!) */
   100     { "JDST",   tDAYZONE, -HOUR(15/2) },    /* Java (3pm in Cronusland!) */
   101     { "CCT",    tZONE,    -HOUR( 8) },      /* China Coast, USSR Zone 7 */
   102     { "CCST",   tDAYZONE, -HOUR( 8) },      /* China Coast, USSR Zone 7 */
   103     { "JST",    tZONE,    -HOUR( 9) },      /* Japan Standard, USSR Zone 8 */
   104     { "JSDST",  tDAYZONE, -HOUR( 9) },      /* Japan Standard, USSR Zone 8 */
   105     { "CAST",   tZONE,    -HOUR(19/2) },    /* Central Australian Standard */
   106     { "CADT",   tDAYZONE, -HOUR(19/2) },    /* Central Australian Daylight */
   107     { "EAST",   tZONE,    -HOUR(10) },      /* Eastern Australian Standard */
   108     { "EADT",   tDAYZONE, -HOUR(10) },      /* Eastern Australian Daylight */
   109     { "NZT",    tZONE,    -HOUR(12) },      /* New Zealand */
   110     { "NZDT",   tDAYZONE, -HOUR(12) },      /* New Zealand Daylight */
   111     {  NULL  }
   112 };
   113 
   114 /*
   115  * Prototypes for procedures that are private to this file:
   116  */
   117 
   118 static void SubtractUnsignedWide _ANSI_ARGS_((UnsignedWide *x,
   119 	UnsignedWide *y, UnsignedWide *result));
   120 
   121 /*
   122  *-----------------------------------------------------------------------------
   123  *
   124  * TclpGetGMTOffset --
   125  *
   126  *	This procedure gets the offset seconds that needs to be _added_ to tcl time
   127  *  in seconds (i.e. GMT time) to get local time needed as input to various
   128  *  Mac OS APIs, to convert Mac OS API output to tcl time, _subtract_ this value.
   129  *
   130  * Results:
   131  *	Number of seconds separating GMT time and mac.
   132  *
   133  * Side effects:
   134  *	None.
   135  *
   136  *-----------------------------------------------------------------------------
   137  */
   138 
   139 long
   140 TclpGetGMTOffset()
   141 {
   142     if (gmt_initialized == false) {
   143 	MachineLocation loc;
   144 	
   145     Tcl_MutexLock(&gmtMutex);
   146 	ReadLocation(&loc);
   147 	gmt_offset = loc.u.gmtDelta & 0x00ffffff;
   148 	if (gmt_offset & 0x00800000) {
   149 	    gmt_offset = gmt_offset | 0xff000000;
   150 	}
   151 	gmt_isdst=(loc.u.dlsDelta < 0);
   152 	gmt_initialized = true;
   153     Tcl_MutexUnlock(&gmtMutex);
   154     }
   155 	return (gmt_offset);
   156 }
   157 
   158 /*
   159  *-----------------------------------------------------------------------------
   160  *
   161  * TclpGetSeconds --
   162  *
   163  *	This procedure returns the number of seconds from the epoch.  On
   164  *	the Macintosh the epoch is Midnight Jan 1, 1904.  Unfortunatly,
   165  *	the Macintosh doesn't tie the epoch to a particular time zone.  For
   166  *	Tcl we tie the epoch to GMT.  This makes the time zone date parsing
   167  *	code work.  The epoch for Mac-Tcl is: Midnight Jan 1, 1904 GMT.
   168  *
   169  * Results:
   170  *	Number of seconds from the epoch in GMT.
   171  *
   172  * Side effects:
   173  *	None.
   174  *
   175  *-----------------------------------------------------------------------------
   176  */
   177 
   178 unsigned long
   179 TclpGetSeconds()
   180 {
   181     unsigned long seconds;
   182 
   183     GetDateTime(&seconds);
   184 	return (seconds - TclpGetGMTOffset() + tcl_mac_epoch_offset);
   185 }
   186 
   187 /*
   188  *-----------------------------------------------------------------------------
   189  *
   190  * TclpGetClicks --
   191  *
   192  *	This procedure returns a value that represents the highest resolution
   193  *	clock available on the system.  There are no garantees on what the
   194  *	resolution will be.  In Tcl we will call this value a "click".  The
   195  *	start time is also system dependant.
   196  *
   197  * Results:
   198  *	Number of clicks from some start time.
   199  *
   200  * Side effects:
   201  *	None.
   202  *
   203  *-----------------------------------------------------------------------------
   204  */
   205 
   206 unsigned long
   207 TclpGetClicks()
   208 {
   209     UnsignedWide micros;
   210 
   211     Microseconds(&micros);
   212     return micros.lo;
   213 }
   214 
   215 /*
   216  *----------------------------------------------------------------------
   217  *
   218  * TclpGetTimeZone --
   219  *
   220  *	Get the current time zone.
   221  *
   222  * Results:
   223  *	The return value is the local time zone, measured in
   224  *	minutes away from GMT (-ve for east, +ve for west).
   225  *
   226  * Side effects:
   227  *	None.
   228  *
   229  *----------------------------------------------------------------------
   230  */
   231 
   232 int
   233 TclpGetTimeZone (
   234     unsigned long  currentTime)		/* Ignored on Mac. */
   235 {
   236     long offset;
   237 
   238     /*
   239      * Convert the Mac offset from seconds to minutes and
   240      * add an hour if we have daylight savings time.
   241      */
   242     offset = -TclpGetGMTOffset();
   243     offset /= 60;
   244     if (gmt_isdst) {
   245 	offset += 60;
   246     }
   247     
   248     return offset;
   249 }
   250 
   251 /*
   252  *----------------------------------------------------------------------
   253  *
   254  * Tcl_GetTime --
   255  *
   256  *	Gets the current system time in seconds and microseconds
   257  *	since the beginning of the epoch: 00:00 UCT, January 1, 1970.
   258  *
   259  * Results:
   260  *	Returns the current time (in the local timezone) in timePtr.
   261  *
   262  * Side effects:
   263  *	None.
   264  *
   265  *----------------------------------------------------------------------
   266  */
   267 
   268 void
   269 Tcl_GetTime(
   270     Tcl_Time *timePtr)		/* Location to store time information. */
   271 {
   272     UnsignedWide micro;
   273 #ifndef NO_LONG_LONG
   274     long long *microPtr;
   275 #endif
   276 	
   277     if (initalized == false) {
   278 	GetDateTime(&baseSeconds);
   279 	/*
   280 	 * Remove the local offset that ReadDateTime() adds.
   281 	 */
   282 	baseSeconds -= TclpGetGMTOffset() - tcl_mac_epoch_offset;
   283 	Microseconds(&microOffset);
   284 	initalized = true;
   285     }
   286 
   287     Microseconds(&micro);
   288 
   289 #ifndef NO_LONG_LONG
   290     microPtr = (long long *) &micro;
   291     *microPtr -= *((long long *) &microOffset);
   292     timePtr->sec = baseSeconds + (*microPtr / 1000000);
   293     timePtr->usec = *microPtr % 1000000;
   294 #else
   295     SubtractUnsignedWide(&micro, &microOffset, &micro);
   296 
   297     /*
   298      * This lovely computation is equal to: base + (micro / 1000000)
   299      * For the .hi part the ratio of 0x100000000 / 1000000 has been
   300      * reduced to avoid overflow.  This computation certainly has 
   301      * problems as the .hi part gets large.  However, your application
   302      * would have to run for a long time to make that happen.
   303      */
   304 
   305     timePtr->sec = baseSeconds + (micro.lo / 1000000) + 
   306     	(long) (micro.hi * ((double) 33554432.0 / 15625.0));
   307     timePtr->usec = micro.lo % 1000000;
   308 #endif
   309 }
   310 
   311 /*
   312  *----------------------------------------------------------------------
   313  *
   314  * TclpGetDate --
   315  *
   316  *	Converts raw seconds to a struct tm data structure.  The
   317  *	returned time will be for Greenwich Mean Time if the useGMT flag 
   318  *	is set.  Otherwise, the returned time will be for the local
   319  *	time zone.  This function is meant to be used as a replacement
   320  *	for localtime and gmtime which is broken on most ANSI libs
   321  *	on the Macintosh.
   322  *
   323  * Results:
   324  *	None.
   325  *
   326  * Side effects:
   327  *  	The passed in struct tm data structure is modified.
   328  *
   329  *----------------------------------------------------------------------
   330  */
   331 
   332 struct tm *
   333 TclpGetDate(
   334     TclpTime_t time,	/* Time struct to fill. */
   335     int useGMT)		/* True if date should reflect GNT time. */
   336 {
   337     const time_t *tp = (const time_t *)time;
   338     DateTimeRec dtr;
   339     unsigned long offset=0L;
   340     static struct tm statictime;
   341     static const short monthday[12] =
   342         {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
   343 	    
   344 	if(useGMT)
   345 		SecondsToDate(*tp - tcl_mac_epoch_offset, &dtr);
   346 	else
   347 		SecondsToDate(*tp + TclpGetGMTOffset() - tcl_mac_epoch_offset, &dtr);
   348 	
   349     statictime.tm_sec = dtr.second;
   350     statictime.tm_min = dtr.minute;
   351     statictime.tm_hour = dtr.hour;
   352     statictime.tm_mday = dtr.day;
   353     statictime.tm_mon = dtr.month - 1;
   354     statictime.tm_year = dtr.year - 1900;
   355     statictime.tm_wday = dtr.dayOfWeek - 1;
   356     statictime.tm_yday = monthday[statictime.tm_mon]
   357 	+ statictime.tm_mday - 1;
   358     if (1 < statictime.tm_mon && !(statictime.tm_year & 3)) {
   359 	++statictime.tm_yday;
   360     }
   361     if(useGMT)
   362     	statictime.tm_isdst = 0;
   363     else
   364     	statictime.tm_isdst = gmt_isdst;
   365     gmt_lastGetDateUseGMT=useGMT; /* hack to make TclpGetTZName below work */
   366     return(&statictime);
   367 }
   368 
   369 /*
   370  *----------------------------------------------------------------------
   371  *
   372  * TclpGetTZName --
   373  *
   374  *	Gets the current timezone string.
   375  *
   376  * Results:
   377  *	Returns a pointer to a static string, or NULL on failure.
   378  *
   379  * Side effects:
   380  *	None.
   381  *
   382  *----------------------------------------------------------------------
   383  */
   384 
   385 char *
   386 TclpGetTZName(int dst)
   387 {
   388     register TABLE *tp;
   389 	long zonevalue=-TclpGetGMTOffset();
   390 		
   391     if (gmt_isdst)
   392         zonevalue += HOUR(1);
   393 
   394 	if(gmt_lastGetDateUseGMT) /* hack: if last TclpGetDate was called */
   395 		zonevalue=0;          /* with useGMT==1 then we're using GMT  */
   396 
   397     for (tp = invTimezoneTable; tp->name; tp++) {
   398         if ((tp->value == zonevalue) && (tp->type == dst)) break;
   399     }
   400 	if(!tp->name)
   401 		tp = invTimezoneTable; /* default to unknown */
   402 
   403     return tp->name;
   404 }
   405 
   406 #ifdef NO_LONG_LONG
   407 /*
   408  *----------------------------------------------------------------------
   409  *
   410  * SubtractUnsignedWide --
   411  *
   412  *	Subtracts one UnsignedWide value from another.
   413  *
   414  * Results:
   415  *  	The subtracted value.
   416  *
   417  * Side effects:
   418  *	None.
   419  *
   420  *----------------------------------------------------------------------
   421  */
   422 
   423 static void
   424 SubtractUnsignedWide(
   425     UnsignedWide *x,		/* Ptr to wide int. */
   426     UnsignedWide *y,		/* Ptr to wide int. */
   427     UnsignedWide *result)	/* Ptr to result. */
   428 {
   429     result->hi = x->hi - y->hi;
   430     if (x->lo < y->lo) {
   431 	result->hi--;
   432     }
   433     result->lo = x->lo - y->lo;
   434 }
   435 #endif