diff options
| author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2023-11-23 13:25:45 (GMT) |
|---|---|---|
| committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2023-11-23 13:25:45 (GMT) |
| commit | fefd5e71dcb3969e41112b186b2d30918ad62010 (patch) | |
| tree | c7f8968d3f2a6dbed22973a4b87d5c438b350a26 /generic | |
| parent | 097954529a4f7cbc2bba17841f07a4283b68f1cc (diff) | |
| parent | 613ad6861bdef8e2bfcde5630c0b34af183c6f56 (diff) | |
| download | tcl-fefd5e71dcb3969e41112b186b2d30918ad62010.zip tcl-fefd5e71dcb3969e41112b186b2d30918ad62010.tar.gz tcl-fefd5e71dcb3969e41112b186b2d30918ad62010.tar.bz2 | |
Merge 8.7
Diffstat (limited to 'generic')
| -rw-r--r-- | generic/regc_lex.c | 5 | ||||
| -rw-r--r-- | generic/tclClock.c | 2 | ||||
| -rw-r--r-- | generic/tclIO.c | 47 | ||||
| -rw-r--r-- | generic/tclIOCmd.c | 10 | ||||
| -rw-r--r-- | generic/tclInt.h | 1 | ||||
| -rw-r--r-- | generic/tclInterp.c | 3 | ||||
| -rw-r--r-- | generic/tclOODefineCmds.c | 44 | ||||
| -rw-r--r-- | generic/tclTest.c | 7 | ||||
| -rw-r--r-- | generic/tclTestObj.c | 6 | ||||
| -rw-r--r-- | generic/tclZipfs.c | 116 |
10 files changed, 161 insertions, 80 deletions
diff --git a/generic/regc_lex.c b/generic/regc_lex.c index eb068b4..28ae821 100644 --- a/generic/regc_lex.c +++ b/generic/regc_lex.c @@ -843,11 +843,6 @@ lexescape( if (ISERR()) { FAILW(REG_EESCAPE); } - if (i > 0xFFFF) { - /* TODO: output a Surrogate pair - */ - i = 0xFFFD; - } RETV(PLAIN, (uchr) i); break; case CHR('v'): diff --git a/generic/tclClock.c b/generic/tclClock.c index ab6d23f..228937e 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -894,7 +894,7 @@ ConvertLocalToUTCUsingC( Tcl_MutexLock(&clockMutex); errno = 0; fields->seconds = (Tcl_WideInt) mktime(&timeVal); - localErrno = errno; + localErrno = (fields->seconds == -1) ? errno : 0; Tcl_MutexUnlock(&clockMutex); /* diff --git a/generic/tclIO.c b/generic/tclIO.c index bc1b1c6..3b36457 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -4934,7 +4934,7 @@ Tcl_GetsObj( * two times, as gs.bytesWrote is not 0 on the first pass. This feels * once to much, as the data is anyway not used. */ - + /* Set eol to the position that caused the encoding error, and then * continue to gotEOL, which stores the data that was decoded * without error to objPtr. This allows the caller to do something @@ -7616,6 +7616,33 @@ Tcl_Eof( return GotFlag(statePtr, CHANNEL_EOF) ? 1 : 0; } + +/* + *---------------------------------------------------------------------- + * + * TclChannelGetBlockingMode -- + * + * Returns 1 if the channel is in blocking mode (default), 0 otherwise. + * + * Results: + * 1 or 0, always. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclChannelGetBlockingMode( + Tcl_Channel chan) +{ + ChannelState *statePtr = ((Channel *) chan)->state; + /* State of real channel structure. */ + + return GotFlag(statePtr, CHANNEL_NONBLOCKING) ? 0 : 1; +} + /* *---------------------------------------------------------------------- * @@ -9802,6 +9829,7 @@ CopyData( ChannelState *inStatePtr, *outStatePtr; int result = TCL_OK; Tcl_Size sizeb; + Tcl_Size sizePart; Tcl_WideInt total; int size; const char *buffer; @@ -9888,6 +9916,23 @@ CopyData( size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb, !GotFlag(inStatePtr, CHANNEL_NONBLOCKING) ,0 /* No append */); + /* + * In case of a recoverable encoding error, any data before + * the error should be written. This data is in the bufObj. + * Program flow for this case: + * - Check, if there are any remaining bytes to write + * - If yes, simulate a successful read to write them out + * - Come back here by the outer loop and read again + * - Do not enter in the if below, as there are no pending + * writes + * - Fail below with a read error + */ + if (size < 0 && Tcl_GetErrno() == EILSEQ) { + Tcl_GetStringFromObj(bufObj, &sizePart); + if (sizePart > 0) { + size = sizePart; + } + } } underflow = (size >= 0) && (size < sizeb); /* Input underflow */ } diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c index 938fa01..9667419 100644 --- a/generic/tclIOCmd.c +++ b/generic/tclIOCmd.c @@ -459,7 +459,12 @@ Tcl_ReadObjCmd( TclChannelPreserve(chan); charactersRead = Tcl_ReadChars(chan, resultPtr, toRead, 0); if (charactersRead == TCL_IO_FAILURE) { - Tcl_DecrRefCount(resultPtr); + Tcl_Obj *returnOptsPtr = NULL; + if (TclChannelGetBlockingMode(chan)) { + returnOptsPtr = Tcl_NewDictObj(); + Tcl_DictObjPut(NULL, returnOptsPtr, Tcl_NewStringObj("-data", -1), + resultPtr); + } /* * TIP #219. * Capture error messages put by the driver into the bypass area and @@ -473,6 +478,9 @@ Tcl_ReadObjCmd( TclGetString(chanObjPtr), Tcl_PosixError(interp))); } TclChannelRelease(chan); + if (returnOptsPtr) { + Tcl_SetReturnOptions(interp, returnOptsPtr); + } return TCL_ERROR; } diff --git a/generic/tclInt.h b/generic/tclInt.h index 3d8a702..f696ad2 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -3112,6 +3112,7 @@ MODULE_SCOPE int TclByteArrayMatch(const unsigned char *string, MODULE_SCOPE double TclCeil(const void *a); MODULE_SCOPE void TclChannelPreserve(Tcl_Channel chan); MODULE_SCOPE void TclChannelRelease(Tcl_Channel chan); +MODULE_SCOPE int TclChannelGetBlockingMode(Tcl_Channel chan); MODULE_SCOPE int TclCheckArrayTraces(Tcl_Interp *interp, Var *varPtr, Var *arrayPtr, Tcl_Obj *name, int index); MODULE_SCOPE int TclCheckBadOctal(Tcl_Interp *interp, diff --git a/generic/tclInterp.c b/generic/tclInterp.c index b023615..3d2c009 100644 --- a/generic/tclInterp.c +++ b/generic/tclInterp.c @@ -402,6 +402,7 @@ Tcl_Init( "if {$tail eq [info tclversion]} continue\n" "file join [file dirname $env(TCL_LIBRARY)] tcl[info tclversion]}\n" " }\n" +" lappend scripts {::tcl::zipfs::tcl_library_init}\n" " if {[info exists tclDefaultLibrary]} {\n" " lappend scripts {set tclDefaultLibrary}\n" " } else {\n" @@ -3603,7 +3604,7 @@ static void WrapFree( void *ptr) { - Tcl_Free(ptr); + ckfree(ptr); } void diff --git a/generic/tclOODefineCmds.c b/generic/tclOODefineCmds.c index 034c877..5f10475 100644 --- a/generic/tclOODefineCmds.c +++ b/generic/tclOODefineCmds.c @@ -2455,9 +2455,13 @@ ClassMixinSet( Tcl_Obj *const *objv) { Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp); - int mixinc, i; + int mixinc, i, isNew; Tcl_Obj **mixinv; - Class **mixins; + Class **mixins;; /* The references to the classes to actually + * install. */ + Tcl_HashTable uniqueCheck; /* Note that this hash table is just used as a + * set of class references; it has no payload + * values and keys are always pointers. */ if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) { Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv, @@ -2479,6 +2483,7 @@ ClassMixinSet( } mixins = (Class **)TclStackAlloc(interp, sizeof(Class *) * mixinc); + Tcl_InitHashTable(&uniqueCheck, TCL_ONE_WORD_KEYS); for (i = 0; i < mixinc; i++) { mixins[i] = GetClassInOuterContext(interp, mixinv[i], @@ -2487,6 +2492,13 @@ ClassMixinSet( i--; goto freeAndError; } + (void) Tcl_CreateHashEntry(&uniqueCheck, (void *) mixins[i], &isNew); + if (!isNew) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "class should only be a direct mixin once", -1)); + Tcl_SetErrorCode(interp, "TCL", "OO", "REPETITIOUS",NULL); + goto freeAndError; + } if (TclOOIsReachable(oPtr->classPtr, mixins[i])) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "may not mix a class into itself", -1)); @@ -2496,10 +2508,12 @@ ClassMixinSet( } TclOOClassSetMixins(interp, oPtr->classPtr, mixinc, mixins); + Tcl_DeleteHashTable(&uniqueCheck); TclStackFree(interp, mixins); return TCL_OK; freeAndError: + Tcl_DeleteHashTable(&uniqueCheck); TclStackFree(interp, mixins); return TCL_ERROR; } @@ -2906,10 +2920,13 @@ ObjMixinSet( Tcl_Obj *const *objv) { Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp); - int mixinc; + int mixinc, i, isNew; Tcl_Obj **mixinv; - Class **mixins; - int i; + Class **mixins; /* The references to the classes to actually + * install. */ + Tcl_HashTable uniqueCheck; /* Note that this hash table is just used as a + * set of class references; it has no payload + * values and keys are always pointers. */ if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) { Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv, @@ -2925,19 +2942,32 @@ ObjMixinSet( } mixins = (Class **)TclStackAlloc(interp, sizeof(Class *) * mixinc); + Tcl_InitHashTable(&uniqueCheck, TCL_ONE_WORD_KEYS); for (i = 0; i < mixinc; i++) { mixins[i] = GetClassInOuterContext(interp, mixinv[i], "may only mix in classes"); if (mixins[i] == NULL) { - TclStackFree(interp, mixins); - return TCL_ERROR; + goto freeAndError; + } + (void) Tcl_CreateHashEntry(&uniqueCheck, (void *) mixins[i], &isNew); + if (!isNew) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "class should only be a direct mixin once", -1)); + Tcl_SetErrorCode(interp, "TCL", "OO", "REPETITIOUS",NULL); + goto freeAndError; } } TclOOObjectSetMixins(oPtr, mixinc, mixins); TclStackFree(interp, mixins); + Tcl_DeleteHashTable(&uniqueCheck); return TCL_OK; + + freeAndError: + TclStackFree(interp, mixins); + Tcl_DeleteHashTable(&uniqueCheck); + return TCL_ERROR; } /* diff --git a/generic/tclTest.c b/generic/tclTest.c index efa045e..02e1fac 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -2086,7 +2086,6 @@ static int UtfExtWrapper( } flagMap[] = { {"start", TCL_ENCODING_START}, {"end", TCL_ENCODING_END}, - {"stoponerror", TCL_ENCODING_PROFILE_STRICT}, {"noterminate", TCL_ENCODING_NO_TERMINATE}, {"charlimit", TCL_ENCODING_CHAR_LIMIT}, {"profiletcl8", TCL_ENCODING_PROFILE_TCL8}, @@ -3813,7 +3812,7 @@ TestlistrepCmd( Tcl_Obj *const objv[]) /* Argument objects. */ { /* Subcommands supported by this command */ - const char* subcommands[] = { + static const char *const subcommands[] = { "new", "describe", "config", @@ -4624,11 +4623,11 @@ TestregexpObjCmd( } else { if (ii == TCL_INDEX_NONE) { TclRegExpRangeUniChar(regExpr, ii, &start, &end); - newPtr = Tcl_GetRange(objPtr, start, end); + newPtr = TclGetRange(objPtr, start, end); } else if (ii > info.nsubs || info.matches[ii].end <= 0) { newPtr = Tcl_NewObj(); } else { - newPtr = Tcl_GetRange(objPtr, info.matches[ii].start, + newPtr = TclGetRange(objPtr, info.matches[ii].start, info.matches[ii].end - 1); } } diff --git a/generic/tclTestObj.c b/generic/tclTestObj.c index 3b958dd..9f31cff 100644 --- a/generic/tclTestObj.c +++ b/generic/tclTestObj.c @@ -153,7 +153,7 @@ TestbignumobjCmd( int objc, /* Argument count */ Tcl_Obj *const objv[]) /* Argument vector */ { - const char *const subcmds[] = { + static const char *const subcmds[] = { "set", "get", "mult10", "div10", "iseven", "radixsize", NULL }; enum options { @@ -887,7 +887,7 @@ TestlistobjCmd( Tcl_Obj *const objv[]) /* Argument objects */ { /* Subcommands supported by this command */ - const char* const subcommands[] = { + static const char* const subcommands[] = { "set", "get", "replace", @@ -1062,7 +1062,7 @@ TestobjCmd( int i; const Tcl_ObjType *targetType; Tcl_Obj **varPtr; - const char *subcommands[] = { + static const char *const subcommands[] = { "freeallvars", "bug3598580", "types", "objtype", "newobj", "set", "assign", "convert", "duplicate", diff --git a/generic/tclZipfs.c b/generic/tclZipfs.c index adabcda..5df300a 100644 --- a/generic/tclZipfs.c +++ b/generic/tclZipfs.c @@ -91,17 +91,6 @@ static const z_crc_t* crc32tab; #define ZIPFS_VOLUME_LEN 9 #define ZIPFS_APP_MOUNT ZIPFS_VOLUME "app" #define ZIPFS_ZIP_MOUNT ZIPFS_VOLUME "lib/tcl" - -#define ZIPFS_SCRIPT_PREFIX "set ::tcl_library " -#define ZIPFS_TCL_LIBRARY_1 ZIPFS_APP_MOUNT "/tcl_library" -#define ZIPFS_INIT_SCRIPT_1 ZIPFS_SCRIPT_PREFIX ZIPFS_TCL_LIBRARY_1 - -#define ZIPFS_TCL_LIBRARY_2 ZIPFS_ZIP_MOUNT -#define ZIPFS_INIT_SCRIPT_2 ZIPFS_SCRIPT_PREFIX ZIPFS_TCL_LIBRARY_2 - -#define ZIPFS_TCL_LIBRARY_3 ZIPFS_ZIP_MOUNT "/tcl_library" -#define ZIPFS_INIT_SCRIPT_3 ZIPFS_SCRIPT_PREFIX ZIPFS_TCL_LIBRARY_3 - #define ZIPFS_FALLBACK_ENCODING "cp437" /* @@ -324,7 +313,6 @@ static const char pwrot[17] = "\x10\x90\x50\xD0\x30\xB0\x70\xF0"; static const char *zipfs_literal_tcl_library = NULL; -static const char *zipfs_init_script = NULL; /* Function prototypes */ @@ -4243,28 +4231,6 @@ ScriptLibrarySetup( Tcl_Obj *libDirObj = Tcl_NewStringObj(dirName, -1); Tcl_Obj *subDirObj, *searchPathObj; - /* - * We know where the init.tcl is located in the attached script library - * archive. Use a pre-init script to tell every Tcl interp as it gets - * created where that is, so none of them need to construct and then - * iterate through some search path. That's the literal documented - * purpose of Tcl_SetPreInitScript(). Use it. - * - * TODO: Examine why we need so many variations and eliminate as many - * as possible. - */ - - if (0 == strcmp(zipfs_literal_tcl_library, ZIPFS_TCL_LIBRARY_1)) { - zipfs_init_script = ZIPFS_INIT_SCRIPT_1; - } else if (0 == strcmp(zipfs_literal_tcl_library, ZIPFS_TCL_LIBRARY_2)) { - zipfs_init_script = ZIPFS_INIT_SCRIPT_2; - } else if (0 == strcmp(zipfs_literal_tcl_library, ZIPFS_TCL_LIBRARY_3)) { - zipfs_init_script = ZIPFS_INIT_SCRIPT_3; - } - if (zipfs_init_script) { - Tcl_SetPreInitScript(zipfs_init_script); - } - TclNewLiteralStringObj(subDirObj, "encoding"); Tcl_IncrRefCount(subDirObj); TclNewObj(searchPathObj); @@ -4302,12 +4268,13 @@ TclZipfs_TclLibrary(void) * Look for the library file system within the executable. */ - vfsInitScript = Tcl_NewStringObj(ZIPFS_TCL_LIBRARY_1 "/init.tcl", -1); + vfsInitScript = Tcl_NewStringObj(ZIPFS_APP_MOUNT "/tcl_library/init.tcl", + -1); Tcl_IncrRefCount(vfsInitScript); found = Tcl_FSAccess(vfsInitScript, F_OK); Tcl_DecrRefCount(vfsInitScript); if (found == TCL_OK) { - zipfs_literal_tcl_library = ZIPFS_TCL_LIBRARY_1; + zipfs_literal_tcl_library = ZIPFS_APP_MOUNT "/tcl_library"; return ScriptLibrarySetup(zipfs_literal_tcl_library); } @@ -4356,6 +4323,44 @@ TclZipfs_TclLibrary(void) /* *------------------------------------------------------------------------- * + * ZipFSTclLibraryObjCmd -- + * + * This procedure is invoked to process the + * [::tcl::zipfs::tcl_library_init] command, usually called during the + * execution of Tcl's interpreter startup. It returns the root that Tcl's + * library files are mounted under. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * May initialise the cache of where such library files are to be found. + * This cache is never cleared. + * + *------------------------------------------------------------------------- + */ + +static int +ZipFSTclLibraryObjCmd( + TCL_UNUSED(void *), + Tcl_Interp *interp, /* Current interpreter. */ + TCL_UNUSED(int) /*objc*/, + TCL_UNUSED(Tcl_Obj *const *)) /*objv*/ +{ + if (!Tcl_IsSafe(interp)) { + Tcl_Obj *pResult = TclZipfs_TclLibrary(); + + if (!pResult) { + TclNewObj(pResult); + } + Tcl_SetObjResult(interp, pResult); + } + return TCL_OK; +} + +/* + *------------------------------------------------------------------------- + * * ZipChannelClose -- * * This function is called to close a channel. @@ -6248,6 +6253,8 @@ TclZipfs_Init( Tcl_GetEnsembleMappingDict(NULL, ensemble, &mapObj); Tcl_DictObjPut(NULL, mapObj, Tcl_NewStringObj("find", -1), Tcl_NewStringObj("::tcl::zipfs::find", -1)); + Tcl_CreateObjCommand(interp, "::tcl::zipfs::tcl_library_init", + ZipFSTclLibraryObjCmd, NULL, NULL); Tcl_PkgProvide(interp, "tcl::zipfs", "2.0"); } return TCL_OK; @@ -6276,21 +6283,22 @@ ZipfsAppHookFindTclInit( return TCL_ERROR; } - TclNewLiteralStringObj(vfsInitScript, ZIPFS_TCL_LIBRARY_2 "/init.tcl"); + TclNewLiteralStringObj(vfsInitScript, ZIPFS_ZIP_MOUNT "/init.tcl"); Tcl_IncrRefCount(vfsInitScript); found = Tcl_FSAccess(vfsInitScript, F_OK); Tcl_DecrRefCount(vfsInitScript); if (found == 0) { - zipfs_literal_tcl_library = ZIPFS_TCL_LIBRARY_2; + zipfs_literal_tcl_library = ZIPFS_ZIP_MOUNT; return TCL_OK; } - TclNewLiteralStringObj(vfsInitScript, ZIPFS_TCL_LIBRARY_3 "/init.tcl"); + TclNewLiteralStringObj(vfsInitScript, + ZIPFS_ZIP_MOUNT "/tcl_library/init.tcl"); Tcl_IncrRefCount(vfsInitScript); found = Tcl_FSAccess(vfsInitScript, F_OK); Tcl_DecrRefCount(vfsInitScript); if (found == 0) { - zipfs_literal_tcl_library = ZIPFS_TCL_LIBRARY_3; + zipfs_literal_tcl_library = ZIPFS_ZIP_MOUNT "/tcl_library"; return TCL_OK; } @@ -6407,13 +6415,12 @@ TclZipfs_AppHook( if (!zipfs_literal_tcl_library) { TclNewLiteralStringObj(vfsInitScript, - ZIPFS_TCL_LIBRARY_1 "/init.tcl"); + ZIPFS_APP_MOUNT "/tcl_library/init.tcl"); Tcl_IncrRefCount(vfsInitScript); found = Tcl_FSAccess(vfsInitScript, F_OK); Tcl_DecrRefCount(vfsInitScript); if (found == TCL_OK) { - zipfs_literal_tcl_library = ZIPFS_TCL_LIBRARY_1; - Tcl_DecrRefCount(TclZipfs_TclLibrary()); + zipfs_literal_tcl_library = ZIPFS_APP_MOUNT "/tcl_library"; return version; } } @@ -6440,9 +6447,9 @@ TclZipfs_AppHook( * wants it. */ - Tcl_DecrRefCount(TclZipfs_TclLibrary()); + TclZipfs_TclLibrary(); TclNewLiteralStringObj(vfsInitScript, - ZIPFS_TCL_LIBRARY_3 "install.tcl"); + ZIPFS_ZIP_MOUNT "/tcl_library/install.tcl"); Tcl_IncrRefCount(vfsInitScript); if (Tcl_FSAccess(vfsInitScript, F_OK) == 0) { Tcl_SetStartupScript(vfsInitScript, NULL); @@ -6452,17 +6459,6 @@ TclZipfs_AppHook( int found; Tcl_Obj *vfsInitScript; - /* Set Tcl Encodings */ - TclNewLiteralStringObj(vfsInitScript, - ZIPFS_TCL_LIBRARY_1 "/init.tcl"); - Tcl_IncrRefCount(vfsInitScript); - found = Tcl_FSAccess(vfsInitScript, F_OK); - Tcl_DecrRefCount(vfsInitScript); - if (found == TCL_OK) { - zipfs_literal_tcl_library = ZIPFS_TCL_LIBRARY_1; - Tcl_DecrRefCount(TclZipfs_TclLibrary()); - } - TclNewLiteralStringObj(vfsInitScript, ZIPFS_APP_MOUNT "/main.tcl"); Tcl_IncrRefCount(vfsInitScript); if (Tcl_FSAccess(vfsInitScript, F_OK) == 0) { @@ -6474,8 +6470,14 @@ TclZipfs_AppHook( } else { Tcl_DecrRefCount(vfsInitScript); } - + /* Set Tcl Encodings */ + TclNewLiteralStringObj(vfsInitScript, + ZIPFS_APP_MOUNT "/tcl_library/init.tcl"); + Tcl_IncrRefCount(vfsInitScript); + found = Tcl_FSAccess(vfsInitScript, F_OK); + Tcl_DecrRefCount(vfsInitScript); if (found == TCL_OK) { + zipfs_literal_tcl_library = ZIPFS_APP_MOUNT "/tcl_library"; return version; } } |
