diff options
author | sebres <sebres@users.sourceforge.net> | 2017-01-10 22:28:25 (GMT) |
---|---|---|
committer | sebres <sebres@users.sourceforge.net> | 2017-01-10 22:28:25 (GMT) |
commit | 5afae758b98de2da47b30d6aa4b40a5d5a604fbc (patch) | |
tree | 9bea9e914a912fb419e1f480d397197c4362a28a | |
parent | 7b6cd1089c2d3a6eeb8f12b106af40c18017c8f3 (diff) | |
download | tcl-5afae758b98de2da47b30d6aa4b40a5d5a604fbc.zip tcl-5afae758b98de2da47b30d6aa4b40a5d5a604fbc.tar.gz tcl-5afae758b98de2da47b30d6aa4b40a5d5a604fbc.tar.bz2 |
improve LocalizeFormat, internal caching of localized formats inside msgcat for locale and format objects
smart reference introduced in dict (smart pointer with 0 object reference but increase dict-reference, provide changeable locale dict)
-rw-r--r-- | generic/tclClock.c | 64 | ||||
-rw-r--r-- | generic/tclClockFmt.c | 75 | ||||
-rw-r--r-- | generic/tclDate.h | 10 | ||||
-rw-r--r-- | generic/tclDictObj.c | 122 | ||||
-rw-r--r-- | generic/tclInt.h | 1 | ||||
-rwxr-xr-x | library/clock.tcl | 83 | ||||
-rw-r--r-- | library/init.tcl | 2 | ||||
-rw-r--r-- | library/msgcat/msgcat.tcl | 3 |
8 files changed, 269 insertions, 91 deletions
diff --git a/generic/tclClock.c b/generic/tclClock.c index 166a4b3..e066812 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -60,6 +60,7 @@ typedef enum ClockLiteral { LIT_GETSYSTEMTIMEZONE, LIT_SETUPTIMEZONE, LIT_MCGET, LIT_TCL_CLOCK, + LIT_LOCALIZE_FORMAT, #if 0 LIT_FREESCAN, #endif @@ -82,7 +83,8 @@ static const char *const Literals[] = { "::tcl::clock::TZData", "::tcl::clock::GetSystemTimeZone", "::tcl::clock::SetupTimeZone", - "::msgcat::mcget", "::tcl::clock" + "::msgcat::mcget", "::tcl::clock", + "::tcl::clock::LocalizeFormat" #if 0 "::tcl::clock::FreeScan" #endif @@ -487,7 +489,6 @@ MODULE_SCOPE Tcl_Obj * ClockMCDict(ClockFmtScnCmdArgs *opts) { ClockClientData *dataPtr = opts->clientData; - Tcl_Obj *callargs[3]; /* if dict not yet retrieved */ if (opts->mcDictObj == NULL) { @@ -518,6 +519,7 @@ ClockMCDict(ClockFmtScnCmdArgs *opts) } if (opts->mcDictObj == NULL) { + Tcl_Obj *callargs[3]; /* get msgcat dictionary - ::msgcat::mcget ::tcl::clock locale */ callargs[0] = dataPtr->literals[LIT_MCGET]; callargs[1] = dataPtr->literals[LIT_TCL_CLOCK]; @@ -528,6 +530,11 @@ ClockMCDict(ClockFmtScnCmdArgs *opts) } opts->mcDictObj = Tcl_GetObjResult(opts->interp); + /* be sure that object reference not increases (dict changeable) */ + if (opts->mcDictObj->refCount > 0) { + /* smart reference (shared dict as object with no ref-counter) */ + opts->mcDictObj = Tcl_DictObjSmartRef(opts->interp, opts->mcDictObj); + } if ( opts->localeObj == dataPtr->CurrentLocale ) { Tcl_SetObjRef(dataPtr->CurrentLocaleDict, opts->mcDictObj); } else { @@ -535,6 +542,7 @@ ClockMCDict(ClockFmtScnCmdArgs *opts) Tcl_UnsetObjRef(dataPtr->LastUnnormUsedLocale); Tcl_SetObjRef(dataPtr->LastUsedLocaleDict, opts->mcDictObj); } + Tcl_ResetResult(opts->interp); } } @@ -626,6 +634,56 @@ ClockMCGetListIdxDict( return valObj; } +MODULE_SCOPE Tcl_Obj * +ClockLocalizeFormat( + ClockFmtScnCmdArgs *opts) +{ + ClockClientData *dataPtr = opts->clientData; + Tcl_Obj *valObj, *keyObj; + + keyObj = ClockFrmObjGetLocFmtKey(opts->interp, opts->formatObj); + + if (opts->mcDictObj == NULL) { + ClockMCDict(opts); + if (opts->mcDictObj == NULL) + return NULL; + } + + /* try to find in cache within mc-catalog */ + if (Tcl_DictObjGet(NULL, opts->mcDictObj, + keyObj, &valObj) != TCL_OK) { + return NULL; + } + if (valObj == NULL) { + Tcl_Obj *callargs[4]; + /* call LocalizeFormat locale format fmtkey */ + callargs[0] = dataPtr->literals[LIT_LOCALIZE_FORMAT]; + callargs[1] = opts->localeObj; + callargs[2] = opts->formatObj; + callargs[3] = keyObj; + Tcl_IncrRefCount(keyObj); + if (Tcl_EvalObjv(opts->interp, 4, callargs, 0) != TCL_OK + ) { + Tcl_DecrRefCount(keyObj); + return NULL; + } + + valObj = Tcl_GetObjResult(opts->interp); + + if (Tcl_DictObjPut(opts->interp, opts->mcDictObj, + keyObj, valObj) != TCL_OK + ) { + Tcl_DecrRefCount(keyObj); + return NULL; + } + + Tcl_DecrRefCount(keyObj); + Tcl_ResetResult(opts->interp); + } + + return (opts->formatObj = valObj); +} + /* *---------------------------------------------------------------------- */ @@ -2936,7 +2994,7 @@ ClockScanObjCmd( #endif else { /* Use compiled version of Scan - */ - + ret = ClockScan(clientData, interp, info, objv[1], &opts); } diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index a3c7f20..184b52a 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -308,14 +308,14 @@ Tcl_ObjType ClockFmtObjType = { #define ObjClockFmtScn(objPtr) \ (ClockFmtScnStorage *)objPtr->internalRep.twoPtrValue.ptr1; -#define SetObjLitStorage(objPtr, lit) \ - objPtr->internalRep.twoPtrValue.ptr2 = lit -#define ObjLitStorage(objPtr) \ - (ClockLitStorage *)objPtr->internalRep.twoPtrValue.ptr2; - -#define ClockFmtObj_SetObjIntRep(objPtr, fss, lit) \ - objPtr->internalRep.twoPtrValue.ptr1 = fss, \ - objPtr->internalRep.twoPtrValue.ptr2 = lit, \ +#define SetObjLocFmtKey(objPtr, key) \ + Tcl_InitObjRef((Tcl_Obj *)objPtr->internalRep.twoPtrValue.ptr2, key) +#define ObjLocFmtKey(objPtr) \ + ((Tcl_Obj *)objPtr->internalRep.twoPtrValue.ptr2) + +#define ClockFmtObj_SetObjIntRep(objPtr, fss, key) \ + objPtr->internalRep.twoPtrValue.ptr1 = fss; \ + Tcl_InitObjRef((Tcl_Obj *)objPtr->internalRep.twoPtrValue.ptr2, key); \ objPtr->typePtr = &ClockFmtObjType; /* @@ -327,7 +327,6 @@ ClockFmtObj_DupInternalRep(srcPtr, copyPtr) Tcl_Obj *copyPtr; { ClockFmtScnStorage *fss = ObjClockFmtScn(srcPtr); - // ClockLitStorage *lit = ObjLitStorage(srcPtr); if (fss != NULL) { Tcl_MutexLock(&ClockFmtMutex); @@ -335,7 +334,7 @@ ClockFmtObj_DupInternalRep(srcPtr, copyPtr) Tcl_MutexUnlock(&ClockFmtMutex); } - ClockFmtObj_SetObjIntRep(copyPtr, fss, NULL); + ClockFmtObj_SetObjIntRep(copyPtr, fss, ObjLocFmtKey(srcPtr)); /* if no format representation, dup string representation */ if (fss == NULL) { @@ -352,7 +351,6 @@ ClockFmtObj_FreeInternalRep(objPtr) Tcl_Obj *objPtr; { ClockFmtScnStorage *fss = ObjClockFmtScn(objPtr); - // ClockLitStorage *lit = ObjLitStorage(objPtr); if (fss != NULL) { Tcl_MutexLock(&ClockFmtMutex); /* decrement object reference count of format/scan storage */ @@ -368,7 +366,7 @@ ClockFmtObj_FreeInternalRep(objPtr) Tcl_MutexUnlock(&ClockFmtMutex); } SetObjClockFmtScn(objPtr, NULL); - SetObjLitStorage(objPtr, NULL); + Tcl_UnsetObjRef(ObjLocFmtKey(objPtr)); objPtr->typePtr = NULL; }; /* @@ -379,16 +377,18 @@ ClockFmtObj_SetFromAny(interp, objPtr) Tcl_Interp *interp; Tcl_Obj *objPtr; { - ClockFmtScnStorage *fss; - const char *strFmt = TclGetString(objPtr); - - if (!strFmt || (fss = FindOrCreateFmtScnStorage(interp, strFmt)) == NULL) { - return TCL_ERROR; - } - + /* validate string representation before free old internal represenation */ + (void)TclGetString(objPtr); + + /* free old internal represenation */ if (objPtr->typePtr && objPtr->typePtr->freeIntRepProc) objPtr->typePtr->freeIntRepProc(objPtr); - ClockFmtObj_SetObjIntRep(objPtr, fss, NULL); + + /* initial state of format object */ + objPtr->internalRep.twoPtrValue.ptr1 = NULL; + objPtr->internalRep.twoPtrValue.ptr2 = NULL; + objPtr->typePtr = &ClockFmtObjType; + return TCL_OK; }; /* @@ -415,6 +415,33 @@ ClockFmtObj_UpdateString(objPtr) /* *---------------------------------------------------------------------- + */ +MODULE_SCOPE Tcl_Obj* +ClockFrmObjGetLocFmtKey( + Tcl_Interp *interp, + Tcl_Obj *objPtr) +{ + Tcl_Obj *keyObj; + + if (objPtr->typePtr != &ClockFmtObjType) { + if (ClockFmtObj_SetFromAny(interp, objPtr) != TCL_OK) { + return NULL; + } + } + + keyObj = ObjLocFmtKey(objPtr); + if (keyObj) { + return keyObj; + } + + keyObj = Tcl_ObjPrintf("FMT_%s", TclGetString(objPtr)); + SetObjLocFmtKey(objPtr, keyObj); + + return keyObj; +} + +/* + *---------------------------------------------------------------------- * * Tcl_GetClockFrmScnFromObj -- * @@ -731,7 +758,7 @@ static ClockScanTokenMap ScnWordTokenMap = { ClockScanToken * ClockGetOrParseScanFormat( Tcl_Interp *interp, /* Tcl interpreter */ - Tcl_Obj *formatObj) /* Format container */ + Tcl_Obj *formatObj) /* Format container */ { ClockFmtScnStorage *fss; ClockScanToken *tok; @@ -889,6 +916,12 @@ ClockScan( unsigned short int flags = 0; int ret = TCL_ERROR; + /* get localized format */ + + if (ClockLocalizeFormat(opts) == NULL) { + return TCL_ERROR; + } + if ((tok = ClockGetOrParseScanFormat(interp, opts->formatObj)) == NULL) { return TCL_ERROR; } diff --git a/generic/tclDate.h b/generic/tclDate.h index 1c51a02..62fa693 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -345,10 +345,6 @@ typedef struct ClockFmtScnStorage { * stored by offset +sizeof(self) */ } ClockFmtScnStorage; -typedef struct ClockLitStorage { - int dummy; -} ClockLitStorage; - /* * Prototypes of module functions. */ @@ -366,9 +362,15 @@ MODULE_SCOPE Tcl_Obj * ClockMCGet(ClockFmtScnCmdArgs *opts, int mcKey); MODULE_SCOPE Tcl_Obj * ClockMCGetListIdxDict(ClockFmtScnCmdArgs *opts, int mcKey); +MODULE_SCOPE Tcl_Obj * + ClockLocalizeFormat(ClockFmtScnCmdArgs *opts); /* tclClockFmt.c module declarations */ +MODULE_SCOPE Tcl_Obj* + ClockFrmObjGetLocFmtKey(Tcl_Interp *interp, + Tcl_Obj *objPtr); + MODULE_SCOPE ClockFmtScnStorage * Tcl_GetClockFrmScnFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr); diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index 1115999..3944173 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -51,6 +51,8 @@ static int DictSetCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static int DictSizeCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); +static int DictSmartRefCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); static int DictUnsetCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static int DictUpdateCmd(ClientData dummy, Tcl_Interp *interp, @@ -98,6 +100,7 @@ static const EnsembleImplMap implementationMap[] = { {"replace", DictReplaceCmd, NULL, NULL, NULL, 0 }, {"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 }, {"size", DictSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 }, + {"smartref",DictSmartRefCmd,NULL, NULL, NULL, 0 }, {"unset", DictUnsetCmd, TclCompileDictUnsetCmd, NULL, NULL, 0 }, {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 }, {"values", DictValuesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 }, @@ -142,7 +145,7 @@ typedef struct Dict { * the entries in the order that they are * created. */ int epoch; /* Epoch counter */ - size_t refCount; /* Reference counter (see above) */ + int refcount; /* Reference counter (see above) */ Tcl_Obj *chain; /* Linked list used for invalidating the * string representations of updated nested * dictionaries. */ @@ -392,7 +395,7 @@ DupDictInternalRep( newDict->epoch = 0; newDict->chain = NULL; - newDict->refCount = 1; + newDict->refcount = 1; /* * Store in the object. @@ -427,7 +430,8 @@ FreeDictInternalRep( { Dict *dict = DICT(dictPtr); - if (dict->refCount-- <= 1) { + dict->refcount--; + if (dict->refcount <= 0) { DeleteDict(dict); } dictPtr->typePtr = NULL; @@ -712,7 +716,7 @@ SetDictFromAny( TclFreeIntRep(objPtr); dict->epoch = 0; dict->chain = NULL; - dict->refCount = 1; + dict->refcount = 1; DICT(objPtr) = dict; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = &tclDictType; @@ -1116,7 +1120,7 @@ Tcl_DictObjFirst( searchPtr->dictionaryPtr = (Tcl_Dict) dict; searchPtr->epoch = dict->epoch; searchPtr->next = cPtr->nextPtr; - dict->refCount++; + dict->refcount++; if (keyPtrPtr != NULL) { *keyPtrPtr = Tcl_GetHashKey(&dict->table, &cPtr->entry); } @@ -1230,7 +1234,8 @@ Tcl_DictObjDone( if (searchPtr->epoch != -1) { searchPtr->epoch = -1; dict = (Dict *) searchPtr->dictionaryPtr; - if (dict->refCount-- <= 1) { + dict->refcount--; + if (dict->refcount <= 0) { DeleteDict(dict); } } @@ -1382,7 +1387,7 @@ Tcl_NewDictObj(void) InitChainTable(dict); dict->epoch = 0; dict->chain = NULL; - dict->refCount = 1; + dict->refcount = 1; DICT(dictPtr) = dict; dictPtr->internalRep.twoPtrValue.ptr2 = NULL; dictPtr->typePtr = &tclDictType; @@ -1432,7 +1437,7 @@ Tcl_DbNewDictObj( InitChainTable(dict); dict->epoch = 0; dict->chain = NULL; - dict->refCount = 1; + dict->refcount = 1; DICT(dictPtr) = dict; dictPtr->internalRep.twoPtrValue.ptr2 = NULL; dictPtr->typePtr = &tclDictType; @@ -1957,6 +1962,77 @@ DictSizeCmd( /* *---------------------------------------------------------------------- + */ + +Tcl_Obj * +Tcl_DictObjSmartRef( + Tcl_Interp *interp, + Tcl_Obj *dictPtr) +{ + Tcl_Obj *result; + Dict *dict; + + if (dictPtr->typePtr != &tclDictType + && SetDictFromAny(interp, dictPtr) != TCL_OK) { + return NULL; + } + + dict = DICT(dictPtr); + + result = Tcl_NewObj(); + DICT(result) = dict; + dict->refcount++; + result->internalRep.twoPtrValue.ptr2 = NULL; + result->typePtr = &tclDictType; + + return result; +} + +/* + *---------------------------------------------------------------------- + * + * DictSmartRefCmd -- + * + * This function implements the "dict smartref" Tcl command. See the user + * documentation for details on what it does, and TIP#111 for the formal + * specification. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +static int +DictSmartRefCmd( + ClientData dummy, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const *objv) +{ + Tcl_Obj *result; + Dict *dict; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "dictionary"); + return TCL_ERROR; + } + + result = Tcl_DictObjSmartRef(interp, objv[1]); + if (result == NULL) { + return TCL_ERROR; + } + + Tcl_SetObjResult(interp, result); + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- * * DictExistsCmd -- * @@ -2280,7 +2356,7 @@ DictAppendCmd( Tcl_Obj *const *objv) { Tcl_Obj *dictPtr, *valuePtr, *resultPtr; - int allocatedDict = 0; + int i, allocatedDict = 0; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?value ...?"); @@ -2305,33 +2381,15 @@ DictAppendCmd( if ((objc > 3) || (valuePtr == NULL)) { /* Only go through append activites when something will change. */ - Tcl_Obj *appendObjPtr = NULL; - - if (objc > 3) { - /* Something to append */ - - if (objc == 4) { - appendObjPtr = objv[3]; - } else if (TCL_OK != TclStringCatObjv(interp, /* inPlace */ 1, - objc-3, objv+3, &appendObjPtr)) { - return TCL_ERROR; - } - } - if (appendObjPtr == NULL) { - /* => (objc == 3) => (valuePtr == NULL) */ + if (valuePtr == NULL) { TclNewObj(valuePtr); - } else if (valuePtr == NULL) { - valuePtr = appendObjPtr; - appendObjPtr = NULL; + } else if (Tcl_IsShared(valuePtr)) { + valuePtr = Tcl_DuplicateObj(valuePtr); } - if (appendObjPtr) { - if (Tcl_IsShared(valuePtr)) { - valuePtr = Tcl_DuplicateObj(valuePtr); - } - - Tcl_AppendObjToObj(valuePtr, appendObjPtr); + for (i=3 ; i<objc ; i++) { + Tcl_AppendObjToObj(valuePtr, objv[i]); } Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr); diff --git a/generic/tclInt.h b/generic/tclInt.h index 1b37d84..a569788 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2905,6 +2905,7 @@ MODULE_SCOPE int TclFindDictElement(Tcl_Interp *interp, const char *dict, int dictLength, const char **elementPtr, const char **nextPtr, int *sizePtr, int *literalPtr); +MODULE_SCOPE Tcl_Obj * Tcl_DictObjSmartRef(Tcl_Interp *interp, Tcl_Obj *); /* TIP #280 - Modified token based evulation, with line information. */ MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, int numBytes, int flags, int line, diff --git a/library/clock.tcl b/library/clock.tcl index b4632b1..4173174 100755 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -629,6 +629,8 @@ proc ::tcl::clock::Initialize {} { # Caches + variable LocaleFormats {}; # Dictionary with localized formats + variable LocaleNumeralCache {}; # Dictionary whose keys are locale # names and whose values are pairs # comprising regexes matching numerals @@ -2323,38 +2325,59 @@ proc ::tcl::clock::LoadWindowsDateTimeFormats { locale } { # #---------------------------------------------------------------------- -proc ::tcl::clock::LocalizeFormat { locale format } { +proc ::tcl::clock::LocalizeFormat { locale format {fmtkey {}} } { + variable LocaleFormats + + if { $fmtkey eq {} } { set fmtkey FMT_$format } + if { [catch { + set locfmt [dict get $LocaleFormats $locale $fmtkey] + }] } { - # message catalog key to cache this format - set key FORMAT_$format + # get map list cached or build it: + if { [catch { + set mlst [dict get $LocaleFormats $locale MLST] + }] } { + + # message catalog dictionary: + set mcd [::msgcat::mcget ::tcl::clock $locale] + + # Handle locale-dependent format groups by mapping them out of the format + # string. Note that the order of the [string map] operations is + # significant because later formats can refer to later ones; for example + # %c can refer to %X, which in turn can refer to %T. + + set mlst { + %% %% + %D %m/%d/%Y + %+ {%a %b %e %H:%M:%S %Z %Y} + } + lappend mlst %EY [string map $mlst [dict get $mcd LOCALE_YEAR_FORMAT]] + lappend mlst %T [string map $mlst [dict get $mcd TIME_FORMAT_24_SECS]] + lappend mlst %R [string map $mlst [dict get $mcd TIME_FORMAT_24]] + lappend mlst %r [string map $mlst [dict get $mcd TIME_FORMAT_12]] + lappend mlst %X [string map $mlst [dict get $mcd TIME_FORMAT]] + lappend mlst %EX [string map $mlst [dict get $mcd LOCALE_TIME_FORMAT]] + lappend mlst %x [string map $mlst [dict get $mcd DATE_FORMAT]] + lappend mlst %Ex [string map $mlst [dict get $mcd LOCALE_DATE_FORMAT]] + lappend mlst %c [string map $mlst [dict get $mcd DATE_TIME_FORMAT]] + lappend mlst %Ec [string map $mlst [dict get $mcd LOCALE_DATE_TIME_FORMAT]] + + dict set LocaleFormats $locale MLST $mlst + } - if { [::msgcat::mcexists -exactlocale -exactnamespace $key] } { - return [mc $key] - } - # Handle locale-dependent format groups by mapping them out of the format - # string. Note that the order of the [string map] operations is - # significant because later formats can refer to later ones; for example - # %c can refer to %X, which in turn can refer to %T. - - set list { - %% %% - %D %m/%d/%Y - %+ {%a %b %e %H:%M:%S %Z %Y} + # translate: + set locfmt [string map $mlst $format] + + # Save original format as long as possible, because of internal representation (performance) + if {$locfmt eq $format} { + set locfmt $format + } + + # cache it: + dict set LocaleFormats $locale $fmtkey $locfmt } - lappend list %EY [string map $list [mc LOCALE_YEAR_FORMAT]] - lappend list %T [string map $list [mc TIME_FORMAT_24_SECS]] - lappend list %R [string map $list [mc TIME_FORMAT_24]] - lappend list %r [string map $list [mc TIME_FORMAT_12]] - lappend list %X [string map $list [mc TIME_FORMAT]] - lappend list %EX [string map $list [mc LOCALE_TIME_FORMAT]] - lappend list %x [string map $list [mc DATE_FORMAT]] - lappend list %Ex [string map $list [mc LOCALE_DATE_FORMAT]] - lappend list %c [string map $list [mc DATE_TIME_FORMAT]] - lappend list %Ec [string map $list [mc LOCALE_DATE_TIME_FORMAT]] - set format [string map $list $format] - - ::msgcat::mcset $locale $key $format - return $format + + return $locfmt } #---------------------------------------------------------------------- @@ -4437,6 +4460,7 @@ proc ::tcl::clock::ChangeCurrentLocale {args} { proc ::tcl::clock::ClearCaches {} { variable FormatProc + variable LocaleFormats variable LocaleNumeralCache variable TimeZoneBad @@ -4451,6 +4475,7 @@ proc ::tcl::clock::ClearCaches {} { } unset -nocomplain FormatProc + set LocaleFormats {} set LocaleNumeralCache {} set TimeZoneBad {} InitTZData diff --git a/library/init.tcl b/library/init.tcl index 06a9459..ef0a84a 100644 --- a/library/init.tcl +++ b/library/init.tcl @@ -178,7 +178,7 @@ if {[interp issafe]} { # Auto-loading stubs for 'clock.tcl' - foreach cmd {add format SetupTimeZone GetSystemTimeZone __org_scan} { + foreach cmd {add format LocalizeFormat SetupTimeZone GetSystemTimeZone __org_scan} { proc ::tcl::clock::$cmd args { variable TclLibDir source -encoding utf-8 [file join $TclLibDir clock.tcl] diff --git a/library/msgcat/msgcat.tcl b/library/msgcat/msgcat.tcl index 3fd2cdb..a25f6c8 100644 --- a/library/msgcat/msgcat.tcl +++ b/library/msgcat/msgcat.tcl @@ -947,7 +947,8 @@ proc msgcat::Merge {ns locales} { } } dict set Merged $ns $loc $mrgcat - return $mrgcat + # return smart reference (shared dict as object with exact one ref-counter) + return [dict smartref $mrgcat] } # msgcat::Invoke -- |