diff options
Diffstat (limited to 'generic/tclClock.c')
| -rw-r--r-- | generic/tclClock.c | 803 | 
1 files changed, 517 insertions, 286 deletions
| diff --git a/generic/tclClock.c b/generic/tclClock.c index 6a334ad..ac4a4d6 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -7,12 +7,10 @@   *   * Copyright 1991-1995 Karl Lehenbauer and Mark Diekhans.   * Copyright (c) 1995 Sun Microsystems, Inc. - * Copyright (c) 2004 by Kevin B. Kenny.  All rights reserved. + * Copyright (c) 2004 by Kevin B. Kenny. All rights reserved.   *   * See the file "license.terms" for information on usage and redistribution of   * this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclClock.c,v 1.51 2006/02/01 23:34:38 dkf Exp $   */  #include "tclInt.h" @@ -21,7 +19,7 @@   * Windows has mktime. The configurators do not check.   */ -#ifdef __WIN32__ +#ifdef _WIN32  #define HAVE_MKTIME 1  #endif @@ -33,12 +31,12 @@  #define SECONDS_PER_DAY			86400  #define JULIAN_SEC_POSIX_EPOCH	      (((Tcl_WideInt) JULIAN_DAY_POSIX_EPOCH) \  					* SECONDS_PER_DAY) -#define FOUR_CENTURIES			146097 /* days */ +#define FOUR_CENTURIES			146097	/* days */  #define JDAY_1_JAN_1_CE_JULIAN		1721424  #define JDAY_1_JAN_1_CE_GREGORIAN	1721426 -#define ONE_CENTURY_GREGORIAN		36524  /* days */ -#define FOUR_YEARS			1461   /* days */ -#define ONE_YEAR			365    /* days */ +#define ONE_CENTURY_GREGORIAN		36524	/* days */ +#define FOUR_YEARS			1461	/* days */ +#define ONE_YEAR			365	/* days */  /*   * Table of the days in each month, leap and common years @@ -58,9 +56,14 @@ static const int daysInPriorMonths[2][13] = {   */  typedef enum ClockLiteral { -    LIT_BCE,		LIT_CE, +    LIT__NIL, +    LIT__DEFAULT_FORMAT, +    LIT_BCE,		LIT_C, +    LIT_CANNOT_USE_GMT_AND_TIMEZONE, +    LIT_CE,      LIT_DAYOFMONTH,	LIT_DAYOFWEEK,		LIT_DAYOFYEAR, -    LIT_ERA,		LIT_GREGORIAN, +    LIT_ERA,		LIT_GMT,		LIT_GREGORIAN, +    LIT_INTEGER_VALUE_TOO_LARGE,      LIT_ISO8601WEEK,	LIT_ISO8601YEAR,      LIT_JULIANDAY,	LIT_LOCALSECONDS,      LIT_MONTH, @@ -69,9 +72,14 @@ typedef enum ClockLiteral {      LIT__END  } ClockLiteral;  static const char *const literals[] = { -    "BCE",		"CE", +    "", +    "%a %b %d %H:%M:%S %Z %Y", +    "BCE",		"C", +    "cannot use -gmt and -timezone in same call", +    "CE",      "dayOfMonth",	"dayOfWeek",		"dayOfYear", -    "era",		"gregorian", +    "era",		":GMT",			"gregorian", +    "integer value too large to represent",      "iso8601Week",	"iso8601Year",      "julianDay",	"localSeconds",      "month", @@ -84,8 +92,8 @@ static const char *const literals[] = {   */  typedef struct ClockClientData { -    int refCount;		/* Number of live references */ -    Tcl_Obj** literals;		/* Pool of object literals */ +    size_t refCount;		/* Number of live references. */ +    Tcl_Obj **literals;		/* Pool of object literals. */  } ClockClientData;  /* @@ -99,7 +107,7 @@ typedef struct TclDateFields {  				 * from the Posix epoch */      int tzOffset;		/* Time zone offset in seconds east of  				 * Greenwich */ -    Tcl_Obj* tzName;		/* Time zone name */ +    Tcl_Obj *tzName;		/* Time zone name */      int julianDay;		/* Julian Day Number in local time zone */      enum {BCE=1, CE=0} era;	/* Era */      int gregorian;		/* Flag == 1 if the date is Gregorian */ @@ -111,7 +119,7 @@ typedef struct TclDateFields {      int iso8601Week;		/* ISO8601 week number */      int dayOfWeek;		/* Day of the week */  } TclDateFields; -static CONST char* eras[] = { "CE", "BCE", NULL }; +static const char *const eras[] = { "CE", "BCE", NULL };  /*   * Thread specific data block holding a 'struct tm' for the 'gmtime' and @@ -131,58 +139,86 @@ TCL_DECLARE_MUTEX(clockMutex)   * Function prototypes for local procedures in this file:   */ -static int		ConvertUTCToLocal(Tcl_Interp*, -			    TclDateFields*, Tcl_Obj*, int); -static int		ConvertUTCToLocalUsingTable(Tcl_Interp*, -			    TclDateFields*, int, Tcl_Obj *CONST[]); -static int		ConvertUTCToLocalUsingC(Tcl_Interp*, -			    TclDateFields*, int); -static int		ConvertLocalToUTC(Tcl_Interp*, -			    TclDateFields*, Tcl_Obj*, int); -static int		ConvertLocalToUTCUsingTable(Tcl_Interp*, -			    TclDateFields*, int, Tcl_Obj *CONST[]); -static int		ConvertLocalToUTCUsingC(Tcl_Interp*, -			    TclDateFields*, int); -static Tcl_Obj*		LookupLastTransition(Tcl_Interp*, Tcl_WideInt, -			    int, Tcl_Obj *CONST *); -static void		GetYearWeekDay(TclDateFields*, int); -static void		GetGregorianEraYearDay(TclDateFields*, int); -static void		GetMonthDay(TclDateFields*); -static void		GetJulianDayFromEraYearWeekDay(TclDateFields*, int); -static void		GetJulianDayFromEraYearMonthDay(TclDateFields*, int); -static int		IsGregorianLeapYear(TclDateFields*); +static int		ConvertUTCToLocal(Tcl_Interp *, +			    TclDateFields *, Tcl_Obj *, int); +static int		ConvertUTCToLocalUsingTable(Tcl_Interp *, +			    TclDateFields *, int, Tcl_Obj *const[]); +static int		ConvertUTCToLocalUsingC(Tcl_Interp *, +			    TclDateFields *, int); +static int		ConvertLocalToUTC(Tcl_Interp *, +			    TclDateFields *, Tcl_Obj *, int); +static int		ConvertLocalToUTCUsingTable(Tcl_Interp *, +			    TclDateFields *, int, Tcl_Obj *const[]); +static int		ConvertLocalToUTCUsingC(Tcl_Interp *, +			    TclDateFields *, int); +static Tcl_Obj *	LookupLastTransition(Tcl_Interp *, Tcl_WideInt, +			    int, Tcl_Obj *const *); +static void		GetYearWeekDay(TclDateFields *, int); +static void		GetGregorianEraYearDay(TclDateFields *, int); +static void		GetMonthDay(TclDateFields *); +static void		GetJulianDayFromEraYearWeekDay(TclDateFields *, int); +static void		GetJulianDayFromEraYearMonthDay(TclDateFields *, int); +static int		IsGregorianLeapYear(TclDateFields *);  static int		WeekdayOnOrBefore(int, int);  static int		ClockClicksObjCmd(  			    ClientData clientData, Tcl_Interp *interp, -			    int objc, Tcl_Obj *CONST objv[]); +			    int objc, Tcl_Obj *const objv[]);  static int		ClockConvertlocaltoutcObjCmd(  			    ClientData clientData, Tcl_Interp *interp, -			    int objc, Tcl_Obj *CONST objv[]); +			    int objc, Tcl_Obj *const objv[]);  static int		ClockGetdatefieldsObjCmd(  			    ClientData clientData, Tcl_Interp *interp, -			    int objc, Tcl_Obj *CONST objv[]); +			    int objc, Tcl_Obj *const objv[]);  static int		ClockGetjuliandayfromerayearmonthdayObjCmd(  			    ClientData clientData, Tcl_Interp *interp, -			    int objc, Tcl_Obj *CONST objv[]); +			    int objc, Tcl_Obj *const objv[]);  static int		ClockGetjuliandayfromerayearweekdayObjCmd(  			    ClientData clientData, Tcl_Interp *interp, -			    int objc, Tcl_Obj *CONST objv[]); +			    int objc, Tcl_Obj *const objv[]);  static int		ClockGetenvObjCmd(  			    ClientData clientData, Tcl_Interp *interp, -			    int objc, Tcl_Obj *CONST objv[]); +			    int objc, Tcl_Obj *const objv[]);  static int		ClockMicrosecondsObjCmd(  			    ClientData clientData, Tcl_Interp *interp, -			    int objc, Tcl_Obj *CONST objv[]); +			    int objc, Tcl_Obj *const objv[]);  static int		ClockMillisecondsObjCmd(  			    ClientData clientData, Tcl_Interp *interp, -			    int objc, Tcl_Obj *CONST objv[]); +			    int objc, Tcl_Obj *const objv[]); +static int		ClockParseformatargsObjCmd( +			    ClientData clientData, Tcl_Interp *interp, +			    int objc, Tcl_Obj *const objv[]);  static int		ClockSecondsObjCmd(  			    ClientData clientData, Tcl_Interp *interp, -			    int objc, Tcl_Obj *CONST objv[]); -static struct tm *	ThreadSafeLocalTime(CONST time_t *); +			    int objc, Tcl_Obj *const objv[]); +static struct tm *	ThreadSafeLocalTime(const time_t *);  static void		TzsetIfNecessary(void);  static void		ClockDeleteCmdProc(ClientData); +/* + * Structure containing description of "native" clock commands to create. + */ + +struct ClockCommand { +    const char *name;		/* The tail of the command name. The full name +				 * is "::tcl::clock::<name>". When NULL marks +				 * the end of the table. */ +    Tcl_ObjCmdProc *objCmdProc;	/* Function that implements the command. This +				 * will always have the ClockClientData sent +				 * to it, but may well ignore this data. */ +}; + +static const struct ClockCommand clockCommands[] = { +    { "getenv",			ClockGetenvObjCmd }, +    { "Oldscan",		TclClockOldscanObjCmd }, +    { "ConvertLocalToUTC",	ClockConvertlocaltoutcObjCmd }, +    { "GetDateFields",		ClockGetdatefieldsObjCmd }, +    { "GetJulianDayFromEraYearMonthDay", +		ClockGetjuliandayfromerayearmonthdayObjCmd }, +    { "GetJulianDayFromEraYearWeekDay", +		ClockGetjuliandayfromerayearweekdayObjCmd }, +    { "ParseFormatArgs",	ClockParseformatargsObjCmd }, +    { NULL, NULL } +};  /*   *---------------------------------------------------------------------- @@ -204,23 +240,44 @@ static void		ClockDeleteCmdProc(ClientData);  void  TclClockInit( -    Tcl_Interp* interp		/* Tcl interpreter */ -) { +    Tcl_Interp *interp)		/* Tcl interpreter */ +{ +    const struct ClockCommand *clockCmdPtr; +    char cmdName[50];		/* Buffer large enough to hold the string +				 *::tcl::clock::GetJulianDayFromEraYearMonthDay +				 * plus a terminating NUL. */ +    ClockClientData *data;      int i; +    /* Structure of the 'clock' ensemble */ + +    static const EnsembleImplMap clockImplMap[] = { +	{"add",          NULL,                    TclCompileBasicMin1ArgCmd, NULL, NULL,       0}, +	{"clicks",       ClockClicksObjCmd,       TclCompileClockClicksCmd,  NULL, NULL,       0}, +	{"format",       NULL,                    TclCompileBasicMin1ArgCmd, NULL, NULL,       0}, +	{"microseconds", ClockMicrosecondsObjCmd, TclCompileClockReadingCmd, NULL, INT2PTR(1), 0}, +	{"milliseconds", ClockMillisecondsObjCmd, TclCompileClockReadingCmd, NULL, INT2PTR(2), 0}, +	{"scan",         NULL,                    TclCompileBasicMin1ArgCmd, NULL, NULL      , 0}, +	{"seconds",      ClockSecondsObjCmd,      TclCompileClockReadingCmd, NULL, INT2PTR(3), 0}, +	{NULL,           NULL,                    NULL,                      NULL, NULL,       0} +    }; +      /* -     * Create the client data. +     * Safe interps get [::clock] as alias to a master, so do not need their +     * own copies of the support routines.       */ -    ClockClientData *data = -	(ClockClientData*) ckalloc(sizeof(ClockClientData)); -    data->refCount = 0; +    if (Tcl_IsSafe(interp)) { +	return; +    }      /* -     * Create the literal pool. +     * Create the client data, which is a refcounted literal pool.       */ -    data->literals = (Tcl_Obj**) ckalloc(LIT__END * sizeof(Tcl_Obj*)); +    data = ckalloc(sizeof(ClockClientData)); +    data->refCount = 0; +    data->literals = ckalloc(LIT__END * sizeof(Tcl_Obj*));      for (i = 0; i < LIT__END; ++i) {  	data->literals[i] = Tcl_NewStringObj(literals[i], -1);  	Tcl_IncrRefCount(data->literals[i]); @@ -228,38 +285,21 @@ TclClockInit(      /*       * Install the commands. +     * TODO - Let Tcl_MakeEnsemble do this?       */ -    Tcl_CreateObjCommand(interp,	"::tcl::clock::clicks", -	    ClockClicksObjCmd,	(ClientData) NULL, NULL); -    Tcl_CreateObjCommand(interp,	"::tcl::clock::getenv", -	    ClockGetenvObjCmd,	(ClientData) NULL, NULL); -    Tcl_CreateObjCommand(interp,	"::tcl::clock::microseconds", -	    ClockMicrosecondsObjCmd,	(ClientData) NULL, NULL); -    Tcl_CreateObjCommand(interp,	"::tcl::clock::milliseconds", -	    ClockMillisecondsObjCmd,	(ClientData) NULL, NULL); -    Tcl_CreateObjCommand(interp,	"::tcl::clock::seconds", -	    ClockSecondsObjCmd,	(ClientData) NULL, NULL); -    Tcl_CreateObjCommand(interp,	"::tcl::clock::Oldscan", -	    TclClockOldscanObjCmd,	(ClientData) NULL, NULL); -    Tcl_CreateObjCommand(interp,	"::tcl::clock::ConvertLocalToUTC", -	    ClockConvertlocaltoutcObjCmd, (ClientData) data, -	    ClockDeleteCmdProc); -    ++data->refCount; -    Tcl_CreateObjCommand(interp,	"::tcl::clock::GetDateFields", -	    ClockGetdatefieldsObjCmd,(ClientData) data, -	    ClockDeleteCmdProc); -    ++data->refCount; -    Tcl_CreateObjCommand(interp, -	    "::tcl::clock::GetJulianDayFromEraYearMonthDay", -	    ClockGetjuliandayfromerayearmonthdayObjCmd,(ClientData) data, -	    ClockDeleteCmdProc); -    ++data->refCount; -    Tcl_CreateObjCommand(interp, -	    "::tcl::clock::GetJulianDayFromEraYearWeekDay", -	    ClockGetjuliandayfromerayearweekdayObjCmd,(ClientData) data, -	    ClockDeleteCmdProc); -    ++data->refCount; +#define TCL_CLOCK_PREFIX_LEN 14 /* == strlen("::tcl::clock::") */ +    memcpy(cmdName, "::tcl::clock::", TCL_CLOCK_PREFIX_LEN); +    for (clockCmdPtr=clockCommands ; clockCmdPtr->name!=NULL ; clockCmdPtr++) { +	strcpy(cmdName + TCL_CLOCK_PREFIX_LEN, clockCmdPtr->name); +	data->refCount++; +	Tcl_CreateObjCommand(interp, cmdName, clockCmdPtr->objCmdProc, data, +		ClockDeleteCmdProc); +    } + +    /* Make the clock ensemble */ + +    TclMakeEnsemble(interp, "clock", clockImplMap);  }  /* @@ -291,15 +331,15 @@ TclClockInit(  static int  ClockConvertlocaltoutcObjCmd( -    ClientData clientData,	/* Client data  */ -    Tcl_Interp* interp,		/* Tcl interpreter */ +    ClientData clientData,	/* Client data */ +    Tcl_Interp *interp,		/* Tcl interpreter */      int objc,			/* Parameter count */ -    Tcl_Obj *CONST * objv	/* Parameter vector */ -) { -    ClockClientData* data = (ClockClientData*) clientData; -    Tcl_Obj* CONST * literals = data->literals; -    Tcl_Obj* secondsObj; -    Tcl_Obj* dict; +    Tcl_Obj *const *objv)	/* Parameter vector */ +{ +    ClockClientData *data = clientData; +    Tcl_Obj *const *literals = data->literals; +    Tcl_Obj *secondsObj; +    Tcl_Obj *dict;      int changeover;      TclDateFields fields;      int created = 0; @@ -314,12 +354,19 @@ ClockConvertlocaltoutcObjCmd(  	return TCL_ERROR;      }      dict = objv[1]; -    if ((Tcl_DictObjGet(interp, dict, literals[LIT_LOCALSECONDS], -		&secondsObj) != TCL_OK) -	    || (Tcl_GetWideIntFromObj(interp, secondsObj, -		&(fields.localSeconds)) != TCL_OK) -	    || (Tcl_GetIntFromObj(interp, objv[3], &changeover) != TCL_OK) -	    || ConvertLocalToUTC(interp, &fields, objv[2], changeover)) { +    if (Tcl_DictObjGet(interp, dict, literals[LIT_LOCALSECONDS], +	    &secondsObj)!= TCL_OK) { +	return TCL_ERROR; +    } +    if (secondsObj == NULL) { +	Tcl_SetObjResult(interp, Tcl_NewStringObj("key \"localseconds\" not " +		"found in dictionary", -1)); +	return TCL_ERROR; +    } +    if ((Tcl_GetWideIntFromObj(interp, secondsObj, +	    &fields.localSeconds) != TCL_OK) +	|| (TclGetIntFromObj(interp, objv[3], &changeover) != TCL_OK) +	|| ConvertLocalToUTC(interp, &fields, objv[2], changeover)) {  	return TCL_ERROR;      } @@ -357,16 +404,16 @@ ClockConvertlocaltoutcObjCmd(   *   * Parameters:   *	seconds - Time expressed in seconds from the Posix epoch. - *	tzdata - Time zone data of the time zone in which time is to - *                 be expressed. + *	tzdata - Time zone data of the time zone in which time is to be + *		 expressed.   *	changeover - Julian Day Number at which the current locale adopted   *		     the Gregorian calendar   *   * Results:   *	Returns a dictonary populated with the fields:   *		seconds - Seconds from the Posix epoch - *		localSeconds - Nominal seconds from the Posix epoch in - *			       the local time zone. + *		localSeconds - Nominal seconds from the Posix epoch in the + *			       local time zone.   *		tzOffset - Time zone offset in seconds east of Greenwich   *		tzName - Time zone name   *		julianDay - Julian Day Number in the local time zone @@ -377,14 +424,14 @@ ClockConvertlocaltoutcObjCmd(  int  ClockGetdatefieldsObjCmd(      ClientData clientData,	/* Opaque pointer to literal pool, etc. */ -    Tcl_Interp* interp,		/* Tcl interpreter */ +    Tcl_Interp *interp,		/* Tcl interpreter */      int objc,			/* Parameter count */ -    Tcl_Obj *CONST *objv	/* Parameter vector */ -) { +    Tcl_Obj *const *objv)	/* Parameter vector */ +{      TclDateFields fields; -    Tcl_Obj* dict; -    ClockClientData* data = (ClockClientData*) clientData; -    Tcl_Obj* CONST * literals = data->literals; +    Tcl_Obj *dict; +    ClockClientData *data = clientData; +    Tcl_Obj *const *literals = data->literals;      int changeover;      /* @@ -395,8 +442,18 @@ ClockGetdatefieldsObjCmd(  	Tcl_WrongNumArgs(interp, 1, objv, "seconds tzdata changeover");  	return TCL_ERROR;      } -    if (Tcl_GetWideIntFromObj(interp, objv[1], &(fields.seconds)) != TCL_OK -	    || Tcl_GetIntFromObj(interp, objv[3], &changeover) != TCL_OK) { +    if (Tcl_GetWideIntFromObj(interp, objv[1], &fields.seconds) != TCL_OK +	    || TclGetIntFromObj(interp, objv[3], &changeover) != TCL_OK) { +	return TCL_ERROR; +    } + +    /* +     * fields.seconds could be an unsigned number that overflowed. Make sure +     * that it isn't. +     */ + +    if (objv[1]->typePtr == &tclBignumType) { +	Tcl_SetObjResult(interp, literals[LIT_INTEGER_VALUE_TOO_LARGE]);  	return TCL_ERROR;      } @@ -479,17 +536,56 @@ ClockGetdatefieldsObjCmd(   */  static int -ClockGetjuliandayfromerayearmonthdayObjCmd ( +FetchEraField( +    Tcl_Interp *interp, +    Tcl_Obj *dict, +    Tcl_Obj *key, +    int *storePtr) +{ +    Tcl_Obj *value = NULL; + +    if (Tcl_DictObjGet(interp, dict, key, &value) != TCL_OK) { +	return TCL_ERROR; +    } +    if (value == NULL) { +	Tcl_SetObjResult(interp, Tcl_NewStringObj( +		"expected key(s) not found in dictionary", -1)); +	return TCL_ERROR; +    } +    return Tcl_GetIndexFromObj(interp, value, eras, "era", TCL_EXACT, storePtr); +} + +static int +FetchIntField( +    Tcl_Interp *interp, +    Tcl_Obj *dict, +    Tcl_Obj *key, +    int *storePtr) +{ +    Tcl_Obj *value = NULL; + +    if (Tcl_DictObjGet(interp, dict, key, &value) != TCL_OK) { +	return TCL_ERROR; +    } +    if (value == NULL) { +	Tcl_SetObjResult(interp, Tcl_NewStringObj( +		"expected key(s) not found in dictionary", -1)); +	return TCL_ERROR; +    } +    return TclGetIntFromObj(interp, value, storePtr); +} + +static int +ClockGetjuliandayfromerayearmonthdayObjCmd(      ClientData clientData,	/* Opaque pointer to literal pool, etc. */ -    Tcl_Interp* interp,		/* Tcl interpreter */ +    Tcl_Interp *interp,		/* Tcl interpreter */      int objc,			/* Parameter count */ -    Tcl_Obj *CONST *objv	/* Parameter vector */ -) { +    Tcl_Obj *const *objv)	/* Parameter vector */ +{      TclDateFields fields; -    Tcl_Obj* dict; -    ClockClientData* data = (ClockClientData*) clientData; -    Tcl_Obj* CONST * literals = data->literals; -    Tcl_Obj* fieldPtr; +    Tcl_Obj *dict; +    ClockClientData *data = clientData; +    Tcl_Obj *const *literals = data->literals;      int changeover;      int copied = 0;      int status; @@ -504,20 +600,14 @@ ClockGetjuliandayfromerayearmonthdayObjCmd (  	return TCL_ERROR;      }      dict = objv[1]; -    if (Tcl_DictObjGet(interp, dict, literals[LIT_ERA], &fieldPtr) != TCL_OK -	    || Tcl_GetIndexFromObj(interp, fieldPtr, eras, "era", TCL_EXACT, -		&era) != TCL_OK -	    || Tcl_DictObjGet(interp, dict, literals[LIT_YEAR], -		&fieldPtr) != TCL_OK -	    || Tcl_GetIntFromObj(interp, fieldPtr, &(fields.year)) != TCL_OK -	    || Tcl_DictObjGet(interp, dict, literals[LIT_MONTH], -		&fieldPtr) != TCL_OK -	    || Tcl_GetIntFromObj(interp, fieldPtr, &(fields.month)) != TCL_OK -	    || Tcl_DictObjGet(interp, dict, literals[LIT_DAYOFMONTH], -		&fieldPtr) != TCL_OK -	    || Tcl_GetIntFromObj(interp, fieldPtr, -		&(fields.dayOfMonth)) != TCL_OK -	    || Tcl_GetIntFromObj(interp, objv[2], &changeover) != TCL_OK) { +    if (FetchEraField(interp, dict, literals[LIT_ERA], &era) != TCL_OK +	    || FetchIntField(interp, dict, literals[LIT_YEAR], &fields.year) +		!= TCL_OK +	    || FetchIntField(interp, dict, literals[LIT_MONTH], &fields.month) +		!= TCL_OK +	    || FetchIntField(interp, dict, literals[LIT_DAYOFMONTH], +		&fields.dayOfMonth) != TCL_OK +	    || TclGetIntFromObj(interp, objv[2], &changeover) != TCL_OK) {  	return TCL_ERROR;      }      fields.era = era; @@ -570,17 +660,16 @@ ClockGetjuliandayfromerayearmonthdayObjCmd (   */  static int -ClockGetjuliandayfromerayearweekdayObjCmd ( +ClockGetjuliandayfromerayearweekdayObjCmd(      ClientData clientData,	/* Opaque pointer to literal pool, etc. */ -    Tcl_Interp* interp,		/* Tcl interpreter */ +    Tcl_Interp *interp,		/* Tcl interpreter */      int objc,			/* Parameter count */ -    Tcl_Obj *CONST *objv	/* Parameter vector */ -) { +    Tcl_Obj *const *objv)	/* Parameter vector */ +{      TclDateFields fields; -    Tcl_Obj* dict; -    ClockClientData* data = (ClockClientData*) clientData; -    Tcl_Obj* CONST * literals = data->literals; -    Tcl_Obj* fieldPtr; +    Tcl_Obj *dict; +    ClockClientData *data = clientData; +    Tcl_Obj *const *literals = data->literals;      int changeover;      int copied = 0;      int status; @@ -595,22 +684,14 @@ ClockGetjuliandayfromerayearweekdayObjCmd (  	return TCL_ERROR;      }      dict = objv[1]; -    if (Tcl_DictObjGet(interp, dict, literals[LIT_ERA], &fieldPtr) != TCL_OK -	    || Tcl_GetIndexFromObj(interp, fieldPtr, eras, "era", TCL_EXACT, -		&era) != TCL_OK -	    || Tcl_DictObjGet(interp, dict, literals[LIT_ISO8601YEAR], -		&fieldPtr) != TCL_OK -	    || Tcl_GetIntFromObj(interp, fieldPtr, -		&(fields.iso8601Year)) != TCL_OK -	    || Tcl_DictObjGet(interp, dict, literals[LIT_ISO8601WEEK], -		&fieldPtr) != TCL_OK -	    || Tcl_GetIntFromObj(interp, fieldPtr, -		&(fields.iso8601Week)) != TCL_OK -	    || Tcl_DictObjGet(interp, dict, literals[LIT_DAYOFWEEK], -		&fieldPtr) != TCL_OK -	    || Tcl_GetIntFromObj(interp, fieldPtr, -		&(fields.dayOfWeek)) != TCL_OK -	    || Tcl_GetIntFromObj(interp, objv[2], &changeover) != TCL_OK) { +    if (FetchEraField(interp, dict, literals[LIT_ERA], &era) != TCL_OK +	    || FetchIntField(interp, dict, literals[LIT_ISO8601YEAR], +		&fields.iso8601Year) != TCL_OK +	    || FetchIntField(interp, dict, literals[LIT_ISO8601WEEK], +		&fields.iso8601Week) != TCL_OK +	    || FetchIntField(interp, dict, literals[LIT_DAYOFWEEK], +		&fields.dayOfWeek) != TCL_OK +	    || TclGetIntFromObj(interp, objv[2], &changeover) != TCL_OK) {  	return TCL_ERROR;      }      fields.era = era; @@ -661,19 +742,19 @@ ClockGetjuliandayfromerayearweekdayObjCmd (  static int  ConvertLocalToUTC( -    Tcl_Interp* interp,		/* Tcl interpreter */ -    TclDateFields* fields,	/* Fields of the time */ -    Tcl_Obj* tzdata,		/* Time zone data */ -    int changeover		/* Julian Day of the Gregorian transition */ -) { +    Tcl_Interp *interp,		/* Tcl interpreter */ +    TclDateFields *fields,	/* Fields of the time */ +    Tcl_Obj *tzdata,		/* Time zone data */ +    int changeover)		/* Julian Day of the Gregorian transition */ +{      int rowc;			/* Number of rows in tzdata */ -    Tcl_Obj** rowv;		/* Pointers to the rows */ +    Tcl_Obj **rowv;		/* Pointers to the rows */      /*       * Unpack the tz data.       */ -    if (Tcl_ListObjGetElements(interp, tzdata, &rowc, &rowv) != TCL_OK) { +    if (TclListObjGetElements(interp, tzdata, &rowc, &rowv) != TCL_OK) {  	return TCL_ERROR;      } @@ -709,14 +790,14 @@ ConvertLocalToUTC(  static int  ConvertLocalToUTCUsingTable( -    Tcl_Interp* interp,		/* Tcl interpreter */ -    TclDateFields* fields,	/* Time to convert, with 'seconds' filled in */ +    Tcl_Interp *interp,		/* Tcl interpreter */ +    TclDateFields *fields,	/* Time to convert, with 'seconds' filled in */      int rowc,			/* Number of points at which time changes */ -    Tcl_Obj *CONST rowv[]	/* Points at which time changes */ -) { -    Tcl_Obj* row; +    Tcl_Obj *const rowv[])	/* Points at which time changes */ +{ +    Tcl_Obj *row;      int cellc; -    Tcl_Obj** cellv; +    Tcl_Obj **cellv;      int have[8];      int nHave = 0;      int i; @@ -738,10 +819,10 @@ ConvertLocalToUTCUsingTable(      while (!found) {  	row = LookupLastTransition(interp, fields->seconds, rowc, rowv);  	if ((row == NULL) -		|| Tcl_ListObjGetElements(interp, row, &cellc, +		|| TclListObjGetElements(interp, row, &cellc,  		    &cellv) != TCL_OK -		|| Tcl_GetIntFromObj(interp, cellv[1], -		    &(fields->tzOffset)) != TCL_OK) { +		|| TclGetIntFromObj(interp, cellv[1], +		    &fields->tzOffset) != TCL_OK) {  	    return TCL_ERROR;  	}  	found = 0; @@ -755,8 +836,7 @@ ConvertLocalToUTCUsingTable(  	    if (nHave == 8) {  		Tcl_Panic("loop in ConvertLocalToUTCUsingTable");  	    } -	    have[nHave] = fields->tzOffset; -	    ++nHave; +	    have[nHave++] = fields->tzOffset;  	}  	fields->seconds = fields->localSeconds - fields->tzOffset;      } @@ -785,20 +865,26 @@ ConvertLocalToUTCUsingTable(  static int  ConvertLocalToUTCUsingC( -    Tcl_Interp* interp,		/* Tcl interpreter */ -    TclDateFields* fields,	/* Time to convert, with 'seconds' filled in */ -    int changeover		/* Julian Day of the Gregorian transition */ -) { +    Tcl_Interp *interp,		/* Tcl interpreter */ +    TclDateFields *fields,	/* Time to convert, with 'seconds' filled in */ +    int changeover)		/* Julian Day of the Gregorian transition */ +{      struct tm timeVal;      int localErrno;      int secondOfDay; +    Tcl_WideInt jsec;      /*       * Convert the given time to a date.       */ -    fields->julianDay = (int) ((fields->localSeconds + JULIAN_SEC_POSIX_EPOCH) -	    / SECONDS_PER_DAY); +    jsec = fields->localSeconds + JULIAN_SEC_POSIX_EPOCH; +    fields->julianDay = (int) (jsec / SECONDS_PER_DAY); +    secondOfDay = (int)(jsec % SECONDS_PER_DAY); +    if (secondOfDay < 0) { +	secondOfDay += SECONDS_PER_DAY; +	fields->julianDay--; +    }      GetGregorianEraYearDay(fields, changeover);      GetMonthDay(fields); @@ -809,10 +895,6 @@ ConvertLocalToUTCUsingC(      timeVal.tm_year = fields->year - 1900;      timeVal.tm_mon = fields->month - 1;      timeVal.tm_mday = fields->dayOfMonth; -    secondOfDay = (int)(fields->localSeconds % SECONDS_PER_DAY); -    if (secondOfDay < 0) { -	secondOfDay += SECONDS_PER_DAY; -    }      timeVal.tm_hour = (secondOfDay / 3600) % 24;      timeVal.tm_min = (secondOfDay / 60) % 60;      timeVal.tm_sec = secondOfDay % 60; @@ -838,9 +920,8 @@ ConvertLocalToUTCUsingC(      if (localErrno != 0  	    || (fields->seconds == -1 && timeVal.tm_yday == -1)) { -	Tcl_SetObjResult(interp, -		Tcl_NewStringObj("time value too large/small to represent", -		-1)); +	Tcl_SetObjResult(interp, Tcl_NewStringObj( +		"time value too large/small to represent", -1));  	return TCL_ERROR;      }      return TCL_OK; @@ -864,19 +945,19 @@ ConvertLocalToUTCUsingC(  static int  ConvertUTCToLocal( -    Tcl_Interp* interp,		/* Tcl interpreter */ -    TclDateFields* fields,	/* Fields of the time */ -    Tcl_Obj* tzdata,		/* Time zone data */ -    int changeover		/* Julian Day of the Gregorian transition */ -) { +    Tcl_Interp *interp,		/* Tcl interpreter */ +    TclDateFields *fields,	/* Fields of the time */ +    Tcl_Obj *tzdata,		/* Time zone data */ +    int changeover)		/* Julian Day of the Gregorian transition */ +{      int rowc;			/* Number of rows in tzdata */ -    Tcl_Obj** rowv;		/* Pointers to the rows */ +    Tcl_Obj **rowv;		/* Pointers to the rows */      /*       * Unpack the tz data.       */ -    if (Tcl_ListObjGetElements(interp, tzdata, &rowc, &rowv) != TCL_OK) { +    if (TclListObjGetElements(interp, tzdata, &rowc, &rowv) != TCL_OK) {  	return TCL_ERROR;      } @@ -912,15 +993,15 @@ ConvertUTCToLocal(  static int  ConvertUTCToLocalUsingTable( -    Tcl_Interp* interp,		/* Tcl interpreter */ -    TclDateFields* fields,	/* Fields of the date */ +    Tcl_Interp *interp,		/* Tcl interpreter */ +    TclDateFields *fields,	/* Fields of the date */      int rowc,			/* Number of rows in the conversion table  				 * (>= 1) */ -    Tcl_Obj *CONST rowv[]	/* Rows of the conversion table */ -) { -    Tcl_Obj* row;		/* Row containing the current information */ +    Tcl_Obj *const rowv[])	/* Rows of the conversion table */ +{ +    Tcl_Obj *row;		/* Row containing the current information */      int cellc;			/* Count of cells in the row (must be 4) */ -    Tcl_Obj** cellv;		/* Pointers to the cells */ +    Tcl_Obj **cellv;		/* Pointers to the cells */      /*       * Look up the nearest transition time. @@ -928,8 +1009,8 @@ ConvertUTCToLocalUsingTable(      row = LookupLastTransition(interp, fields->seconds, rowc, rowv);      if (row == NULL || -	    Tcl_ListObjGetElements(interp, row, &cellc, &cellv) != TCL_OK || -	    Tcl_GetIntFromObj(interp,cellv[1],&(fields->tzOffset)) != TCL_OK) { +	    TclListObjGetElements(interp, row, &cellc, &cellv) != TCL_OK || +	    TclGetIntFromObj(interp, cellv[1], &fields->tzOffset) != TCL_OK) {  	return TCL_ERROR;      } @@ -964,12 +1045,12 @@ ConvertUTCToLocalUsingTable(  static int  ConvertUTCToLocalUsingC( -    Tcl_Interp* interp,		/* Tcl interpreter */ -    TclDateFields* fields,	/* Time to convert, with 'seconds' filled in */ -    int changeover		/* Julian Day of the Gregorian transition */ -) { +    Tcl_Interp *interp,		/* Tcl interpreter */ +    TclDateFields *fields,	/* Time to convert, with 'seconds' filled in */ +    int changeover)		/* Julian Day of the Gregorian transition */ +{      time_t tock; -    struct tm* timeVal;		/* Time after conversion */ +    struct tm *timeVal;		/* Time after conversion */      int diff;			/* Time zone diff local-Greenwich */      char buffer[8];		/* Buffer for time zone name */ @@ -979,17 +1060,17 @@ ConvertUTCToLocalUsingC(      tock = (time_t) fields->seconds;      if ((Tcl_WideInt) tock != fields->seconds) { -	Tcl_AppendResult(interp, -		"number too large to represent as a Posix time", NULL); +	Tcl_SetObjResult(interp, Tcl_NewStringObj( +		"number too large to represent as a Posix time", -1));  	Tcl_SetErrorCode(interp, "CLOCK", "argTooLarge", NULL);  	return TCL_ERROR;      }      TzsetIfNecessary();      timeVal = ThreadSafeLocalTime(&tock);      if (timeVal == NULL) { -	Tcl_AppendResult(interp, -		"localtime failed (clock value may be too ", -		"large/small to represent)", NULL); +	Tcl_SetObjResult(interp, Tcl_NewStringObj( +		"localtime failed (clock value may be too " +		"large/small to represent)", -1));  	Tcl_SetErrorCode(interp, "CLOCK", "localtimeFailed", NULL);  	return TCL_ERROR;      } @@ -1050,16 +1131,16 @@ ConvertUTCToLocalUsingC(   *----------------------------------------------------------------------   */ -static Tcl_Obj* +static Tcl_Obj *  LookupLastTransition( -    Tcl_Interp* interp,		/* Interpreter for error messages */ +    Tcl_Interp *interp,		/* Interpreter for error messages */      Tcl_WideInt tick,		/* Time from the epoch */      int rowc,			/* Number of rows of tzdata */ -    Tcl_Obj *CONST * rowv)	/* Rows in tzdata */ +    Tcl_Obj *const *rowv)	/* Rows in tzdata */  {      int l;      int u; -    Tcl_Obj* compObj; +    Tcl_Obj *compObj;      Tcl_WideInt compVal;      /* @@ -1122,10 +1203,10 @@ LookupLastTransition(  static void  GetYearWeekDay( -    TclDateFields* fields,	/* Date to convert, must have 'julianDay' */ -    int changeover		/* Julian Day Number of the Gregorian +    TclDateFields *fields,	/* Date to convert, must have 'julianDay' */ +    int changeover)		/* Julian Day Number of the Gregorian  				 * transition */ -) { +{      TclDateFields temp;      int dayOfFiscalYear; @@ -1189,9 +1270,9 @@ GetYearWeekDay(  static void  GetGregorianEraYearDay( -    TclDateFields* fields,	/* Date fields containing 'julianDay' */ -    int changeover		/* Gregorian transition date */ -) { +    TclDateFields *fields,	/* Date fields containing 'julianDay' */ +    int changeover)		/* Gregorian transition date */ +{      int jday = fields->julianDay;      int day;      int year; @@ -1213,6 +1294,10 @@ GetGregorianEraYearDay(  	day = jday - JDAY_1_JAN_1_CE_GREGORIAN;  	n = day / FOUR_CENTURIES;  	day %= FOUR_CENTURIES; +	if (day < 0) { +	    day += FOUR_CENTURIES; +	    n--; +	}  	year += 400 * n;  	/* @@ -1231,7 +1316,6 @@ GetGregorianEraYearDay(  	    day += ONE_CENTURY_GREGORIAN;  	}  	year += 100 * n; -      } else {  	/*  	 * Julian calendar. @@ -1240,7 +1324,6 @@ GetGregorianEraYearDay(  	fields->gregorian = 0;  	year = 1;  	day = jday - JDAY_1_JAN_1_CE_JULIAN; -      }      /* @@ -1248,7 +1331,11 @@ GetGregorianEraYearDay(       */      n = day / FOUR_YEARS; -    day %= 1461; +    day %= FOUR_YEARS; +    if (day < 0) { +	day += FOUR_YEARS; +	n--; +    }      year += 4 * n;      /* @@ -1271,7 +1358,7 @@ GetGregorianEraYearDay(       * store era/year/day back into fields.       */ -    if (year < 0) { +    if (year <= 0) {  	fields->era = BCE;  	fields->year = 1 - year;      } else { @@ -1299,11 +1386,11 @@ GetGregorianEraYearDay(  static void  GetMonthDay( -    TclDateFields* fields	/* Date to convert */ -) { +    TclDateFields *fields)	/* Date to convert */ +{      int day = fields->dayOfYear;      int month; -    const int* h = hath[IsGregorianLeapYear(fields)]; +    const int *h = hath[IsGregorianLeapYear(fields)];      for (month = 0; month < 12 && day > h[month]; ++month) {  	day -= h[month]; @@ -1331,18 +1418,18 @@ GetMonthDay(  static void  GetJulianDayFromEraYearWeekDay( -    TclDateFields* fields,	/* Date to convert */ -    int changeover		/* Julian Day Number of the Gregorian +    TclDateFields *fields,	/* Date to convert */ +    int changeover)		/* Julian Day Number of the Gregorian  				 * transition */ -) { +{      int firstMonday;		/* Julian day number of week 1, day 1 in the  				 * given year */ +    TclDateFields firstWeek;      /*       * Find January 4 in the ISO8601 year, which will always be in week 1.       */ -    TclDateFields firstWeek;      firstWeek.era = fields->era;      firstWeek.year = fields->iso8601Year;      firstWeek.month = 1; @@ -1382,12 +1469,10 @@ GetJulianDayFromEraYearWeekDay(  static void  GetJulianDayFromEraYearMonthDay( -    TclDateFields* fields,	/* Date to convert */ -    int changeover		/* Gregorian transition date as a Julian Day */ -) { -    int year;  int ym1; -    int month; int mm1; -    int q; int r; +    TclDateFields *fields,	/* Date to convert */ +    int changeover)		/* Gregorian transition date as a Julian Day */ +{ +    int year, ym1, month, mm1, q, r, ym1o4, ym1o100, ym1o400;      if (fields->era == BCE) {  	year = 1 - fields->year; @@ -1428,13 +1513,37 @@ GetJulianDayFromEraYearMonthDay(       * Try an initial conversion in the Gregorian calendar.       */ +#if 0 /* BUG http://core.tcl.tk/tcl/tktview?name=da340d4f32 */ +    ym1o4 = ym1 / 4; +#else +    /* +     * Have to make sure quotient is truncated towards 0 when negative. +     * See above bug for details. The casts are necessary. +     */ +    if (ym1 >= 0) +        ym1o4 = ym1 / 4; +    else { +        ym1o4 = - (int) (((unsigned int) -ym1) / 4); +    } +#endif +    if (ym1 % 4 < 0) { +	ym1o4--; +    } +    ym1o100 = ym1 / 100; +    if (ym1 % 100 < 0) { +	ym1o100--; +    } +    ym1o400 = ym1 / 400; +    if (ym1 % 400 < 0) { +	ym1o400--; +    }      fields->julianDay = JDAY_1_JAN_1_CE_GREGORIAN - 1  	    + fields->dayOfMonth  	    + daysInPriorMonths[IsGregorianLeapYear(fields)][month - 1]  	    + (ONE_YEAR * ym1) -	    + (ym1 / 4) -	    - (ym1 / 100) -	    + (ym1 / 400); +	    + ym1o4 +	    - ym1o100 +	    + ym1o400;      /*       * If the resulting date is before the Gregorian changeover, convert in @@ -1447,7 +1556,7 @@ GetJulianDayFromEraYearMonthDay(  		+ fields->dayOfMonth  		+ daysInPriorMonths[year%4 == 0][month - 1]  		+ (365 * ym1) -		+ (ym1 / 4); +		+ ym1o4;      }  } @@ -1467,8 +1576,8 @@ GetJulianDayFromEraYearMonthDay(  static int  IsGregorianLeapYear( -    TclDateFields* fields	/* Date to test */ -) { +    TclDateFields *fields)	/* Date to test */ +{      int year;      if (fields->era == BCE) { @@ -1506,9 +1615,12 @@ IsGregorianLeapYear(  static int  WeekdayOnOrBefore(      int dayOfWeek,		/* Day of week; Sunday == 0 or 7 */ -    int julianDay		/* Reference date */ -) { +    int julianDay)		/* Reference date */ +{      int k = (dayOfWeek + 6) % 7; +    if (k < 0) { +	k += 7; +    }      return julianDay - ((julianDay - k) % 7);  } @@ -1536,18 +1648,18 @@ WeekdayOnOrBefore(  int  ClockGetenvObjCmd(      ClientData clientData, -    Tcl_Interp* interp, +    Tcl_Interp *interp,      int objc, -    Tcl_Obj *CONST objv[]) +    Tcl_Obj *const objv[])  { -    CONST char* varName; -    CONST char* varValue; +    const char *varName; +    const char *varValue;      if (objc != 2) {  	Tcl_WrongNumArgs(interp, 1, objv, "name");  	return TCL_ERROR;      } -    varName = Tcl_GetStringFromObj(objv[1], NULL); +    varName = TclGetString(objv[1]);      varValue = getenv(varName);      if (varValue == NULL) {  	varValue = ""; @@ -1575,15 +1687,14 @@ ClockGetenvObjCmd(  static struct tm *  ThreadSafeLocalTime( -    CONST time_t *timePtr)	/* Pointer to the number of seconds since the +    const time_t *timePtr)	/* Pointer to the number of seconds since the  				 * local system's epoch */  {      /*       * Get a thread-local buffer to hold the returned time.       */ -    struct tm *tmPtr = (struct tm *) -	    Tcl_GetThreadData(&tmKey, (int) sizeof(struct tm)); +    struct tm *tmPtr = Tcl_GetThreadData(&tmKey, (int) sizeof(struct tm));  #ifdef HAVE_LOCALTIME_R      localtime_r(timePtr, tmPtr);  #else @@ -1594,10 +1705,9 @@ ThreadSafeLocalTime(      if (sysTmPtr == NULL) {  	Tcl_MutexUnlock(&clockMutex);  	return NULL; -    } else { -	memcpy((void *) tmPtr, (void *) localtime(timePtr), sizeof(struct tm)); -	Tcl_MutexUnlock(&clockMutex);      } +    memcpy(tmPtr, localtime(timePtr), sizeof(struct tm)); +    Tcl_MutexUnlock(&clockMutex);  #endif      return tmPtr;  } @@ -1623,18 +1733,19 @@ ThreadSafeLocalTime(  int  ClockClicksObjCmd(      ClientData clientData,	/* Client data is unused */ -    Tcl_Interp* interp,		/* Tcl interpreter */ +    Tcl_Interp *interp,		/* Tcl interpreter */      int objc,			/* Parameter count */ -    Tcl_Obj* CONST* objv)	/* Parameter values */ +    Tcl_Obj *const *objv)	/* Parameter values */  { -    static CONST char *clicksSwitches[] = { +    static const char *const clicksSwitches[] = {  	"-milliseconds", "-microseconds", NULL      };      enum ClicksSwitch { -	CLICKS_MILLIS,   CLICKS_MICROS,   CLICKS_NATIVE +	CLICKS_MILLIS, CLICKS_MICROS, CLICKS_NATIVE      };      int index = CLICKS_NATIVE;      Tcl_Time now; +    Tcl_WideInt clicks = 0;      switch (objc) {      case 1: @@ -1646,27 +1757,29 @@ ClockClicksObjCmd(  	}  	break;      default: -	Tcl_WrongNumArgs(interp, 1, objv, "?option?"); +	Tcl_WrongNumArgs(interp, 1, objv, "?-switch?");  	return TCL_ERROR;      }      switch (index) {      case CLICKS_MILLIS:  	Tcl_GetTime(&now); -	Tcl_SetObjResult(interp, Tcl_NewWideIntObj( (Tcl_WideInt) -		now.sec * 1000 + now.usec / 1000 ) ); +	clicks = (Tcl_WideInt) now.sec * 1000 + now.usec / 1000;  	break;      case CLICKS_NATIVE: -	Tcl_SetObjResult(interp, Tcl_NewWideIntObj( (Tcl_WideInt) -		TclpGetClicks())); +#ifdef TCL_WIDE_CLICKS +	clicks = TclpGetWideClicks(); +#else +	clicks = (Tcl_WideInt) TclpGetClicks(); +#endif  	break;      case CLICKS_MICROS:  	Tcl_GetTime(&now); -	Tcl_SetObjResult(interp, Tcl_NewWideIntObj( -		((Tcl_WideInt) now.sec * 1000000) + now.usec)); +	clicks = ((Tcl_WideInt) now.sec * 1000000) + now.usec;  	break;      } +    Tcl_SetObjResult(interp, Tcl_NewWideIntObj(clicks));      return TCL_OK;  } @@ -1691,9 +1804,9 @@ ClockClicksObjCmd(  int  ClockMillisecondsObjCmd(      ClientData clientData,	/* Client data is unused */ -    Tcl_Interp* interp,		/* Tcl interpreter */ +    Tcl_Interp *interp,		/* Tcl interpreter */      int objc,			/* Parameter count */ -    Tcl_Obj* CONST* objv)	/* Parameter values */ +    Tcl_Obj *const *objv)	/* Parameter values */  {      Tcl_Time now; @@ -1702,7 +1815,7 @@ ClockMillisecondsObjCmd(  	return TCL_ERROR;      }      Tcl_GetTime(&now); -    Tcl_SetObjResult(interp, Tcl_NewWideIntObj( (Tcl_WideInt) +    Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt)  	    now.sec * 1000 + now.usec / 1000));      return TCL_OK;  } @@ -1728,9 +1841,9 @@ ClockMillisecondsObjCmd(  int  ClockMicrosecondsObjCmd(      ClientData clientData,	/* Client data is unused */ -    Tcl_Interp* interp,		/* Tcl interpreter */ +    Tcl_Interp *interp,		/* Tcl interpreter */      int objc,			/* Parameter count */ -    Tcl_Obj* CONST* objv)	/* Parameter values */ +    Tcl_Obj *const *objv)	/* Parameter values */  {      Tcl_Time now; @@ -1744,6 +1857,124 @@ ClockMicrosecondsObjCmd(      return TCL_OK;  } +/* + *----------------------------------------------------------------------------- + * + * ClockParseformatargsObjCmd -- + * + *	Parses the arguments for [clock format]. + * + * Results: + *	Returns a standard Tcl result, whose value is a four-element list + *	comprising the time format, the locale, and the timezone. + * + * This function exists because the loop that parses the [clock format] + * options is a known performance "hot spot", and is implemented in an effort + * to speed that particular code up. + * + *----------------------------------------------------------------------------- + */ + +static int +ClockParseformatargsObjCmd( +    ClientData clientData,	/* Client data containing literal pool */ +    Tcl_Interp *interp,		/* Tcl interpreter */ +    int objc,			/* Parameter count */ +    Tcl_Obj *const objv[])	/* Parameter vector */ +{ +    ClockClientData *dataPtr = clientData; +    Tcl_Obj **litPtr = dataPtr->literals; +    Tcl_Obj *results[3];	/* Format, locale and timezone */ +#define formatObj results[0] +#define localeObj results[1] +#define timezoneObj results[2] +    int gmtFlag = 0; +    static const char *const options[] = { /* Command line options expected */ +	"-format",	"-gmt",		"-locale", +	"-timezone",	NULL }; +    enum optionInd { +	CLOCK_FORMAT_FORMAT,	CLOCK_FORMAT_GMT,	CLOCK_FORMAT_LOCALE, +	CLOCK_FORMAT_TIMEZONE +    }; +    int optionIndex;		/* Index of an option. */ +    int saw = 0;		/* Flag == 1 if option was seen already. */ +    Tcl_WideInt clockVal;	/* Clock value - just used to parse. */ +    int i; + +    /* +     * Args consist of a time followed by keyword-value pairs. +     */ + +    if (objc < 2 || (objc % 2) != 0) { +	Tcl_WrongNumArgs(interp, 0, objv, +		"clock format clockval ?-format string? " +		"?-gmt boolean? ?-locale LOCALE? ?-timezone ZONE?"); +	Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); +	return TCL_ERROR; +    } + +    /* +     * Extract values for the keywords. +     */ + +    formatObj = litPtr[LIT__DEFAULT_FORMAT]; +    localeObj = litPtr[LIT_C]; +    timezoneObj = litPtr[LIT__NIL]; +    for (i = 2; i < objc; i+=2) { +	if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, +		&optionIndex) != TCL_OK) { +	    Tcl_SetErrorCode(interp, "CLOCK", "badOption", +		    Tcl_GetString(objv[i]), NULL); +	    return TCL_ERROR; +	} +	switch (optionIndex) { +	case CLOCK_FORMAT_FORMAT: +	    formatObj = objv[i+1]; +	    break; +	case CLOCK_FORMAT_GMT: +	    if (Tcl_GetBooleanFromObj(interp, objv[i+1], &gmtFlag) != TCL_OK){ +		return TCL_ERROR; +	    } +	    break; +	case CLOCK_FORMAT_LOCALE: +	    localeObj = objv[i+1]; +	    break; +	case CLOCK_FORMAT_TIMEZONE: +	    timezoneObj = objv[i+1]; +	    break; +	} +	saw |= 1 << optionIndex; +    } + +    /* +     * Check options. +     */ + +    if (Tcl_GetWideIntFromObj(interp, objv[1], &clockVal) != TCL_OK) { +	return TCL_ERROR; +    } +    if ((saw & (1 << CLOCK_FORMAT_GMT)) +	    && (saw & (1 << CLOCK_FORMAT_TIMEZONE))) { +	Tcl_SetObjResult(interp, litPtr[LIT_CANNOT_USE_GMT_AND_TIMEZONE]); +	Tcl_SetErrorCode(interp, "CLOCK", "gmtWithTimezone", NULL); +	return TCL_ERROR; +    } +    if (gmtFlag) { +	timezoneObj = litPtr[LIT_GMT]; +    } + +    /* +     * Return options as a list. +     */ + +    Tcl_SetObjResult(interp, Tcl_NewListObj(3, results)); +    return TCL_OK; + +#undef timezoneObj +#undef localeObj +#undef formatObj +} +  /*----------------------------------------------------------------------   *   * ClockSecondsObjCmd - @@ -1765,9 +1996,9 @@ ClockMicrosecondsObjCmd(  int  ClockSecondsObjCmd(      ClientData clientData,	/* Client data is unused */ -    Tcl_Interp* interp,		/* Tcl interpreter */ +    Tcl_Interp *interp,		/* Tcl interpreter */      int objc,			/* Parameter count */ -    Tcl_Obj* CONST* objv)	/* Parameter values */ +    Tcl_Obj *const *objv)	/* Parameter values */  {      Tcl_Time now; @@ -1800,22 +2031,23 @@ ClockSecondsObjCmd(  static void  TzsetIfNecessary(void)  { -    static char* tzWas = NULL;	/* Previous value of TZ, protected by +    static char* tzWas = INT2PTR(-1);	/* Previous value of TZ, protected by  				 * clockMutex. */ -    CONST char* tzIsNow;	/* Current value of TZ */ +    const char *tzIsNow;	/* Current value of TZ */      Tcl_MutexLock(&clockMutex);      tzIsNow = getenv("TZ"); -    if (tzIsNow != NULL && (tzWas == NULL || strcmp(tzIsNow, tzWas) != 0)) { +    if (tzIsNow != NULL && (tzWas == NULL || tzWas == INT2PTR(-1) +	    || strcmp(tzIsNow, tzWas) != 0)) {  	tzset(); -	if (tzWas != NULL) { +	if (tzWas != NULL && tzWas != INT2PTR(-1)) {  	    ckfree(tzWas);  	}  	tzWas = ckalloc(strlen(tzIsNow) + 1);  	strcpy(tzWas, tzIsNow);      } else if (tzIsNow == NULL && tzWas != NULL) {  	tzset(); -	ckfree(tzWas); +	if (tzWas != INT2PTR(-1)) ckfree(tzWas);  	tzWas = NULL;      }      Tcl_MutexUnlock(&clockMutex); @@ -1839,16 +2071,15 @@ static void  ClockDeleteCmdProc(      ClientData clientData)	/* Opaque pointer to the client data */  { -    ClockClientData *data = (ClockClientData*) clientData; +    ClockClientData *data = clientData;      int i; -    --(data->refCount); -    if (data->refCount == 0) { +    if (data->refCount-- <= 1) {  	for (i = 0; i < LIT__END; ++i) {  	    Tcl_DecrRefCount(data->literals[i]);  	} -	ckfree((char*) (data->literals)); -	ckfree((char*) data); +	ckfree(data->literals); +	ckfree(data);      }  } | 
