diff options
author | cvs2fossil <cvs2fossil> | 2011-01-25 19:02:56 (GMT) |
---|---|---|
committer | cvs2fossil <cvs2fossil> | 2011-01-25 19:02:56 (GMT) |
commit | 352fce86be9d102b2284de839b7f7ff94ed971f2 (patch) | |
tree | e454e0d4460f15029e4ed5ae3f3131a992445426 /mac/tclMacTime.c | |
parent | 75f084f6970d2344bb5a82fdff6a73825bc6e64e (diff) | |
download | tcl-d17b46e6e2c06a5517e3628d8dd5d9710c745d33.zip tcl-d17b46e6e2c06a5517e3628d8dd5d9710c745d33.tar.gz tcl-d17b46e6e2c06a5517e3628d8dd5d9710c745d33.tar.bz2 |
Created branch dgp-refactor-merge-syntheticdgp_refactor_mergedgp_refactor_merge_synthetic
Diffstat (limited to 'mac/tclMacTime.c')
-rw-r--r-- | mac/tclMacTime.c | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/mac/tclMacTime.c b/mac/tclMacTime.c new file mode 100644 index 0000000..d585ee7 --- /dev/null +++ b/mac/tclMacTime.c @@ -0,0 +1,436 @@ +/* + * tclMacTime.c -- + * + * Contains Macintosh specific versions of Tcl functions that + * obtain time values from the operating system. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tclMacTime.c,v 1.8 2003/05/18 19:48:26 kennykb Exp $ + */ + +#include "tclInt.h" +#include "tclPort.h" +#include "tclMacInt.h" +#include <OSUtils.h> +#include <Timer.h> +#include <time.h> + +/* + * Static variables used by the Tcl_GetTime function. + */ + +static int initalized = false; +static unsigned long baseSeconds; +static UnsignedWide microOffset; + +static int gmt_initialized = false; +static long gmt_offset; +static int gmt_isdst; +TCL_DECLARE_MUTEX(gmtMutex) + +static int gmt_lastGetDateUseGMT = 0; + +typedef struct _TABLE { + char *name; + int type; + time_t value; +} TABLE; + + +#define HOUR(x) ((time_t) (3600 * x)) + +#define tZONE 0 +#define tDAYZONE 1 + + +/* + * inverse timezone table, adapted from tclDate.c by removing duplicates and + * adding some made up names for unusual daylight savings + */ +static TABLE invTimezoneTable[] = { + { "Z", -1, HOUR( 36) }, /* Unknown */ + { "GMT", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "BST", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "WAT", tZONE, HOUR( 1) }, /* West Africa */ + { "WADST", tDAYZONE, HOUR( 1) }, /* West Africa Daylight*/ + { "AT", tZONE, HOUR( 2) }, /* Azores Daylight*/ + { "ADST", tDAYZONE, HOUR( 2) }, /* Azores */ + { "NFT", tZONE, HOUR( 7/2) }, /* Newfoundland */ + { "NDT", tDAYZONE, HOUR( 7/2) }, /* Newfoundland Daylight */ + { "AST", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "ADT", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "EST", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "EDT", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "CST", tZONE, HOUR( 6) }, /* Central Standard */ + { "CDT", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "MST", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "MDT", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "PST", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "PDT", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "YST", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "YDT", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "HST", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "HDT", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ + { "NT", tZONE, HOUR(11) }, /* Nome */ + { "NST", tDAYZONE, HOUR(11) }, /* Nome Daylight*/ + { "IDLW", tZONE, HOUR(12) }, /* International Date Line West */ + { "CET", tZONE, -HOUR( 1) }, /* Central European */ + { "CEST", tDAYZONE, -HOUR( 1) }, /* Central European Summer */ + { "EET", tZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 */ + { "EEST", tDAYZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 Daylight*/ + { "BT", tZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 */ + { "BDST", tDAYZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 Daylight*/ + { "IT", tZONE, -HOUR( 7/2) }, /* Iran */ + { "IDST", tDAYZONE, -HOUR( 7/2) }, /* Iran Daylight*/ + { "ZP4", tZONE, -HOUR( 4) }, /* USSR Zone 3 */ + { "ZP4S", tDAYZONE, -HOUR( 4) }, /* USSR Zone 3 */ + { "ZP5", tZONE, -HOUR( 5) }, /* USSR Zone 4 */ + { "ZP5S", tDAYZONE, -HOUR( 5) }, /* USSR Zone 4 */ + { "IST", tZONE, -HOUR(11/2) }, /* Indian Standard */ + { "ISDST", tDAYZONE, -HOUR(11/2) }, /* Indian Standard */ + { "ZP6", tZONE, -HOUR( 6) }, /* USSR Zone 5 */ + { "ZP6S", tDAYZONE, -HOUR( 6) }, /* USSR Zone 5 */ + { "WAST", tZONE, -HOUR( 7) }, /* West Australian Standard */ + { "WADT", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */ + { "JT", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */ + { "JDST", tDAYZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */ + { "CCT", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */ + { "CCST", tDAYZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */ + { "JST", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */ + { "JSDST", tDAYZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */ + { "CAST", tZONE, -HOUR(19/2) }, /* Central Australian Standard */ + { "CADT", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */ + { "EAST", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "EADT", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "NZT", tZONE, -HOUR(12) }, /* New Zealand */ + { "NZDT", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + { NULL } +}; + +/* + * Prototypes for procedures that are private to this file: + */ + +static void SubtractUnsignedWide _ANSI_ARGS_((UnsignedWide *x, + UnsignedWide *y, UnsignedWide *result)); + +/* + *----------------------------------------------------------------------------- + * + * TclpGetGMTOffset -- + * + * This procedure gets the offset seconds that needs to be _added_ to tcl time + * in seconds (i.e. GMT time) to get local time needed as input to various + * Mac OS APIs, to convert Mac OS API output to tcl time, _subtract_ this value. + * + * Results: + * Number of seconds separating GMT time and mac. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +long +TclpGetGMTOffset() +{ + if (gmt_initialized == false) { + MachineLocation loc; + + Tcl_MutexLock(&gmtMutex); + ReadLocation(&loc); + gmt_offset = loc.u.gmtDelta & 0x00ffffff; + if (gmt_offset & 0x00800000) { + gmt_offset = gmt_offset | 0xff000000; + } + gmt_isdst=(loc.u.dlsDelta < 0); + gmt_initialized = true; + Tcl_MutexUnlock(&gmtMutex); + } + return (gmt_offset); +} + +/* + *----------------------------------------------------------------------------- + * + * TclpGetSeconds -- + * + * This procedure returns the number of seconds from the epoch. On + * the Macintosh the epoch is Midnight Jan 1, 1904. Unfortunatly, + * the Macintosh doesn't tie the epoch to a particular time zone. For + * Tcl we tie the epoch to GMT. This makes the time zone date parsing + * code work. The epoch for Mac-Tcl is: Midnight Jan 1, 1904 GMT. + * + * Results: + * Number of seconds from the epoch in GMT. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +unsigned long +TclpGetSeconds() +{ + unsigned long seconds; + + GetDateTime(&seconds); + return (seconds - TclpGetGMTOffset() + tcl_mac_epoch_offset); +} + +/* + *----------------------------------------------------------------------------- + * + * TclpGetClicks -- + * + * This procedure returns a value that represents the highest resolution + * clock available on the system. There are no garantees on what the + * resolution will be. In Tcl we will call this value a "click". The + * start time is also system dependant. + * + * Results: + * Number of clicks from some start time. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +unsigned long +TclpGetClicks() +{ + UnsignedWide micros; + + Microseconds(µs); + return micros.lo; +} + +/* + *---------------------------------------------------------------------- + * + * TclpGetTimeZone -- + * + * Get the current time zone. + * + * Results: + * The return value is the local time zone, measured in + * minutes away from GMT (-ve for east, +ve for west). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclpGetTimeZone ( + unsigned long currentTime) /* Ignored on Mac. */ +{ + long offset; + + /* + * Convert the Mac offset from seconds to minutes and + * add an hour if we have daylight savings time. + */ + offset = -TclpGetGMTOffset(); + offset /= 60; + if (gmt_isdst) { + offset += 60; + } + + return offset; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_GetTime -- + * + * Gets the current system time in seconds and microseconds + * since the beginning of the epoch: 00:00 UCT, January 1, 1970. + * + * Results: + * Returns the current time (in the local timezone) in timePtr. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_GetTime( + Tcl_Time *timePtr) /* Location to store time information. */ +{ + UnsignedWide micro; +#ifndef NO_LONG_LONG + long long *microPtr; +#endif + + if (initalized == false) { + GetDateTime(&baseSeconds); + /* + * Remove the local offset that ReadDateTime() adds. + */ + baseSeconds -= TclpGetGMTOffset() - tcl_mac_epoch_offset; + Microseconds(µOffset); + initalized = true; + } + + Microseconds(µ); + +#ifndef NO_LONG_LONG + microPtr = (long long *) µ + *microPtr -= *((long long *) µOffset); + timePtr->sec = baseSeconds + (*microPtr / 1000000); + timePtr->usec = *microPtr % 1000000; +#else + SubtractUnsignedWide(µ, µOffset, µ); + + /* + * This lovely computation is equal to: base + (micro / 1000000) + * For the .hi part the ratio of 0x100000000 / 1000000 has been + * reduced to avoid overflow. This computation certainly has + * problems as the .hi part gets large. However, your application + * would have to run for a long time to make that happen. + */ + + timePtr->sec = baseSeconds + (micro.lo / 1000000) + + (long) (micro.hi * ((double) 33554432.0 / 15625.0)); + timePtr->usec = micro.lo % 1000000; +#endif +} + +/* + *---------------------------------------------------------------------- + * + * TclpGetDate -- + * + * Converts raw seconds to a struct tm data structure. The + * returned time will be for Greenwich Mean Time if the useGMT flag + * is set. Otherwise, the returned time will be for the local + * time zone. This function is meant to be used as a replacement + * for localtime and gmtime which is broken on most ANSI libs + * on the Macintosh. + * + * Results: + * None. + * + * Side effects: + * The passed in struct tm data structure is modified. + * + *---------------------------------------------------------------------- + */ + +struct tm * +TclpGetDate( + TclpTime_t time, /* Time struct to fill. */ + int useGMT) /* True if date should reflect GNT time. */ +{ + const time_t *tp = (const time_t *)time; + DateTimeRec dtr; + unsigned long offset=0L; + static struct tm statictime; + static const short monthday[12] = + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + + if(useGMT) + SecondsToDate(*tp - tcl_mac_epoch_offset, &dtr); + else + SecondsToDate(*tp + TclpGetGMTOffset() - tcl_mac_epoch_offset, &dtr); + + statictime.tm_sec = dtr.second; + statictime.tm_min = dtr.minute; + statictime.tm_hour = dtr.hour; + statictime.tm_mday = dtr.day; + statictime.tm_mon = dtr.month - 1; + statictime.tm_year = dtr.year - 1900; + statictime.tm_wday = dtr.dayOfWeek - 1; + statictime.tm_yday = monthday[statictime.tm_mon] + + statictime.tm_mday - 1; + if (1 < statictime.tm_mon && !(statictime.tm_year & 3)) { + ++statictime.tm_yday; + } + if(useGMT) + statictime.tm_isdst = 0; + else + statictime.tm_isdst = gmt_isdst; + gmt_lastGetDateUseGMT=useGMT; /* hack to make TclpGetTZName below work */ + return(&statictime); +} + +/* + *---------------------------------------------------------------------- + * + * TclpGetTZName -- + * + * Gets the current timezone string. + * + * Results: + * Returns a pointer to a static string, or NULL on failure. + * The static string is in UTF-8 encoding. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +TclpGetTZName(int dst) +{ + register TABLE *tp; + long zonevalue=-TclpGetGMTOffset(); + + if (gmt_isdst) + zonevalue += HOUR(1); + + if(gmt_lastGetDateUseGMT) /* hack: if last TclpGetDate was called */ + zonevalue=0; /* with useGMT==1 then we're using GMT */ + + for (tp = invTimezoneTable; tp->name; tp++) { + if ((tp->value == zonevalue) && (tp->type == dst)) break; + } + if(!tp->name) + tp = invTimezoneTable; /* default to unknown */ + + return tp->name; +} + +#ifdef NO_LONG_LONG +/* + *---------------------------------------------------------------------- + * + * SubtractUnsignedWide -- + * + * Subtracts one UnsignedWide value from another. + * + * Results: + * The subtracted value. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +SubtractUnsignedWide( + UnsignedWide *x, /* Ptr to wide int. */ + UnsignedWide *y, /* Ptr to wide int. */ + UnsignedWide *result) /* Ptr to result. */ +{ + result->hi = x->hi - y->hi; + if (x->lo < y->lo) { + result->hi--; + } + result->lo = x->lo - y->lo; +} +#endif |