diff options
-rw-r--r-- | doc/SetResult.3 | 2 | ||||
-rw-r--r-- | doc/file.n | 4 | ||||
-rw-r--r-- | generic/tclBasic.c | 21 | ||||
-rw-r--r-- | generic/tclCmdIL.c | 3 | ||||
-rw-r--r-- | generic/tclCmdMZ.c | 12 | ||||
-rw-r--r-- | generic/tclDictObj.c | 18 | ||||
-rw-r--r-- | generic/tclDisassemble.c | 135 | ||||
-rw-r--r-- | generic/tclEnsemble.c | 90 | ||||
-rw-r--r-- | generic/tclExecute.c | 2 | ||||
-rw-r--r-- | generic/tclIOUtil.c | 3 | ||||
-rw-r--r-- | generic/tclInt.h | 4 | ||||
-rw-r--r-- | generic/tclOO.c | 9 | ||||
-rw-r--r-- | generic/tclOOCall.c | 9 | ||||
-rw-r--r-- | generic/tclOOMethod.c | 6 | ||||
-rw-r--r-- | generic/tclPathObj.c | 10 | ||||
-rw-r--r-- | generic/tclTest.c | 3 | ||||
-rw-r--r-- | library/tcltest/tcltest.tcl | 4 | ||||
-rw-r--r-- | tests/cmdAH.test | 23 | ||||
-rw-r--r-- | tests/compile.test | 99 | ||||
-rw-r--r-- | tests/fileName.test | 14 | ||||
-rw-r--r-- | tests/namespace.test | 9 | ||||
-rw-r--r-- | tests/oo.test | 12 | ||||
-rwxr-xr-x | win/tclWinFile.c | 4 |
23 files changed, 352 insertions, 144 deletions
diff --git a/doc/SetResult.3 b/doc/SetResult.3 index dc8f487..e5b81d7 100644 --- a/doc/SetResult.3 +++ b/doc/SetResult.3 @@ -164,7 +164,7 @@ The source interpreter will have its result reset by this operation. .SH "DEPRECATED INTERFACES" .SS "OLD STRING PROCEDURES" .PP -Use of the following procedures (is deprecated +Use of the following procedures is deprecated since they manipulate the Tcl result as a string. Procedures such as \fBTcl_SetObjResult\fR that manipulate the result as a value @@ -162,7 +162,9 @@ returns \fB/home\fR (or something similar). \fBfile executable \fIname\fR . Returns \fB1\fR if file \fIname\fR is executable by the current user, -\fB0\fR otherwise. +\fB0\fR otherwise. On Windows, which does not have an executable attribute, +the command treats all directories and any files with extensions +\fBexe\fR, \fBcom\fR, \fBcmd\fR, \fBbat\fR or \fBps1\fR as executable. .TP \fBfile exists \fIname\fR . diff --git a/generic/tclBasic.c b/generic/tclBasic.c index b0c31cc..d6a460d 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -128,7 +128,7 @@ static void MathFuncWrongNumArgs(Tcl_Interp *interp, int expected, int actual, Tcl_Obj *const *objv); static Tcl_NRPostProc NRCoroutineCallerCallback; static Tcl_NRPostProc NRCoroutineExitCallback; -static int NRCommand(ClientData data[], Tcl_Interp *interp, int result); +static Tcl_NRPostProc NRCommand; static Tcl_ObjCmdProc OldMathFuncProc; static void OldMathFuncDeleteProc(ClientData clientData); @@ -146,7 +146,6 @@ static int TEOV_RunEnterTraces(Tcl_Interp *interp, Command **cmdPtrPtr, Tcl_Obj *commandPtr, int objc, Tcl_Obj *const objv[]); static Tcl_NRPostProc RewindCoroutineCallback; -static Tcl_NRPostProc TailcallCleanup; static Tcl_NRPostProc TEOEx_ByteCodeCallback; static Tcl_NRPostProc TEOEx_ListCallback; static Tcl_NRPostProc TEOV_Error; @@ -8371,7 +8370,7 @@ TclNRTailcallEval( * a now-gone namespace: cleanup and return. */ - TailcallCleanup(data, interp, result); + Tcl_DecrRefCount(listPtr); return result; } @@ -8380,18 +8379,26 @@ TclNRTailcallEval( */ TclMarkTailcall(interp); - TclNRAddCallback(interp, TailcallCleanup, listPtr, NULL, NULL,NULL); + TclNRAddCallback(interp, TclNRReleaseValues, listPtr, NULL, NULL,NULL); iPtr->lookupNsPtr = (Namespace *) nsPtr; return TclNREvalObjv(interp, objc-1, objv+1, 0, NULL); } -static int -TailcallCleanup( +int +TclNRReleaseValues( ClientData data[], Tcl_Interp *interp, int result) { - Tcl_DecrRefCount((Tcl_Obj *) data[0]); + int i = 0; + while (i < 4) { + if (data[i]) { + Tcl_DecrRefCount((Tcl_Obj *) data[i]); + } else { + break; + } + i++; + } return result; } diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index c93e593..0a1b4fe 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -105,8 +105,7 @@ typedef struct SortInfo { */ static int DictionaryCompare(const char *left, const char *right); -static int IfConditionCallback(ClientData data[], - Tcl_Interp *interp, int result); +static Tcl_NRPostProc IfConditionCallback; static int InfoArgsCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoBodyCmd(ClientData dummy, Tcl_Interp *interp, diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index 13f9e7d..885a0bc 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -22,14 +22,10 @@ static inline Tcl_Obj * During(Tcl_Interp *interp, int resultCode, Tcl_Obj *oldOptions, Tcl_Obj *errorInfo); -static int SwitchPostProc(ClientData data[], Tcl_Interp *interp, - int result); -static int TryPostBody(ClientData data[], Tcl_Interp *interp, - int result); -static int TryPostFinal(ClientData data[], Tcl_Interp *interp, - int result); -static int TryPostHandler(ClientData data[], Tcl_Interp *interp, - int result); +static Tcl_NRPostProc SwitchPostProc; +static Tcl_NRPostProc TryPostBody; +static Tcl_NRPostProc TryPostFinal; +static Tcl_NRPostProc TryPostHandler; static int UniCharIsAscii(int character); static int UniCharIsHexDigit(int character); diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index c8474e6..428173d 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -70,18 +70,12 @@ static inline void DeleteChainTable(struct Dict *dict); static inline Tcl_HashEntry *CreateChainEntry(struct Dict *dict, Tcl_Obj *keyPtr, int *newPtr); static inline int DeleteChainEntry(struct Dict *dict, Tcl_Obj *keyPtr); -static int FinalizeDictUpdate(ClientData data[], - Tcl_Interp *interp, int result); -static int FinalizeDictWith(ClientData data[], - Tcl_Interp *interp, int result); -static int DictForNRCmd(ClientData dummy, Tcl_Interp *interp, - int objc, Tcl_Obj *const *objv); -static int DictMapNRCmd(ClientData dummy, Tcl_Interp *interp, - int objc, Tcl_Obj *const *objv); -static int DictForLoopCallback(ClientData data[], - Tcl_Interp *interp, int result); -static int DictMapLoopCallback(ClientData data[], - Tcl_Interp *interp, int result); +static Tcl_NRPostProc FinalizeDictUpdate; +static Tcl_NRPostProc FinalizeDictWith; +static Tcl_ObjCmdProc DictForNRCmd; +static Tcl_ObjCmdProc DictMapNRCmd; +static Tcl_NRPostProc DictForLoopCallback; +static Tcl_NRPostProc DictMapLoopCallback; /* * Table of dict subcommand names and implementations. diff --git a/generic/tclDisassemble.c b/generic/tclDisassemble.c index c85fe13..1d616fb 100644 --- a/generic/tclDisassemble.c +++ b/generic/tclDisassemble.c @@ -6,7 +6,7 @@ * * Copyright (c) 1996-1998 Sun Microsystems, Inc. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. - * Copyright (c) 2013 Donal K. Fellows. + * Copyright (c) 2013-2016 Donal K. Fellows. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -1279,9 +1279,11 @@ Tcl_DisassembleObjCmd( Tcl_Obj *const objv[]) /* Argument objects. */ { static const char *const types[] = { + "constructor", "destructor", "lambda", "method", "objmethod", "proc", "script", NULL }; enum Types { + DISAS_CLASS_CONSTRUCTOR, DISAS_CLASS_DESTRUCTOR, DISAS_LAMBDA, DISAS_CLASS_METHOD, DISAS_OBJECT_METHOD, DISAS_PROC, DISAS_SCRIPT }; @@ -1290,6 +1292,7 @@ Tcl_DisassembleObjCmd( Proc *procPtr = NULL; Tcl_HashEntry *hPtr; Object *oPtr; + Method *methodPtr; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "type ..."); @@ -1384,6 +1387,136 @@ Tcl_DisassembleObjCmd( codeObjPtr = objv[2]; break; + case DISAS_CLASS_CONSTRUCTOR: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "className"); + return TCL_ERROR; + } + + /* + * Look up the body of a constructor. + */ + + oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[2]); + if (oPtr == NULL) { + return TCL_ERROR; + } + if (oPtr->classPtr == NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" is not a class", TclGetString(objv[2]))); + Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS", + TclGetString(objv[2]), NULL); + return TCL_ERROR; + } + + methodPtr = oPtr->classPtr->constructorPtr; + if (methodPtr == NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" has no defined constructor", + TclGetString(objv[2]))); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE", + "CONSRUCTOR", NULL); + return TCL_ERROR; + } + procPtr = TclOOGetProcFromMethod(methodPtr); + if (procPtr == NULL) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "body not available for this kind of constructor", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE", + "METHODTYPE", NULL); + return TCL_ERROR; + } + + /* + * Compile if necessary. + */ + + if (procPtr->bodyPtr->typePtr != &tclByteCodeType) { + Command cmd; + + /* + * Yes, this is ugly, but we need to pass the namespace in to the + * compiler in two places. + */ + + cmd.nsPtr = (Namespace *) oPtr->namespacePtr; + procPtr->cmdPtr = &cmd; + result = TclProcCompileProc(interp, procPtr, procPtr->bodyPtr, + (Namespace *) oPtr->namespacePtr, "body of constructor", + TclGetString(objv[2])); + procPtr->cmdPtr = NULL; + if (result != TCL_OK) { + return result; + } + } + codeObjPtr = procPtr->bodyPtr; + break; + + case DISAS_CLASS_DESTRUCTOR: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "className"); + return TCL_ERROR; + } + + /* + * Look up the body of a destructor. + */ + + oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[2]); + if (oPtr == NULL) { + return TCL_ERROR; + } + if (oPtr->classPtr == NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" is not a class", TclGetString(objv[2]))); + Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS", + TclGetString(objv[2]), NULL); + return TCL_ERROR; + } + + methodPtr = oPtr->classPtr->destructorPtr; + if (methodPtr == NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" has no defined destructor", + TclGetString(objv[2]))); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE", + "DESRUCTOR", NULL); + return TCL_ERROR; + } + procPtr = TclOOGetProcFromMethod(methodPtr); + if (procPtr == NULL) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "body not available for this kind of destructor", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE", + "METHODTYPE", NULL); + return TCL_ERROR; + } + + /* + * Compile if necessary. + */ + + if (procPtr->bodyPtr->typePtr != &tclByteCodeType) { + Command cmd; + + /* + * Yes, this is ugly, but we need to pass the namespace in to the + * compiler in two places. + */ + + cmd.nsPtr = (Namespace *) oPtr->namespacePtr; + procPtr->cmdPtr = &cmd; + result = TclProcCompileProc(interp, procPtr, procPtr->bodyPtr, + (Namespace *) oPtr->namespacePtr, "body of destructor", + TclGetString(objv[2])); + procPtr->cmdPtr = NULL; + if (result != TCL_OK) { + return result; + } + } + codeObjPtr = procPtr->bodyPtr; + break; + case DISAS_CLASS_METHOD: if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "className methodName"); diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index d2bd0a2..8e5e410 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -41,6 +41,8 @@ static int CompileBasicNArgCommand(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, CompileEnv *envPtr); +static Tcl_NRPostProc FreeER; + /* * The lists of subcommands and options for the [namespace ensemble] command. */ @@ -1674,18 +1676,11 @@ NsEnsembleImplementationCmdNR( */ Tcl_DString buf; /* Message being built */ - Tcl_Obj **elemPtrs; /* Parameter names */ - int len; /* Number of parameters to append */ Tcl_DStringInit(&buf); - if (ensemblePtr->parameterList == NULL) { - len = 0; - } else if (TclListObjGetElements(NULL, ensemblePtr->parameterList, - &len, &elemPtrs) != TCL_OK) { - Tcl_Panic("List of ensemble parameters is not a list"); - } - for (; len>0; len--,elemPtrs++) { - TclDStringAppendObj(&buf, *elemPtrs); + if (ensemblePtr->parameterList) { + Tcl_DStringAppend(&buf, + TclGetString(ensemblePtr->parameterList), -1); TclDStringAppendLiteral(&buf, " "); } TclDStringAppendLiteral(&buf, "subcommand ?arg ...?"); @@ -1850,46 +1845,26 @@ NsEnsembleImplementationCmdNR( */ { - Tcl_Obj **prefixObjv; /* The list of objects to substitute in as the - * target command prefix. */ Tcl_Obj *copyPtr; /* The actual list of words to dispatch to. * Will be freed by the dispatch engine. */ - int prefixObjc, copyObjc; + Tcl_Obj **copyObjv; + int copyObjc, prefixObjc; - /* - * Get the prefix that we're rewriting to. To do this we need to - * ensure that the internal representation of the list does not change - * so that we can safely keep the internal representations of the - * elements in the list. - * - * TODO: Use conventional list operations to make this code sane! - */ + Tcl_ListObjLength(NULL, prefixObj, &prefixObjc); - TclListObjGetElements(NULL, prefixObj, &prefixObjc, &prefixObjv); - - copyObjc = objc - 2 + prefixObjc; - copyPtr = Tcl_NewListObj(copyObjc, NULL); - if (copyObjc > 0) { - register Tcl_Obj **copyObjv; - /* Space used to construct the list of - * arguments to pass to the command that - * implements the ensemble subcommand. */ - register List *listRepPtr = copyPtr->internalRep.twoPtrValue.ptr1; - register int i; - - listRepPtr->elemCount = copyObjc; - copyObjv = &listRepPtr->elements; - memcpy(copyObjv, prefixObjv, sizeof(Tcl_Obj *) * prefixObjc); - memcpy(copyObjv+prefixObjc, objv+1, - sizeof(Tcl_Obj *) * ensemblePtr->numParameters); - memcpy(copyObjv+prefixObjc+ensemblePtr->numParameters, - objv+ensemblePtr->numParameters+2, - sizeof(Tcl_Obj *) * (objc-ensemblePtr->numParameters-2)); - - for (i=0; i < copyObjc; i++) { - Tcl_IncrRefCount(copyObjv[i]); - } - } + if (objc == 2) { + copyPtr = TclListObjCopy(NULL, prefixObj); + } else { + copyPtr = Tcl_NewListObj(objc - 2 + prefixObjc, NULL); + Tcl_ListObjAppendList(NULL, copyPtr, prefixObj); + Tcl_ListObjReplace(NULL, copyPtr, LIST_MAX, 0, + ensemblePtr->numParameters, objv + 1); + Tcl_ListObjReplace(NULL, copyPtr, LIST_MAX, 0, + objc - 2 - ensemblePtr->numParameters, + objv + 2 + ensemblePtr->numParameters); + } + Tcl_IncrRefCount(copyPtr); + TclNRAddCallback(interp, TclNRReleaseValues, copyPtr, NULL, NULL, NULL); TclDecrRefCount(prefixObj); /* @@ -1909,7 +1884,8 @@ NsEnsembleImplementationCmdNR( */ TclSkipTailcall(interp); - return TclNREvalObjEx(interp, copyPtr, TCL_EVAL_INVOKE, NULL,INT_MIN); + Tcl_ListObjGetElements(NULL, copyPtr, ©Objc, ©Objv); + return TclNREvalObjv(interp, copyObjc, copyObjv, TCL_EVAL_INVOKE, NULL); } unknownOrAmbiguousSubcommand: @@ -2062,7 +2038,7 @@ TclResetRewriteEnsemble( * * TclSpellFix -- * - * Record a spelling correction that needs making in the + * Record a spelling correction that needs making in the * generation of the WrongNumArgs usage message. * * Results: @@ -2087,18 +2063,6 @@ FreeER( return result; } -static int -FreeObj( - ClientData data[], - Tcl_Interp *interp, - int result) -{ - Tcl_Obj *objPtr = (Tcl_Obj *)data[0]; - - Tcl_DecrRefCount(objPtr); - return result; -} - void TclSpellFix( Tcl_Interp *interp, @@ -2122,7 +2086,7 @@ TclSpellFix( /* Compute the valid length of the ensemble root */ - size = iPtr->ensembleRewrite.numRemovedObjs + objc + size = iPtr->ensembleRewrite.numRemovedObjs + objc - iPtr->ensembleRewrite.numInsertedObjs; search = iPtr->ensembleRewrite.sourceObjs; @@ -2174,7 +2138,7 @@ TclSpellFix( store[idx] = fix; Tcl_IncrRefCount(fix); - TclNRAddCallback(interp, FreeObj, fix, NULL, NULL, NULL); + TclNRAddCallback(interp, TclNRReleaseValues, fix, NULL, NULL, NULL); } /* @@ -2385,7 +2349,7 @@ MakeCachedEnsembleCommand( if (objPtr->typePtr == &ensembleCmdType) { ensembleCmd = objPtr->internalRep.twoPtrValue.ptr1; TclCleanupCommandMacro(ensembleCmd->token); - if (ensembleCmd->fix) { + if (ensembleCmd->fix) { Tcl_DecrRefCount(ensembleCmd->fix); } } else { diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 355b667..1389382 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2081,8 +2081,6 @@ TclNRExecuteByteCode( * Push the callback for bytecode execution */ - TclResetRewriteEnsemble(interp, 1); - TclNRAddCallback(interp, TEBCresume, TD, /* pc */ NULL, /* cleanup */ INT2PTR(0), NULL); return TCL_OK; diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index 1330c02..3aa0ce5 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -71,8 +71,7 @@ typedef struct ThreadSpecificData { * Prototypes for functions defined later in this file. */ -static int EvalFileCallback(ClientData data[], - Tcl_Interp *interp, int result); +static Tcl_NRPostProc EvalFileCallback; static FilesystemRecord*FsGetFirstFilesystem(void); static void FsThrExitProc(ClientData cd); static Tcl_Obj * FsListMounts(Tcl_Obj *pathPtr, const char *pattern); diff --git a/generic/tclInt.h b/generic/tclInt.h index fba4c7b..a6cc627 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2741,6 +2741,7 @@ MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldmObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldToObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRInvoke; +MODULE_SCOPE Tcl_NRPostProc TclNRReleaseValues; MODULE_SCOPE void TclSetTailcall(Tcl_Interp *interp, Tcl_Obj *tailcallPtr); MODULE_SCOPE void TclPushTailcallPoint(Tcl_Interp *interp); @@ -2851,8 +2852,7 @@ MODULE_SCOPE int TclCheckBadOctal(Tcl_Interp *interp, MODULE_SCOPE int TclChanCaughtErrorBypass(Tcl_Interp *interp, Tcl_Channel chan); MODULE_SCOPE Tcl_ObjCmdProc TclChannelNamesCmd; -MODULE_SCOPE int TclClearRootEnsemble(ClientData data[], - Tcl_Interp *interp, int result); +MODULE_SCOPE Tcl_NRPostProc TclClearRootEnsemble; MODULE_SCOPE ContLineLoc *TclContinuationsEnter(Tcl_Obj *objPtr, int num, int *loc); MODULE_SCOPE void TclContinuationsEnterDerived(Tcl_Obj *objPtr, diff --git a/generic/tclOO.c b/generic/tclOO.c index 0454bfe..ec666ee 100644 --- a/generic/tclOO.c +++ b/generic/tclOO.c @@ -68,12 +68,9 @@ static int CloneObjectMethod(Tcl_Interp *interp, Object *oPtr, static void DeletedDefineNamespace(ClientData clientData); static void DeletedObjdefNamespace(ClientData clientData); static void DeletedHelpersNamespace(ClientData clientData); -static int FinalizeAlloc(ClientData data[], - Tcl_Interp *interp, int result); -static int FinalizeNext(ClientData data[], - Tcl_Interp *interp, int result); -static int FinalizeObjectCall(ClientData data[], - Tcl_Interp *interp, int result); +static Tcl_NRPostProc FinalizeAlloc; +static Tcl_NRPostProc FinalizeNext; +static Tcl_NRPostProc FinalizeObjectCall; static int InitFoundation(Tcl_Interp *interp); static void KillFoundation(ClientData clientData, Tcl_Interp *interp); diff --git a/generic/tclOOCall.c b/generic/tclOOCall.c index facf90d..1797760 100644 --- a/generic/tclOOCall.c +++ b/generic/tclOOCall.c @@ -70,15 +70,12 @@ static void AddSimpleClassChainToCallContext(Class *classPtr, Class *const filterDecl); static int CmpStr(const void *ptr1, const void *ptr2); static void DupMethodNameRep(Tcl_Obj *srcPtr, Tcl_Obj *dstPtr); -static int FinalizeMethodRefs(ClientData data[], - Tcl_Interp *interp, int result); +static Tcl_NRPostProc FinalizeMethodRefs; static void FreeMethodNameRep(Tcl_Obj *objPtr); static inline int IsStillValid(CallChain *callPtr, Object *oPtr, int flags, int reuseMask); -static int ResetFilterFlags(ClientData data[], - Tcl_Interp *interp, int result); -static int SetFilterFlags(ClientData data[], - Tcl_Interp *interp, int result); +static Tcl_NRPostProc ResetFilterFlags; +static Tcl_NRPostProc SetFilterFlags; static inline void StashCallChain(Tcl_Obj *objPtr, CallChain *callPtr); /* diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c index a311ddb..99a8bfc 100644 --- a/generic/tclOOMethod.c +++ b/generic/tclOOMethod.c @@ -70,10 +70,8 @@ static Tcl_Obj ** InitEnsembleRewrite(Tcl_Interp *interp, int objc, static int InvokeProcedureMethod(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); -static int FinalizeForwardCall(ClientData data[], Tcl_Interp *interp, - int result); -static int FinalizePMCall(ClientData data[], Tcl_Interp *interp, - int result); +static Tcl_NRPostProc FinalizeForwardCall; +static Tcl_NRPostProc FinalizePMCall; static int PushMethodCallFrame(Tcl_Interp *interp, CallContext *contextPtr, ProcedureMethod *pmPtr, int objc, Tcl_Obj *const *objv, diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index 99d576d..c2643bf 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -869,12 +869,16 @@ TclJoinPath( * object which can be normalized more efficiently. Currently we only * use the special case when we have exactly two elements, but we * could expand that in the future. + * + * Bugfix [a47641a0]. TclNewFSPathObj requires first argument + * to be an absolute path. Added a check for that elt is absolute. */ if ((i == (elements-2)) && (i == 0) - && (elt->typePtr == &tclFsPathType) - && !((elt->bytes != NULL) && (elt->bytes[0] == '\0'))) { - Tcl_Obj *tailObj = objv[i+1]; + && (elt->typePtr == &tclFsPathType) + && !((elt->bytes != NULL) && (elt->bytes[0] == '\0')) + && TclGetPathType(elt, NULL, NULL, NULL) == TCL_PATH_ABSOLUTE) { + Tcl_Obj *tailObj = objv[i+1]; type = TclGetPathType(tailObj, NULL, NULL, NULL); if (type == TCL_PATH_RELATIVE) { diff --git a/generic/tclTest.c b/generic/tclTest.c index 4695ab5..e33d263 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -413,8 +413,7 @@ static int TestHashSystemHashCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -static int NREUnwind_callback(ClientData data[], Tcl_Interp *interp, - int result); +static Tcl_NRPostProc NREUnwind_callback; static int TestNREUnwind(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); diff --git a/library/tcltest/tcltest.tcl b/library/tcltest/tcltest.tcl index 169b7d4..cde2660 100644 --- a/library/tcltest/tcltest.tcl +++ b/library/tcltest/tcltest.tcl @@ -614,7 +614,7 @@ namespace eval tcltest { set levelMap { l list p pass - b body + b body s skip t start e error @@ -2709,7 +2709,7 @@ proc tcltest::GetMatchingDirectories {rootdir} { DebugPuts 1 "No test directories remain after applying match\ and skip patterns!" } - return $matchDirs + return [lsort $matchDirs] } # tcltest::runAllTests -- diff --git a/tests/cmdAH.test b/tests/cmdAH.test index 64cfeba..f2f7f8c 100644 --- a/tests/cmdAH.test +++ b/tests/cmdAH.test @@ -879,19 +879,18 @@ test cmdAH-18.3 {Tcl_FileObjCmd: executable} {unix testchmod} { test cmdAH-18.5 {Tcl_FileObjCmd: executable} -constraints {win} -body { # On pc, must be a .exe, .com, etc. set x [file exe $gorpfile] - set gorpexe [makeFile foo gorp.exe] - lappend x [file exe $gorpexe] -} -cleanup { - removeFile $gorpexe -} -result {0 1} -test cmdAH-18.5.1 {Tcl_FileObjCmd: executable} -constraints {win} -body { - # On pc, must be a .exe, .com, etc. - set x [file exe $gorpfile] - set gorpexe [makeFile foo gorp.exe] - lappend x [file exe [string toupper $gorpexe]] + set gorpexes {} + foreach ext {exe com cmd bat ps1} { + set gorpexe [makeFile foo gorp.$ext] + lappend gorpexes $gorpexe + lappend x [file exe $gorpexe] [file exe [string toupper $gorpexe]] + } + set x } -cleanup { - removeFile $gorpexe -} -result {0 1} + foreach gorpexe $gorpexes { + removeFile $gorpexe + } +} -result {0 1 1 1 1 1 1 1 1 1 1} test cmdAH-18.6 {Tcl_FileObjCmd: executable} {} { # Directories are always executable. file exe $dirfile diff --git a/tests/compile.test b/tests/compile.test index bb12050..f021cf2 100644 --- a/tests/compile.test +++ b/tests/compile.test @@ -678,7 +678,7 @@ test compile-17.2 {Command interpretation binding for non-compiled code} -setup # change without warning. set disassemblables [linsert [join { - lambda method objmethod proc script + constructor destructor lambda method objmethod proc script } ", "] end-1 or] test compile-18.1 {disassembler - basics} -returnCodes error -body { tcl::unsupported::disassemble @@ -872,6 +872,103 @@ test compile-18.39 {disassembler - basics} -setup { } -cleanup { foo destroy } -result "$bytecodekeys initiallinenumber sourcefile" +test compile-18.40 {disassembler - basics} -returnCodes error -body { + tcl::unsupported::disassemble constructor +} -match glob -result {wrong # args: should be "* constructor className"} +test compile-18.41 {disassembler - basics} -returnCodes error -body { + tcl::unsupported::disassemble constructor nosuchclass +} -result {nosuchclass does not refer to an object} +test compile-18.42 {disassembler - basics} -returnCodes error -setup { + oo::object create justanobject +} -body { + tcl::unsupported::disassemble constructor justanobject +} -cleanup { + justanobject destroy +} -result {"justanobject" is not a class} +test compile-18.43 {disassembler - basics} -returnCodes error -setup { + oo::class create constructorless +} -body { + tcl::unsupported::disassemble constructor constructorless +} -cleanup { + constructorless destroy +} -result {"constructorless" has no defined constructor} +test compile-18.44 {disassembler - basics} -setup { + oo::class create foo {constructor {} {set x 1}} +} -body { + # Allow any string: the result format is not defined anywhere! + tcl::unsupported::disassemble constructor foo +} -cleanup { + foo destroy +} -match glob -result * +test compile-18.45 {disassembler - basics} -returnCodes error -body { + tcl::unsupported::getbytecode constructor +} -match glob -result {wrong # args: should be "* constructor className"} +test compile-18.46 {disassembler - basics} -returnCodes error -body { + tcl::unsupported::getbytecode constructor nosuchobject +} -result {nosuchobject does not refer to an object} +test compile-18.47 {disassembler - basics} -returnCodes error -setup { + oo::class create constructorless +} -body { + tcl::unsupported::getbytecode constructor constructorless +} -cleanup { + constructorless destroy +} -result {"constructorless" has no defined constructor} +test compile-18.48 {disassembler - basics} -setup { + oo::class create foo {constructor {} {set x 1}} +} -body { + dict keys [tcl::unsupported::getbytecode constructor foo] +} -cleanup { + foo destroy +} -result "$bytecodekeys" +# There is no compile-18.49 +test compile-18.50 {disassembler - basics} -returnCodes error -body { + tcl::unsupported::disassemble destructor +} -match glob -result {wrong # args: should be "* destructor className"} +test compile-18.51 {disassembler - basics} -returnCodes error -body { + tcl::unsupported::disassemble destructor nosuchclass +} -result {nosuchclass does not refer to an object} +test compile-18.52 {disassembler - basics} -returnCodes error -setup { + oo::object create justanobject +} -body { + tcl::unsupported::disassemble destructor justanobject +} -cleanup { + justanobject destroy +} -result {"justanobject" is not a class} +test compile-18.53 {disassembler - basics} -returnCodes error -setup { + oo::class create constructorless +} -body { + tcl::unsupported::disassemble destructor constructorless +} -cleanup { + constructorless destroy +} -result {"constructorless" has no defined destructor} +test compile-18.54 {disassembler - basics} -setup { + oo::class create foo {destructor {set x 1}} +} -body { + # Allow any string: the result format is not defined anywhere! + tcl::unsupported::disassemble destructor foo +} -cleanup { + foo destroy +} -match glob -result * +test compile-18.55 {disassembler - basics} -returnCodes error -body { + tcl::unsupported::getbytecode destructor +} -match glob -result {wrong # args: should be "* destructor className"} +test compile-18.56 {disassembler - basics} -returnCodes error -body { + tcl::unsupported::getbytecode destructor nosuchobject +} -result {nosuchobject does not refer to an object} +test compile-18.57 {disassembler - basics} -returnCodes error -setup { + oo::class create constructorless +} -body { + tcl::unsupported::getbytecode destructor constructorless +} -cleanup { + constructorless destroy +} -result {"constructorless" has no defined destructor} +test compile-18.58 {disassembler - basics} -setup { + oo::class create foo {destructor {set x 1}} +} -body { + dict keys [tcl::unsupported::getbytecode destructor foo] +} -cleanup { + foo destroy +} -result "$bytecodekeys" test compile-19.0 {Bug 3614102: reset stack housekeeping} -body { # This will panic in a --enable-symbols=compile build, unless bug is fixed. diff --git a/tests/fileName.test b/tests/fileName.test index 51f00d1..a19bd1e 100644 --- a/tests/fileName.test +++ b/tests/fileName.test @@ -1468,14 +1468,16 @@ if {[testConstraint testsetplatform]} { } test filename-17.2 {windows specific glob with executable} -body { makeDirectory execglob - makeFile contents execglob/abc.exe - makeFile contents execglob/abc.notexecutable - glob -nocomplain -dir [temporaryDirectory]/execglob -tails -types x * + foreach ext {exe com cmd bat ps1 notexecutable} { + makeFile contents execglob/abc.$ext + } + lsort [glob -nocomplain -dir [temporaryDirectory]/execglob -tails -types x *] } -constraints {win} -cleanup { - removeFile execglob/abc.exe - removeFile execglob/abc.notexecutable + foreach ext {exe com cmd bat ps1 notexecutable} { + removeFile execglob/abc.$ext + } removeDirectory execglob -} -result {abc.exe} +} -result {abc.bat abc.cmd abc.com abc.exe abc.ps1} test filename-17.3 {Bug 2571597} win { set p /a file pathtype $p diff --git a/tests/namespace.test b/tests/namespace.test index c433241..dc1d3bf 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -2153,6 +2153,15 @@ test namespace-50.7 {[4402cfa58c]} -setup { rename e2 {} rename target {} } -result {{wrong # args: should be "e1 s2 s1 x y"} {wrong # args: should be "e1 s2 s1 x y"} {wrong # args: should be "e1 s2 s1 x y"} {wrong # args: should be "e1 s2 s1 x y"}} +test namespace-50.8 {[f961d7d1dd]} -setup { + proc target {} {} + namespace ensemble create -command e -map {s target} -parameters {{a b}} +} -body { + e +} -returnCodes error -result {wrong # args: should be "e {a b} subcommand ?arg ...?"} -cleanup { + rename e {} + rename target {} +} test namespace-51.1 {name resolution path control} -body { namespace eval ::test_ns_1 { diff --git a/tests/oo.test b/tests/oo.test index 895f7ed..48e093a 100644 --- a/tests/oo.test +++ b/tests/oo.test @@ -2017,6 +2017,12 @@ test oo-15.10 {variable binding must not bleed through oo::copy} -setup { test oo-16.1 {OO: object introspection} -body { info object } -returnCodes 1 -result "wrong \# args: should be \"info object subcommand ?arg ...?\"" +test oo-16.1.1 {OO: object introspection} -body { + catch {info object} m o + dict get $o -errorinfo +} -result "wrong \# args: should be \"info object subcommand ?arg ...?\" + while executing +\"info object\"" test oo-16.2 {OO: object introspection} -body { info object class NOTANOBJECT } -returnCodes 1 -result {NOTANOBJECT does not refer to an object} @@ -2156,6 +2162,12 @@ test oo-16.14 {OO: object introspection: TIP #436} -setup { test oo-17.1 {OO: class introspection} -body { info class } -returnCodes 1 -result "wrong \# args: should be \"info class subcommand ?arg ...?\"" +test oo-17.1.1 {OO: class introspection} -body { + catch {info class} m o + dict get $o -errorinfo +} -result "wrong \# args: should be \"info class subcommand ?arg ...?\" + while executing +\"info class\"" test oo-17.2 {OO: class introspection} -body { info class superclass NOTANOBJECT } -returnCodes 1 -result {NOTANOBJECT does not refer to an object} diff --git a/win/tclWinFile.c b/win/tclWinFile.c index 25c6ea4..4b0b884 100755 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -1769,7 +1769,7 @@ NativeAccess( * NativeIsExec -- * * Determines if a path is executable. On windows this is simply defined - * by whether the path ends in any of ".exe", ".com", or ".bat" + * by whether the path ends in a standard executable extension. * * Results: * 1 = executable, 0 = not. @@ -1793,6 +1793,8 @@ NativeIsExec( if ((_tcsicmp(path+len-3, TEXT("exe")) == 0) || (_tcsicmp(path+len-3, TEXT("com")) == 0) + || (_tcsicmp(path+len-3, TEXT("cmd")) == 0) + || (_tcsicmp(path+len-3, TEXT("ps1")) == 0) || (_tcsicmp(path+len-3, TEXT("bat")) == 0)) { return 1; } |