summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-01-10 22:25:20 (GMT)
committersebres <sebres@users.sourceforge.net>2017-01-10 22:25:20 (GMT)
commit7b6cd1089c2d3a6eeb8f12b106af40c18017c8f3 (patch)
treed85ca1eb9d9794c0a126d12bde28a3b8e74c744b /generic
parent62ddcc3daa746fc8be02e6b118e0c923ec227793 (diff)
downloadtcl-7b6cd1089c2d3a6eeb8f12b106af40c18017c8f3.zip
tcl-7b6cd1089c2d3a6eeb8f12b106af40c18017c8f3.tar.gz
tcl-7b6cd1089c2d3a6eeb8f12b106af40c18017c8f3.tar.bz2
l10n (with caching) implemented, msgcat package optimized, code review, etc.
Diffstat (limited to 'generic')
-rw-r--r--generic/tclClock.c448
-rw-r--r--generic/tclClockFmt.c193
-rw-r--r--generic/tclDate.h45
3 files changed, 439 insertions, 247 deletions
diff --git a/generic/tclClock.c b/generic/tclClock.c
index 1e9abba..166a4b3 100644
--- a/generic/tclClock.c
+++ b/generic/tclClock.c
@@ -59,8 +59,7 @@ typedef enum ClockLiteral {
LIT_TZDATA,
LIT_GETSYSTEMTIMEZONE,
LIT_SETUPTIMEZONE,
- LIT_GETSYSTEMLOCALE,
- LIT_SETUPLOCALE,
+ LIT_MCGET, LIT_TCL_CLOCK,
#if 0
LIT_FREESCAN,
#endif
@@ -83,13 +82,17 @@ static const char *const Literals[] = {
"::tcl::clock::TZData",
"::tcl::clock::GetSystemTimeZone",
"::tcl::clock::SetupTimeZone",
- "::tcl::clock::mclocale",
- "::tcl::clock::EnterLocale",
+ "::msgcat::mcget", "::tcl::clock"
#if 0
"::tcl::clock::FreeScan"
#endif
};
+/* Msgcat literals for exact match (mcKey) */
+CLOCK_LOCALE_LITERAL_ARRAY(MsgCtLiterals, "");
+/* Msgcat index literals prefixed with _IDX_, used for quick dictionary search */
+CLOCK_LOCALE_LITERAL_ARRAY(MsgCtLitIdxs, "_IDX_");
+
static const char *const eras[] = { "CE", "BCE", NULL };
/*
@@ -257,9 +260,10 @@ TclClockInit(
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]);
+ Tcl_InitObjRef(data->literals[i], Tcl_NewStringObj(Literals[i], -1));
}
+ data->mcLiterals = NULL;
+ data->mcLitIdxs = NULL;
data->LastTZEpoch = 0;
data->currentYearCentury = ClockDefaultYearCentury;
data->yearOfCenturySwitch = ClockDefaultCenturySwitch;
@@ -273,6 +277,12 @@ TclClockInit(
data->LastSetupTimeZone = NULL;
data->LastSetupTZData = NULL;
+ data->CurrentLocale = NULL;
+ data->CurrentLocaleDict = NULL;
+ data->LastUnnormUsedLocale = NULL;
+ data->LastUsedLocale = NULL;
+ data->LastUsedLocaleDict = NULL;
+
data->lastBase.timezoneObj = NULL;
data->UTC2Local.timezoneObj = NULL;
data->UTC2Local.tzName = NULL;
@@ -323,6 +333,12 @@ ClockConfigureClear(
Tcl_UnsetObjRef(data->LastSetupTimeZone);
Tcl_UnsetObjRef(data->LastSetupTZData);
+ Tcl_UnsetObjRef(data->CurrentLocale);
+ Tcl_UnsetObjRef(data->CurrentLocaleDict);
+ Tcl_UnsetObjRef(data->LastUnnormUsedLocale);
+ Tcl_UnsetObjRef(data->LastUsedLocale);
+ Tcl_UnsetObjRef(data->LastUsedLocaleDict);
+
Tcl_UnsetObjRef(data->lastBase.timezoneObj);
Tcl_UnsetObjRef(data->UTC2Local.timezoneObj);
Tcl_UnsetObjRef(data->UTC2Local.tzName);
@@ -341,6 +357,18 @@ ClockDeleteCmdProc(
for (i = 0; i < LIT__END; ++i) {
Tcl_DecrRefCount(data->literals[i]);
}
+ if (data->mcLiterals != NULL) {
+ for (i = 0; i < MCLIT__END; ++i) {
+ Tcl_DecrRefCount(data->mcLiterals[i]);
+ }
+ data->mcLiterals = NULL;
+ }
+ if (data->mcLitIdxs != NULL) {
+ for (i = 0; i < MCLIT__END; ++i) {
+ Tcl_DecrRefCount(data->mcLitIdxs[i]);
+ }
+ data->mcLitIdxs = NULL;
+ }
ClockConfigureClear(data);
@@ -355,9 +383,9 @@ ClockDeleteCmdProc(
inline Tcl_Obj *
NormTimezoneObj(
ClockClientData *dataPtr, /* Client data containing literal pool */
- Tcl_Obj * timezoneObj)
+ Tcl_Obj *timezoneObj)
{
- const char * tz;
+ const char *tz;
if ( timezoneObj == dataPtr->LastUnnormSetupTimeZone
&& dataPtr->LastSetupTimeZone != NULL
) {
@@ -399,6 +427,208 @@ NormTimezoneObj(
/*
*----------------------------------------------------------------------
*/
+static Tcl_Obj *
+NormLocaleObj(
+ ClockClientData *dataPtr, /* Client data containing literal pool */
+ Tcl_Obj *localeObj,
+ Tcl_Obj **mcDictObj)
+{
+ const char *loc;
+ if ( localeObj == NULL || localeObj == dataPtr->CurrentLocale
+ || localeObj == dataPtr->literals[LIT_C]
+ ) {
+ *mcDictObj = dataPtr->CurrentLocaleDict;
+ return dataPtr->CurrentLocale;
+ }
+ if ( localeObj == dataPtr->LastUsedLocale
+ || localeObj == dataPtr->LastUnnormUsedLocale
+ ) {
+ *mcDictObj = dataPtr->LastUsedLocaleDict;
+ return dataPtr->LastUsedLocale;
+ }
+
+ loc = TclGetString(localeObj);
+ if (dataPtr->CurrentLocale != NULL &&
+ (localeObj == dataPtr->CurrentLocale
+ || strcmp(loc, TclGetString(dataPtr->CurrentLocale)) == 0
+ )
+ ) {
+ *mcDictObj = dataPtr->CurrentLocaleDict;
+ localeObj = dataPtr->CurrentLocale;
+ }
+ else
+ if (dataPtr->LastUsedLocale != NULL &&
+ (localeObj == dataPtr->LastUsedLocale
+ || strcmp(loc, TclGetString(dataPtr->LastUsedLocale)) == 0
+ )
+ ) {
+ *mcDictObj = dataPtr->LastUsedLocaleDict;
+ Tcl_SetObjRef(dataPtr->LastUnnormUsedLocale, localeObj);
+ localeObj = dataPtr->LastUsedLocale;
+ }
+ else
+ if (
+ strcmp(loc, Literals[LIT_C]) == 0
+ ) {
+ *mcDictObj = dataPtr->CurrentLocaleDict;
+ localeObj = dataPtr->CurrentLocale;
+ }
+ else
+ {
+ *mcDictObj = NULL;
+ }
+ return localeObj;
+}
+
+/*
+ *----------------------------------------------------------------------
+ */
+MODULE_SCOPE Tcl_Obj *
+ClockMCDict(ClockFmtScnCmdArgs *opts)
+{
+ ClockClientData *dataPtr = opts->clientData;
+ Tcl_Obj *callargs[3];
+
+ /* if dict not yet retrieved */
+ if (opts->mcDictObj == NULL) {
+
+ /* if locale was not yet used */
+ if ( !(opts->flags & CLF_LOCALE_USED) ) {
+
+ opts->localeObj = NormLocaleObj(opts->clientData,
+ opts->localeObj, &opts->mcDictObj);
+
+ if (opts->localeObj == NULL) {
+ Tcl_SetResult(opts->interp,
+ "locale not specified and no default locale set", TCL_STATIC);
+ Tcl_SetErrorCode(opts->interp, "CLOCK", "badOption", NULL);
+ return NULL;
+ }
+ opts->flags |= CLF_LOCALE_USED;
+
+ /* check locale literals already available (on demand creation) */
+ if (dataPtr->mcLiterals == NULL) {
+ int i;
+ dataPtr->mcLiterals = ckalloc(MCLIT__END * sizeof(Tcl_Obj*));
+ for (i = 0; i < MCLIT__END; ++i) {
+ Tcl_InitObjRef(dataPtr->mcLiterals[i],
+ Tcl_NewStringObj(MsgCtLiterals[i], -1));
+ }
+ }
+ }
+
+ if (opts->mcDictObj == NULL) {
+ /* get msgcat dictionary - ::msgcat::mcget ::tcl::clock locale */
+ callargs[0] = dataPtr->literals[LIT_MCGET];
+ callargs[1] = dataPtr->literals[LIT_TCL_CLOCK];
+ callargs[2] = opts->localeObj;
+
+ if (Tcl_EvalObjv(opts->interp, 3, callargs, 0) != TCL_OK) {
+ return NULL;
+ }
+
+ opts->mcDictObj = Tcl_GetObjResult(opts->interp);
+ if ( opts->localeObj == dataPtr->CurrentLocale ) {
+ Tcl_SetObjRef(dataPtr->CurrentLocaleDict, opts->mcDictObj);
+ } else {
+ Tcl_SetObjRef(dataPtr->LastUsedLocale, opts->localeObj);
+ Tcl_UnsetObjRef(dataPtr->LastUnnormUsedLocale);
+ Tcl_SetObjRef(dataPtr->LastUsedLocaleDict, opts->mcDictObj);
+ }
+ }
+ }
+
+ return opts->mcDictObj;
+}
+
+MODULE_SCOPE Tcl_Obj *
+ClockMCGet(
+ ClockFmtScnCmdArgs *opts,
+ int mcKey)
+{
+ ClockClientData *dataPtr = opts->clientData;
+
+ Tcl_Obj *valObj = NULL;
+
+ if (opts->mcDictObj == NULL) {
+ ClockMCDict(opts);
+ if (opts->mcDictObj == NULL)
+ return NULL;
+ }
+
+ Tcl_DictObjGet(opts->interp, opts->mcDictObj,
+ dataPtr->mcLiterals[mcKey], &valObj);
+
+ return valObj; /* or NULL in obscure case if Tcl_DictObjGet failed */
+}
+
+MODULE_SCOPE Tcl_Obj *
+ClockMCGetListIdxDict(
+ ClockFmtScnCmdArgs *opts,
+ int mcKey)
+{
+ ClockClientData *dataPtr = opts->clientData;
+
+ Tcl_Obj *valObj = NULL;
+
+ if (opts->mcDictObj == NULL) {
+ ClockMCDict(opts);
+ if (opts->mcDictObj == NULL)
+ return NULL;
+ }
+
+ /* try to get indices dictionray,
+ * if not available - create from list */
+
+ if (Tcl_DictObjGet(NULL, opts->mcDictObj,
+ dataPtr->mcLitIdxs[mcKey], &valObj) != TCL_OK
+ ) {
+ Tcl_Obj **lstv, *intObj;
+ int i, lstc;
+
+ if (dataPtr->mcLitIdxs == NULL) {
+ dataPtr->mcLitIdxs = ckalloc(MCLIT__END * sizeof(Tcl_Obj*));
+ for (i = 0; i < MCLIT__END; ++i) {
+ Tcl_InitObjRef(dataPtr->mcLitIdxs[i],
+ Tcl_NewStringObj(MsgCtLitIdxs[i], -1));
+ }
+ }
+
+ if (Tcl_DictObjGet(opts->interp, opts->mcDictObj,
+ dataPtr->mcLiterals[mcKey], &valObj) != TCL_OK) {
+ return NULL;
+ };
+ if (TclListObjGetElements(opts->interp, valObj,
+ &lstc, &lstv) != TCL_OK) {
+ return NULL;
+ };
+
+ valObj = Tcl_NewDictObj();
+ for (i = 0; i < lstc; i++) {
+ intObj = Tcl_NewIntObj(i);
+ if (Tcl_DictObjPut(opts->interp, valObj,
+ lstv[i], intObj) != TCL_OK
+ ) {
+ Tcl_DecrRefCount(valObj);
+ Tcl_DecrRefCount(intObj);
+ return NULL;
+ }
+ };
+
+ if (Tcl_DictObjPut(opts->interp, opts->mcDictObj,
+ dataPtr->mcLitIdxs[mcKey], valObj) != TCL_OK
+ ) {
+ Tcl_DecrRefCount(valObj);
+ return NULL;
+ }
+ };
+
+ return valObj;
+}
+
+/*
+ *----------------------------------------------------------------------
+ */
static int
ClockConfigureObjCmd(
ClientData clientData, /* Client data containing literal pool */
@@ -410,23 +640,25 @@ ClockConfigureObjCmd(
Tcl_Obj **litPtr = dataPtr->literals;
static const char *const options[] = {
- "-system-tz", "-setup-tz", "-clear",
+ "-system-tz", "-setup-tz", "-default-locale",
+ "-clear",
"-year-century", "-century-switch",
NULL
};
enum optionInd {
- CLOCK_SYSTEM_TZ, CLOCK_SETUP_TZ, CLOCK_CLEAR_CACHE,
+ CLOCK_SYSTEM_TZ, CLOCK_SETUP_TZ, CLOCK_CURRENT_LOCALE,
+ CLOCK_CLEAR_CACHE,
CLOCK_YEAR_CENTURY, CLOCK_CENTURY_SWITCH,
CLOCK_SETUP_GMT, CLOCK_SETUP_NOP
};
int optionIndex; /* Index of an option. */
int i;
- for (i = 1; i < objc; i+=2) {
- if (Tcl_GetIndexFromObj(interp, objv[i], options,
+ for (i = 1; i < objc; i++) {
+ if (Tcl_GetIndexFromObj(interp, objv[i++], options,
"option", 0, &optionIndex) != TCL_OK) {
Tcl_SetErrorCode(interp, "CLOCK", "badOption",
- Tcl_GetString(objv[i]), NULL);
+ Tcl_GetString(objv[i-1]), NULL);
return TCL_ERROR;
}
switch (optionIndex) {
@@ -434,24 +666,24 @@ ClockConfigureObjCmd(
if (1) {
/* validate current tz-epoch */
unsigned long lastTZEpoch = TzsetGetEpoch();
- if (i+1 < objc) {
- if (dataPtr->SystemTimeZone != objv[i+1]) {
- Tcl_SetObjRef(dataPtr->SystemTimeZone, objv[i+1]);
+ if (i < objc) {
+ if (dataPtr->SystemTimeZone != objv[i]) {
+ Tcl_SetObjRef(dataPtr->SystemTimeZone, objv[i]);
Tcl_UnsetObjRef(dataPtr->SystemSetupTZData);
}
dataPtr->LastTZEpoch = lastTZEpoch;
}
- if (dataPtr->SystemTimeZone != NULL
+ if (i+1 >= objc && dataPtr->SystemTimeZone != NULL
&& dataPtr->LastTZEpoch == lastTZEpoch) {
Tcl_SetObjResult(interp, dataPtr->SystemTimeZone);
}
}
break;
case CLOCK_SETUP_TZ:
- if (i+1 < objc) {
+ if (i < objc) {
/* differentiate GMT and system zones, because used often */
- Tcl_Obj *timezoneObj = NormTimezoneObj(dataPtr, objv[i+1]);
- Tcl_SetObjRef(dataPtr->LastUnnormSetupTimeZone, objv[i+1]);
+ Tcl_Obj *timezoneObj = NormTimezoneObj(dataPtr, objv[i]);
+ Tcl_SetObjRef(dataPtr->LastUnnormSetupTimeZone, objv[i]);
if (dataPtr->LastSetupTimeZone != timezoneObj) {
Tcl_SetObjRef(dataPtr->LastSetupTimeZone, timezoneObj);
Tcl_UnsetObjRef(dataPtr->LastSetupTZData);
@@ -463,7 +695,7 @@ ClockConfigureObjCmd(
}
switch (optionIndex) {
case CLOCK_SETUP_GMT:
- if (i+1 < objc) {
+ if (i < objc) {
if (dataPtr->GMTSetupTimeZone != timezoneObj) {
Tcl_SetObjRef(dataPtr->GMTSetupTimeZone, timezoneObj);
Tcl_UnsetObjRef(dataPtr->GMTSetupTZData);
@@ -471,7 +703,7 @@ ClockConfigureObjCmd(
}
break;
case CLOCK_SETUP_TZ:
- if (i+1 < objc) {
+ if (i < objc) {
if (dataPtr->AnySetupTimeZone != timezoneObj) {
Tcl_SetObjRef(dataPtr->AnySetupTimeZone, timezoneObj);
Tcl_UnsetObjRef(dataPtr->AnySetupTZData);
@@ -480,35 +712,52 @@ ClockConfigureObjCmd(
break;
}
}
- if (dataPtr->LastSetupTimeZone != NULL) {
+ if (i+1 >= objc && dataPtr->LastSetupTimeZone != NULL) {
Tcl_SetObjResult(interp, dataPtr->LastSetupTimeZone);
}
break;
+ case CLOCK_CURRENT_LOCALE:
+ if (i < objc) {
+ if (dataPtr->CurrentLocale != objv[i]) {
+ Tcl_SetObjRef(dataPtr->CurrentLocale, objv[i]);
+ Tcl_UnsetObjRef(dataPtr->CurrentLocaleDict);
+ }
+ }
+ if (i+1 >= objc && dataPtr->CurrentLocale != NULL) {
+ Tcl_SetObjResult(interp, dataPtr->CurrentLocale);
+ }
+ break;
case CLOCK_YEAR_CENTURY:
- if (i+1 < objc) {
+ if (i < objc) {
int year;
- if (TclGetIntFromObj(interp, objv[i+1], &year) != TCL_OK) {
+ if (TclGetIntFromObj(interp, objv[i], &year) != TCL_OK) {
return TCL_ERROR;
}
dataPtr->currentYearCentury = year;
- Tcl_SetObjResult(interp, objv[i+1]);
+ if (i+1 >= objc) {
+ Tcl_SetObjResult(interp, objv[i]);
+ }
continue;
- }
- Tcl_SetObjResult(interp,
- Tcl_NewIntObj(dataPtr->currentYearCentury));
+ }
+ if (i+1 >= objc) {
+ Tcl_SetObjResult(interp,
+ Tcl_NewIntObj(dataPtr->currentYearCentury));
+ }
break;
case CLOCK_CENTURY_SWITCH:
- if (i+1 < objc) {
+ if (i < objc) {
int year;
- if (TclGetIntFromObj(interp, objv[i+1], &year) != TCL_OK) {
+ if (TclGetIntFromObj(interp, objv[i], &year) != TCL_OK) {
return TCL_ERROR;
}
dataPtr->yearOfCenturySwitch = year;
- Tcl_SetObjResult(interp, objv[i+1]);
+ Tcl_SetObjResult(interp, objv[i]);
continue;
- }
- Tcl_SetObjResult(interp,
- Tcl_NewIntObj(dataPtr->yearOfCenturySwitch));
+ }
+ if (i+1 >= objc) {
+ Tcl_SetObjResult(interp,
+ Tcl_NewIntObj(dataPtr->yearOfCenturySwitch));
+ }
break;
case CLOCK_CLEAR_CACHE:
ClockConfigureClear(dataPtr);
@@ -597,7 +846,7 @@ ClockGetSystemTimeZone(
}
Tcl_UnsetObjRef(dataPtr->SystemTimeZone);
- Tcl_UnsetObjRef(data->SystemSetupTZData);
+ Tcl_UnsetObjRef(dataPtr->SystemSetupTZData);
literals = dataPtr->literals;
@@ -683,125 +932,6 @@ ClockFormatNumericTimeZone(int z) {
}
return Tcl_ObjPrintf("%c%02d%02d", sign, h, m);
}
-
-/*
- *----------------------------------------------------------------------
- */
-inline Tcl_Obj *
-NormLocaleObj(
- ClockClientData *dataPtr, /* Client data containing literal pool */
- Tcl_Obj *localeObj)
-{
- const char * tz;
- if ( localeObj == dataPtr->LastUnnormSetupLocale
- && dataPtr->LastSetupLocale != NULL
- ) {
- return dataPtr->LastSetupLocale;
- }
- if ( localeObj == dataPtr->LastSetupLocale
- || localeObj == dataPtr->literals[LIT_CLOCALE]
- || localeObj == dataPtr->SystemLocale
- || localeObj == dataPtr->AnySetupLocale
- ) {
- return localeObj;
- }
-
- tz = TclGetString(localeObj);
- if (dataPtr->AnySetupLocale != NULL &&
- (localeObj == dataPtr->AnySetupLocale
- || strcmp(tz, TclGetString(dataPtr->AnySetupLocale)) == 0
- )
- ) {
- localeObj = dataPtr->AnySetupLocale;
- }
- else
- if (dataPtr->SystemLocale != NULL &&
- (localeObj == dataPtr->SystemLocale
- || strcmp(tz, TclGetString(dataPtr->SystemLocale)) == 0
- )
- ) {
- localeObj = dataPtr->SystemLocale;
- }
- else
- if (
- strcmp(tz, Literals[LIT_GMT]) == 0
- ) {
- localeObj = dataPtr->literals[LIT_GMT];
- }
- return localeObj;
-}
-/*
- *----------------------------------------------------------------------
- */
-static Tcl_Obj *
-ClockGetSystemLocale(
- ClientData clientData, /* Opaque pointer to literal pool, etc. */
- Tcl_Interp *interp) /* Tcl interpreter */
-{
- ClockClientData *dataPtr = clientData;
- Tcl_Obj **literals;
-
- /* if known (cached) - return now */
- if (dataPtr->SystemLocale != NULL) {
- return dataPtr->SystemLocale;
- }
-
- literals = dataPtr->literals;
-
- if (Tcl_EvalObjv(interp, 1, &literals[LIT_GETSYSTEMLOCALE], 0) != TCL_OK) {
- return NULL;
- }
- Tcl_SetObjRef(dataPtr->SystemLocale, Tcl_GetObjResult(interp));
- return dataPtr->SystemLocale;
-}
-/*
- *----------------------------------------------------------------------
- */
-static Tcl_Obj *
-ClockSetupLocale(
- ClientData clientData, /* Opaque pointer to literal pool, etc. */
- Tcl_Interp *interp, /* Tcl interpreter */
- Tcl_Obj *localeObj)
-{
- ClockClientData *dataPtr = clientData;
- Tcl_Obj **literals = dataPtr->literals;
- Tcl_Obj *callargs[2];
-
- if (localeObj == NULL || localeObj == dataPtr->SystemLocale) {
- if (dataPtr->SystemLocale == NULL) {
- return ClockGetSystemLocale(clientData, interp);
- }
- return dataPtr->SystemLocale;
- }
-
-#if 0
- /* if cached (if already setup this one) */
- if ( dataPtr->LastSetupTimeZone != NULL
- && ( localeObj == dataPtr->LastSetupTimeZone
- || timezoneObj == dataPtr->LastUnnormSetupTimeZone
- )
- ) {
- return dataPtr->LastSetupTimeZone;
- }
-
- /* differentiate GMT and system zones, because used often and already set */
- timezoneObj = NormTimezoneObj(dataPtr, timezoneObj);
- if ( timezoneObj == dataPtr->GMTSetupTimeZone
- || timezoneObj == dataPtr->SystemTimeZone
- || timezoneObj == dataPtr->AnySetupTimeZone
- ) {
- return timezoneObj;
- }
-
-#endif
- callargs[0] = literals[LIT_SETUPLOCALE];
- callargs[1] = localeObj;
-
- if (Tcl_EvalObjv(interp, 2, callargs, 0) == TCL_OK) {
- return localeObj; // dataPtr->CurrentLocale;
- }
- return NULL;
-}
/*
*----------------------------------------------------------------------
*
@@ -2741,19 +2871,13 @@ ClockScanObjCmd(
}
}
- /* Setup timezone and locale */
+ /* Setup timezone (normalize object id needed and load TZ on demand) */
opts.timezoneObj = ClockSetupTimeZone(clientData, interp, opts.timezoneObj);
if (opts.timezoneObj == NULL) {
return TCL_ERROR;
}
- opts.localeObj = ClockSetupLocale(clientData, interp, opts.localeObj);
- if (opts.localeObj == NULL) {
- return TCL_ERROR;
- }
-
-
ClockInitDateInfo(info);
yydate.tzName = NULL;
diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c
index 17181d9..a3c7f20 100644
--- a/generic/tclClockFmt.c
+++ b/generic/tclClockFmt.c
@@ -454,45 +454,55 @@ Tcl_GetClockFrmScnFromObj(
return fss;
}
-
+
+/*
+ * DetermineGreedySearchLen --
+ *
+ * Determine min/max lengths as exact as possible (speed, greedy match)
+ *
+ */
+inline
+void DetermineGreedySearchLen(ClockFmtScnCmdArgs *opts,
+ DateInfo *info, ClockScanToken *tok, int *minLen, int *maxLen)
+{
+ register const char*p = yyInput;
+ *minLen = 0;
+ *maxLen = info->dateEnd - p;
+
+ /* if no tokens anymore */
+ if (!(tok+1)->map) {
+ /* should match to end or first space */
+ while (!isspace(UCHAR(*p)) && ++p < info->dateEnd) {};
+ *minLen = p - yyInput;
+ }
+}
static int
LocaleListSearch(ClockFmtScnCmdArgs *opts,
- DateInfo *info, const char * mcKey, int *val)
+ DateInfo *info, int mcKey, int *val,
+ int minLen, int maxLen)
{
- Tcl_Obj *callargs[4] = {NULL, NULL, NULL, NULL}, **lstv;
- int i, lstc;
- Tcl_Obj *valObj = NULL;
- int ret = TCL_RETURN;
+ Tcl_Obj **lstv;
+ int lstc, i, l;
+ const char *s;
+ Tcl_Obj *valObj;
/* get msgcat value */
- TclNewLiteralStringObj(callargs[0], "::msgcat::mcget");
- TclNewLiteralStringObj(callargs[1], "::tcl::clock");
- callargs[2] = opts->localeObj;
- if (opts->localeObj == NULL) {
- TclNewLiteralStringObj(callargs[1], "c");
- }
- callargs[3] = Tcl_NewStringObj(mcKey, -1);
-
- for (i = 0; i < 4; i++) {
- Tcl_IncrRefCount(callargs[i]);
- }
- if (Tcl_EvalObjv(opts->interp, 4, callargs, 0) != TCL_OK) {
- goto done;
+ valObj = ClockMCGet(opts, mcKey);
+ if (valObj == NULL) {
+ return TCL_ERROR;
}
- Tcl_InitObjRef(valObj, Tcl_GetObjResult(opts->interp));
-
/* is a list */
if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
- goto done;
+ return TCL_ERROR;
}
/* search in list */
for (i = 0; i < lstc; i++) {
- const char *s = TclGetString(lstv[i]);
- int l = lstv[i]->length;
- if ( l <= info->dateEnd - yyInput
+ s = TclGetString(lstv[i]);
+ l = lstv[i]->length;
+ if ( l >= minLen && l <= maxLen
&& strncasecmp(yyInput, s, l) == 0
) {
*val = i;
@@ -501,21 +511,11 @@ LocaleListSearch(ClockFmtScnCmdArgs *opts,
}
}
- ret = TCL_OK;
/* if not found */
- if (i >= lstc) {
- ret = TCL_ERROR;
- }
-
-done:
-
- Tcl_UnsetObjRef(valObj);
-
- for (i = 0; i < 4; i++) {
- Tcl_UnsetObjRef(callargs[i]);
+ if (i < lstc) {
+ return TCL_OK;
}
-
- return ret;
+ return TCL_RETURN;
}
static int
@@ -535,12 +535,34 @@ StaticListSearch(ClockFmtScnCmdArgs *opts,
}
s++;
}
- if (*s == NULL) {
- return TCL_ERROR;
+ if (*s != NULL) {
+ return TCL_OK;
}
-
- return TCL_OK;
-};
+ return TCL_RETURN;
+}
+
+inline const char *
+FindWordEnd(
+ ClockScanToken *tok,
+ register const char * p, const char * end)
+{
+ register const char *x = tok->tokWord.start;
+ if (x == tok->tokWord.end) { /* single char word */
+ if (*p != *x) {
+ /* no match -> error */
+ return NULL;
+ }
+ return ++p;
+ }
+ /* multi-char word */
+ while (*p++ == *x++) {
+ if (x >= tok->tokWord.end || p >= end) {
+ /* no match -> error */
+ return NULL;
+ }
+ };
+ return p;
+}
static int
ClockScnToken_Month_Proc(ClockFmtScnCmdArgs *opts,
@@ -560,19 +582,26 @@ ClockScnToken_Month_Proc(ClockFmtScnCmdArgs *opts,
};
int val;
if (StaticListSearch(opts, info, months, &val) != TCL_OK) {
- return TCL_ERROR;
+ return TCL_RETURN;
}
yyMonth = (val % 12) + 1;
return TCL_OK;
*/
- int val;
- int ret = LocaleListSearch(opts, info, "MONTHS_FULL", &val);
+ int ret, val;
+ int minLen;
+ int maxLen;
+
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
+
+ ret = LocaleListSearch(opts, info, MCLIT_MONTHS_FULL, &val,
+ minLen, maxLen);
if (ret != TCL_OK) {
+ /* if not found */
if (ret == TCL_RETURN) {
- return ret;
+ ret = LocaleListSearch(opts, info, MCLIT_MONTHS_ABBREV, &val,
+ minLen, maxLen);
}
- ret = LocaleListSearch(opts, info, "MONTHS_ABBREV", &val);
if (ret != TCL_OK) {
return ret;
}
@@ -588,9 +617,14 @@ static int
ClockScnToken_LocaleListMatcher_Proc(ClockFmtScnCmdArgs *opts,
DateInfo *info, ClockScanToken *tok)
{
- int val;
+ int ret, val;
+ int minLen;
+ int maxLen;
+
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
- int ret = LocaleListSearch(opts, info, (char *)tok->map->data, &val);
+ ret = LocaleListSearch(opts, info, (int)tok->map->data, &val,
+ minLen, maxLen);
if (ret != TCL_OK) {
return ret;
}
@@ -639,8 +673,8 @@ static ClockScanTokenMap ScnSTokenMap[] = {
NULL},
};
static const char *ScnSTokenWrapMapIndex[2] = {
- "eBh",
- "dbb"
+ "eNBh",
+ "dmbb"
};
static const char *ScnETokenMapIndex =
@@ -654,11 +688,14 @@ static const char *ScnETokenWrapMapIndex[2] = {
};
static const char *ScnOTokenMapIndex =
- "d";
+ "dm";
static ClockScanTokenMap ScnOTokenMap[] = {
/* %Od %Oe */
{CTOKT_PARSER, CLF_DATE, 0, 0, TclOffset(DateInfo, date.dayOfMonth),
- ClockScnToken_LocaleListMatcher_Proc, "LOCALE_NUMERALS"},
+ ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
+ /* %Om */
+ {CTOKT_PARSER, CLF_DATE, 0, 0, TclOffset(DateInfo, date.month),
+ ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS},
};
static const char *ScnOTokenWrapMapIndex[2] = {
"e",
@@ -730,7 +767,7 @@ ClockGetOrParseScanFormat(
switch (*p) {
case '%':
if (1) {
- ClockScanTokenMap * maps = ScnSTokenMap;
+ ClockScanTokenMap * scnMap = ScnSTokenMap;
const char *mapIndex = ScnSTokenMapIndex,
**wrapIndex = ScnSTokenWrapMapIndex;
if (p+1 >= e) {
@@ -748,13 +785,13 @@ ClockGetOrParseScanFormat(
continue;
break;
case 'E':
- maps = ScnETokenMap,
+ scnMap = ScnETokenMap,
mapIndex = ScnETokenMapIndex,
wrapIndex = ScnETokenWrapMapIndex;
p++;
break;
case 'O':
- maps = ScnOTokenMap,
+ scnMap = ScnOTokenMap,
mapIndex = ScnOTokenMapIndex,
wrapIndex = ScnOTokenWrapMapIndex;
p++;
@@ -778,7 +815,7 @@ ClockGetOrParseScanFormat(
goto word_tok;
}
}
- tok->map = &ScnSTokenMap[cp - mapIndex];
+ tok->map = &scnMap[cp - mapIndex];
tok->tokWord.start = p;
/* calculate look ahead value by standing together tokens */
if (tok > fss->scnTok) {
@@ -928,7 +965,7 @@ ClockScan(
size = p - yyInput;
if (size < map->minSize) {
/* missing input -> error */
- goto error;
+ goto not_match;
}
/* string 2 number, put number into info structure by offset */
p = yyInput; x = p + size;
@@ -953,10 +990,10 @@ ClockScan(
case TCL_OK:
break;
case TCL_RETURN:
- goto done;
+ goto not_match;
break;
default:
- goto error;
+ goto done;
break;
};
p = yyInput;
@@ -967,7 +1004,7 @@ ClockScan(
if (opts->flags & CLF_STRICT) {
if (!isspace(UCHAR(*p))) {
/* unmatched -> error */
- goto error;
+ goto not_match;
}
p++;
}
@@ -976,21 +1013,13 @@ ClockScan(
}
break;
case CTOKT_WORD:
- x = tok->tokWord.start;
- if (x == tok->tokWord.end) { /* single char word */
- if (*p != *x) {
- /* no match -> error */
- goto error;
- }
- p++;
- continue;
- }
- /* multi-char word */
- while (p < end && x < tok->tokWord.end && *p++ == *x++) {};
- if (x < tok->tokWord.end) {
+ x = FindWordEnd(tok, p, end);
+ if (!x) {
/* no match -> error */
- goto error;
+ goto not_match;
}
+ p = x;
+ continue;
break;
}
}
@@ -1002,7 +1031,7 @@ ClockScan(
/* check end was reached */
if (p < end) {
/* something after last token - wrong format */
- goto error;
+ goto not_match;
}
/* invalidate result */
@@ -1045,15 +1074,15 @@ ClockScan(
overflow:
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "integer value too large to represent", -1));
- Tcl_SetErrorCode(interp, "CLOCK", "integervalueTooLarge", NULL);
+ Tcl_SetResult(interp, "requested date too large to represent",
+ TCL_STATIC);
+ Tcl_SetErrorCode(interp, "CLOCK", "dateTooLarge", NULL);
goto done;
-error:
+not_match:
- Tcl_SetResult(interp,
- "input string does not match supplied format", TCL_STATIC);
+ Tcl_SetResult(interp, "input string does not match supplied format",
+ TCL_STATIC);
Tcl_SetErrorCode(interp, "CLOCK", "badInputString", NULL);
done:
diff --git a/generic/tclDate.h b/generic/tclDate.h
index d97cd3c..1c51a02 100644
--- a/generic/tclDate.h
+++ b/generic/tclDate.h
@@ -35,6 +35,22 @@
#define CLF_INVALIDATE_JULIANDAY (1 << 7) /* assemble julianDay using year, month, etc. */
#define CLF_INVALIDATE_SECONDS (1 << 8) /* assemble localSeconds (and seconds at end) */
+
+/*
+ * Enumeration of the msgcat literals used in [clock]
+ */
+
+typedef enum ClockMsgCtLiteral {
+ MCLIT_MONTHS_FULL, MCLIT_MONTHS_ABBREV,
+ MCLIT_LOCALE_NUMERALS,
+ MCLIT__END
+} ClockMsgCtLiteral;
+
+#define CLOCK_LOCALE_LITERAL_ARRAY(litarr, pref) static const char *const litarr[] = { \
+ pref "MONTHS_FULL", pref "MONTHS_ABBREV", \
+ pref "LOCALE_NUMERALS", \
+}
+
/*
* Primitives to safe set, reset and free references.
*/
@@ -176,16 +192,19 @@ ClockInitDateInfo(DateInfo *info) {
#define CLF_EXTENDED (1 << 4)
#define CLF_STRICT (1 << 8)
+#define CLF_LOCALE_USED (1 << 15)
typedef struct ClockFmtScnCmdArgs {
- ClientData clientData, /* Opaque pointer to literal pool, etc. */
- Tcl_Interp *interp, /* Tcl interpreter */
+ ClientData clientData; /* Opaque pointer to literal pool, etc. */
+ Tcl_Interp *interp; /* Tcl interpreter */
Tcl_Obj *formatObj; /* Format */
Tcl_Obj *localeObj; /* Name of the locale where the time will be expressed. */
Tcl_Obj *timezoneObj; /* Default time zone in which the time will be expressed */
Tcl_Obj *baseObj; /* Base (scan only) */
int flags; /* Flags control scanning */
+
+ Tcl_Obj *mcDictObj; /* Current dictionary of tcl::clock package for given localeObj*/
} ClockFmtScnCmdArgs;
/*
@@ -194,7 +213,11 @@ typedef struct ClockFmtScnCmdArgs {
typedef struct ClockClientData {
int refCount; /* Number of live references. */
- Tcl_Obj **literals; /* Pool of object literals. */
+ Tcl_Obj **literals; /* Pool of object literals (common, locale independent). */
+ Tcl_Obj **mcLiterals; /* Msgcat object literals with mc-keys for search with locale. */
+ Tcl_Obj **mcLitIdxs; /* Msgcat object indices prefixed with _IDX_,
+ * used for quick dictionary search */
+
/* Cache for current clock parameters, imparted via "configure" */
unsigned long LastTZEpoch;
int currentYearCentury;
@@ -208,6 +231,13 @@ typedef struct ClockClientData {
Tcl_Obj *LastUnnormSetupTimeZone;
Tcl_Obj *LastSetupTimeZone;
Tcl_Obj *LastSetupTZData;
+
+ Tcl_Obj *CurrentLocale;
+ Tcl_Obj *CurrentLocaleDict;
+ Tcl_Obj *LastUnnormUsedLocale;
+ Tcl_Obj *LastUsedLocale;
+ Tcl_Obj *LastUsedLocaleDict;
+
/* Cache for last base (last-second fast convert if base/tz not changed) */
struct {
Tcl_Obj *timezoneObj;
@@ -328,6 +358,15 @@ MODULE_SCOPE time_t ToSeconds(time_t Hours, time_t Minutes,
MODULE_SCOPE int TclClockFreeScan(Tcl_Interp *interp, DateInfo *info);
+/* tclClock.c module declarations */
+
+MODULE_SCOPE Tcl_Obj *
+ ClockMCDict(ClockFmtScnCmdArgs *opts);
+MODULE_SCOPE Tcl_Obj *
+ ClockMCGet(ClockFmtScnCmdArgs *opts, int mcKey);
+MODULE_SCOPE Tcl_Obj *
+ ClockMCGetListIdxDict(ClockFmtScnCmdArgs *opts, int mcKey);
+
/* tclClockFmt.c module declarations */
MODULE_SCOPE ClockFmtScnStorage *