From 33648948cab45a58ba614f448459fdcb133023dc Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 26 Feb 2014 13:16:18 +0000 Subject: Simplify macro handling in tclOO*Decls.h, just as already done in "novem" [0c37ab8944], itcl*Decls.h and tdbc*Decls.h. This doesn't change the way symbols are exported. This simplifications were already present in the Tcl 8.6.2 headers, but those were buggy when tclOO was linked in statically without using stubs. --- generic/tclOO.decls | 1 + generic/tclOODecls.h | 78 ++++++++++++++++++++++++------------------------- generic/tclOOIntDecls.h | 45 ++++++++++------------------ 3 files changed, 55 insertions(+), 69 deletions(-) diff --git a/generic/tclOO.decls b/generic/tclOO.decls index 5d6f2c2..265ba88 100644 --- a/generic/tclOO.decls +++ b/generic/tclOO.decls @@ -18,6 +18,7 @@ library tclOO interface tclOO hooks tclOOInt +scspec TCLAPI declare 0 { Tcl_Object Tcl_CopyObjectInstance(Tcl_Interp *interp, diff --git a/generic/tclOODecls.h b/generic/tclOODecls.h index d3b9e59..9fd62ec 100644 --- a/generic/tclOODecls.h +++ b/generic/tclOODecls.h @@ -5,19 +5,19 @@ #ifndef _TCLOODECLS #define _TCLOODECLS -#undef TCL_STORAGE_CLASS -#ifdef BUILD_tcl -# define TCL_STORAGE_CLASS DLLEXPORT -#else -# ifdef USE_TCL_STUBS -# undef USE_TCLOO_STUBS -# define USE_TCLOO_STUBS -# define TCL_STORAGE_CLASS +#ifndef TCLAPI +# ifdef BUILD_tcl +# define TCLAPI extern DLLEXPORT # else -# define TCL_STORAGE_CLASS DLLIMPORT +# define TCLAPI extern DLLIMPORT # endif #endif +#ifdef USE_TCL_STUBS +# undef USE_TCLOO_STUBS +# define USE_TCLOO_STUBS +#endif + /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus @@ -29,92 +29,92 @@ extern "C" { */ /* 0 */ -EXTERN Tcl_Object Tcl_CopyObjectInstance(Tcl_Interp *interp, +TCLAPI Tcl_Object Tcl_CopyObjectInstance(Tcl_Interp *interp, Tcl_Object sourceObject, const char *targetName, const char *targetNamespaceName); /* 1 */ -EXTERN Tcl_Object Tcl_GetClassAsObject(Tcl_Class clazz); +TCLAPI Tcl_Object Tcl_GetClassAsObject(Tcl_Class clazz); /* 2 */ -EXTERN Tcl_Class Tcl_GetObjectAsClass(Tcl_Object object); +TCLAPI Tcl_Class Tcl_GetObjectAsClass(Tcl_Object object); /* 3 */ -EXTERN Tcl_Command Tcl_GetObjectCommand(Tcl_Object object); +TCLAPI Tcl_Command Tcl_GetObjectCommand(Tcl_Object object); /* 4 */ -EXTERN Tcl_Object Tcl_GetObjectFromObj(Tcl_Interp *interp, +TCLAPI Tcl_Object Tcl_GetObjectFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr); /* 5 */ -EXTERN Tcl_Namespace * Tcl_GetObjectNamespace(Tcl_Object object); +TCLAPI Tcl_Namespace * Tcl_GetObjectNamespace(Tcl_Object object); /* 6 */ -EXTERN Tcl_Class Tcl_MethodDeclarerClass(Tcl_Method method); +TCLAPI Tcl_Class Tcl_MethodDeclarerClass(Tcl_Method method); /* 7 */ -EXTERN Tcl_Object Tcl_MethodDeclarerObject(Tcl_Method method); +TCLAPI Tcl_Object Tcl_MethodDeclarerObject(Tcl_Method method); /* 8 */ -EXTERN int Tcl_MethodIsPublic(Tcl_Method method); +TCLAPI int Tcl_MethodIsPublic(Tcl_Method method); /* 9 */ -EXTERN int Tcl_MethodIsType(Tcl_Method method, +TCLAPI int Tcl_MethodIsType(Tcl_Method method, const Tcl_MethodType *typePtr, ClientData *clientDataPtr); /* 10 */ -EXTERN Tcl_Obj * Tcl_MethodName(Tcl_Method method); +TCLAPI Tcl_Obj * Tcl_MethodName(Tcl_Method method); /* 11 */ -EXTERN Tcl_Method Tcl_NewInstanceMethod(Tcl_Interp *interp, +TCLAPI Tcl_Method Tcl_NewInstanceMethod(Tcl_Interp *interp, Tcl_Object object, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, ClientData clientData); /* 12 */ -EXTERN Tcl_Method Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls, +TCLAPI Tcl_Method Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls, Tcl_Obj *nameObj, int isPublic, const Tcl_MethodType *typePtr, ClientData clientData); /* 13 */ -EXTERN Tcl_Object Tcl_NewObjectInstance(Tcl_Interp *interp, +TCLAPI Tcl_Object Tcl_NewObjectInstance(Tcl_Interp *interp, Tcl_Class cls, const char *nameStr, const char *nsNameStr, int objc, Tcl_Obj *const *objv, int skip); /* 14 */ -EXTERN int Tcl_ObjectDeleted(Tcl_Object object); +TCLAPI int Tcl_ObjectDeleted(Tcl_Object object); /* 15 */ -EXTERN int Tcl_ObjectContextIsFiltering( +TCLAPI int Tcl_ObjectContextIsFiltering( Tcl_ObjectContext context); /* 16 */ -EXTERN Tcl_Method Tcl_ObjectContextMethod(Tcl_ObjectContext context); +TCLAPI Tcl_Method Tcl_ObjectContextMethod(Tcl_ObjectContext context); /* 17 */ -EXTERN Tcl_Object Tcl_ObjectContextObject(Tcl_ObjectContext context); +TCLAPI Tcl_Object Tcl_ObjectContextObject(Tcl_ObjectContext context); /* 18 */ -EXTERN int Tcl_ObjectContextSkippedArgs( +TCLAPI int Tcl_ObjectContextSkippedArgs( Tcl_ObjectContext context); /* 19 */ -EXTERN ClientData Tcl_ClassGetMetadata(Tcl_Class clazz, +TCLAPI ClientData Tcl_ClassGetMetadata(Tcl_Class clazz, const Tcl_ObjectMetadataType *typePtr); /* 20 */ -EXTERN void Tcl_ClassSetMetadata(Tcl_Class clazz, +TCLAPI void Tcl_ClassSetMetadata(Tcl_Class clazz, const Tcl_ObjectMetadataType *typePtr, ClientData metadata); /* 21 */ -EXTERN ClientData Tcl_ObjectGetMetadata(Tcl_Object object, +TCLAPI ClientData Tcl_ObjectGetMetadata(Tcl_Object object, const Tcl_ObjectMetadataType *typePtr); /* 22 */ -EXTERN void Tcl_ObjectSetMetadata(Tcl_Object object, +TCLAPI void Tcl_ObjectSetMetadata(Tcl_Object object, const Tcl_ObjectMetadataType *typePtr, ClientData metadata); /* 23 */ -EXTERN int Tcl_ObjectContextInvokeNext(Tcl_Interp *interp, +TCLAPI int Tcl_ObjectContextInvokeNext(Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv, int skip); /* 24 */ -EXTERN Tcl_ObjectMapMethodNameProc * Tcl_ObjectGetMethodNameMapper( +TCLAPI Tcl_ObjectMapMethodNameProc * Tcl_ObjectGetMethodNameMapper( Tcl_Object object); /* 25 */ -EXTERN void Tcl_ObjectSetMethodNameMapper(Tcl_Object object, +TCLAPI void Tcl_ObjectSetMethodNameMapper(Tcl_Object object, Tcl_ObjectMapMethodNameProc *mapMethodNameProc); /* 26 */ -EXTERN void Tcl_ClassSetConstructor(Tcl_Interp *interp, +TCLAPI void Tcl_ClassSetConstructor(Tcl_Interp *interp, Tcl_Class clazz, Tcl_Method method); /* 27 */ -EXTERN void Tcl_ClassSetDestructor(Tcl_Interp *interp, +TCLAPI void Tcl_ClassSetDestructor(Tcl_Interp *interp, Tcl_Class clazz, Tcl_Method method); /* 28 */ -EXTERN Tcl_Obj * Tcl_GetObjectName(Tcl_Interp *interp, +TCLAPI Tcl_Obj * Tcl_GetObjectName(Tcl_Interp *interp, Tcl_Object object); typedef struct { @@ -231,6 +231,4 @@ extern const TclOOStubs *tclOOStubsPtr; /* !END!: Do not edit above this line. */ -#undef TCL_STORAGE_CLASS -#define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLOODECLS */ diff --git a/generic/tclOOIntDecls.h b/generic/tclOOIntDecls.h index 4f70e5b..74a8d81 100644 --- a/generic/tclOOIntDecls.h +++ b/generic/tclOOIntDecls.h @@ -5,17 +5,6 @@ #ifndef _TCLOOINTDECLS #define _TCLOOINTDECLS -#undef TCL_STORAGE_CLASS -#ifdef BUILD_tcl -# define TCL_STORAGE_CLASS DLLEXPORT -#else -# ifdef USE_TCL_STUBS -# define TCL_STORAGE_CLASS -# else -# define TCL_STORAGE_CLASS DLLIMPORT -# endif -#endif - /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus @@ -27,46 +16,46 @@ extern "C" { */ /* 0 */ -EXTERN Tcl_Object TclOOGetDefineCmdContext(Tcl_Interp *interp); +TCLAPI Tcl_Object TclOOGetDefineCmdContext(Tcl_Interp *interp); /* 1 */ -EXTERN Tcl_Method TclOOMakeProcInstanceMethod(Tcl_Interp *interp, +TCLAPI Tcl_Method TclOOMakeProcInstanceMethod(Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, ClientData clientData, Proc **procPtrPtr); /* 2 */ -EXTERN Tcl_Method TclOOMakeProcMethod(Tcl_Interp *interp, +TCLAPI Tcl_Method TclOOMakeProcMethod(Tcl_Interp *interp, Class *clsPtr, int flags, Tcl_Obj *nameObj, const char *namePtr, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, ClientData clientData, Proc **procPtrPtr); /* 3 */ -EXTERN Method * TclOONewProcInstanceMethod(Tcl_Interp *interp, +TCLAPI Method * TclOONewProcInstanceMethod(Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, ProcedureMethod **pmPtrPtr); /* 4 */ -EXTERN Method * TclOONewProcMethod(Tcl_Interp *interp, Class *clsPtr, +TCLAPI Method * TclOONewProcMethod(Tcl_Interp *interp, Class *clsPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, ProcedureMethod **pmPtrPtr); /* 5 */ -EXTERN int TclOOObjectCmdCore(Object *oPtr, Tcl_Interp *interp, +TCLAPI int TclOOObjectCmdCore(Object *oPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv, int publicOnly, Class *startCls); /* 6 */ -EXTERN int TclOOIsReachable(Class *targetPtr, Class *startPtr); +TCLAPI int TclOOIsReachable(Class *targetPtr, Class *startPtr); /* 7 */ -EXTERN Method * TclOONewForwardMethod(Tcl_Interp *interp, +TCLAPI Method * TclOONewForwardMethod(Tcl_Interp *interp, Class *clsPtr, int isPublic, Tcl_Obj *nameObj, Tcl_Obj *prefixObj); /* 8 */ -EXTERN Method * TclOONewForwardInstanceMethod(Tcl_Interp *interp, +TCLAPI Method * TclOONewForwardInstanceMethod(Tcl_Interp *interp, Object *oPtr, int isPublic, Tcl_Obj *nameObj, Tcl_Obj *prefixObj); /* 9 */ -EXTERN Tcl_Method TclOONewProcInstanceMethodEx(Tcl_Interp *interp, +TCLAPI Tcl_Method TclOONewProcInstanceMethodEx(Tcl_Interp *interp, Tcl_Object oPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, @@ -75,7 +64,7 @@ EXTERN Tcl_Method TclOONewProcInstanceMethodEx(Tcl_Interp *interp, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr); /* 10 */ -EXTERN Tcl_Method TclOONewProcMethodEx(Tcl_Interp *interp, +TCLAPI Tcl_Method TclOONewProcMethodEx(Tcl_Interp *interp, Tcl_Class clsPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, @@ -84,22 +73,22 @@ EXTERN Tcl_Method TclOONewProcMethodEx(Tcl_Interp *interp, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr); /* 11 */ -EXTERN int TclOOInvokeObject(Tcl_Interp *interp, +TCLAPI int TclOOInvokeObject(Tcl_Interp *interp, Tcl_Object object, Tcl_Class startCls, int publicPrivate, int objc, Tcl_Obj *const *objv); /* 12 */ -EXTERN void TclOOObjectSetFilters(Object *oPtr, int numFilters, +TCLAPI void TclOOObjectSetFilters(Object *oPtr, int numFilters, Tcl_Obj *const *filters); /* 13 */ -EXTERN void TclOOClassSetFilters(Tcl_Interp *interp, +TCLAPI void TclOOClassSetFilters(Tcl_Interp *interp, Class *classPtr, int numFilters, Tcl_Obj *const *filters); /* 14 */ -EXTERN void TclOOObjectSetMixins(Object *oPtr, int numMixins, +TCLAPI void TclOOObjectSetMixins(Object *oPtr, int numMixins, Class *const *mixins); /* 15 */ -EXTERN void TclOOClassSetMixins(Tcl_Interp *interp, +TCLAPI void TclOOClassSetMixins(Tcl_Interp *interp, Class *classPtr, int numMixins, Class *const *mixins); @@ -174,6 +163,4 @@ extern const TclOOIntStubs *tclOOIntStubsPtr; /* !END!: Do not edit above this line. */ -#undef TCL_STORAGE_CLASS -#define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLOOINTDECLS */ -- cgit v0.12 From 72ae8dccf119510f1b175a9a2243a87069cef308 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 21 Mar 2014 17:11:32 +0000 Subject: Added comments raising questions about possible updates to channel drivers on Windows. --- win/tclWinChan.c | 4 ++++ win/tclWinConsole.c | 7 +++++++ win/tclWinPipe.c | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/win/tclWinChan.c b/win/tclWinChan.c index c63aaa7..48acacb 100644 --- a/win/tclWinChan.c +++ b/win/tclWinChan.c @@ -662,6 +662,10 @@ FileInputProc( *errorCode = 0; /* + * TODO: This comment appears to be out of date. We *do* have a + * console driver, over in tclWinConsole.c. After some Windows + * developer confirms, this comment should be revised. + * * Note that we will block on reads from a console buffer until a full * line has been entered. The only way I know of to get around this is to * write a console driver. We should probably do this at some point, but diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c index 0ec22c5..6630083 100644 --- a/win/tclWinConsole.c +++ b/win/tclWinConsole.c @@ -756,6 +756,13 @@ ConsoleInputProc( if (ReadConsoleBytes(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &count) == TRUE) { + /* + * TODO: This potentially writes beyond the limits specified + * by the caller. In practice this is harmless, since all writes + * are into ChannelBuffers, and those have padding, but still + * ought to remove this, unless some Windows wizard can give + * a reason not to. + */ buf[count] = '\0'; return count; } diff --git a/win/tclWinPipe.c b/win/tclWinPipe.c index 77fc776..a9eec6d 100644 --- a/win/tclWinPipe.c +++ b/win/tclWinPipe.c @@ -82,6 +82,12 @@ static ProcInfo *procList; #define PIPE_EXTRABYTE (1<<3) /* The reader thread has consumed one byte. */ /* + * TODO: It appears the whole EXTRABYTE machinery is in place to support + * outdated Win 95 systems. If this can be confirmed, much code can be + * deleted. + */ + +/* * This structure describes per-instance data for a pipe based channel. */ -- cgit v0.12 From 3b6523dd1f6ce2e08932508cf276ca55d04872e6 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 26 Mar 2014 10:37:57 +0000 Subject: Implementation of [b42b208ba4]: file attributes -readonly on Cygwin. For completeness, implemented -archive, -hidden and -system as well. --- unix/tclUnixFCmd.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++---- unix/tclUnixPort.h | 3 + 2 files changed, 174 insertions(+), 14 deletions(-) diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index e270b6a..259c7e5 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -91,10 +91,10 @@ static int SetPermissionsAttribute(Tcl_Interp *interp, Tcl_Obj *attributePtr); static int GetModeFromPermString(Tcl_Interp *interp, const char *modeStringPtr, mode_t *modePtr); -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) -static int GetReadOnlyAttribute(Tcl_Interp *interp, int objIndex, +#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) || defined(__CYGWIN__) +static int GetUnixFileAttributes(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr); -static int SetReadOnlyAttribute(Tcl_Interp *interp, int objIndex, +static int SetUnixFileAttributes(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr); #endif @@ -124,10 +124,20 @@ extern const char *const tclpFileAttrStrings[]; #else /* !DJGPP */ enum { - UNIX_GROUP_ATTRIBUTE, UNIX_OWNER_ATTRIBUTE, UNIX_PERMISSIONS_ATTRIBUTE, -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) +#if defined(__CYGWIN__) + UNIX_ARCHIVE_ATTRIBUTE, +#endif + UNIX_GROUP_ATTRIBUTE, +#if defined(__CYGWIN__) + UNIX_HIDDEN_ATTRIBUTE, +#endif + UNIX_OWNER_ATTRIBUTE, UNIX_PERMISSIONS_ATTRIBUTE, +#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) || defined(__CYGWIN__) UNIX_READONLY_ATTRIBUTE, #endif +#if defined(__CYGWIN__) + UNIX_SYSTEM_ATTRIBUTE, +#endif #ifdef MAC_OSX_TCL MACOSX_CREATOR_ATTRIBUTE, MACOSX_TYPE_ATTRIBUTE, MACOSX_HIDDEN_ATTRIBUTE, MACOSX_RSRCLENGTH_ATTRIBUTE, @@ -137,10 +147,20 @@ enum { MODULE_SCOPE const char *const tclpFileAttrStrings[]; const char *const tclpFileAttrStrings[] = { - "-group", "-owner", "-permissions", -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) +#if defined(__CYGWIN__) + "-archive", +#endif + "-group", +#if defined(__CYGWIN__) + "-hidden", +#endif + "-owner", "-permissions", +#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) || defined(__CYGWIN__) "-readonly", #endif +#if defined(__CYGWIN__) + "-system", +#endif #ifdef MAC_OSX_TCL "-creator", "-type", "-hidden", "-rsrclength", #endif @@ -149,11 +169,20 @@ const char *const tclpFileAttrStrings[] = { MODULE_SCOPE const TclFileAttrProcs tclpFileAttrProcs[]; const TclFileAttrProcs tclpFileAttrProcs[] = { +#if defined(__CYGWIN__) + {GetUnixFileAttributes, SetUnixFileAttributes}, +#endif {GetGroupAttribute, SetGroupAttribute}, +#if defined(__CYGWIN__) + {GetUnixFileAttributes, SetUnixFileAttributes}, +#endif {GetOwnerAttribute, SetOwnerAttribute}, {GetPermissionsAttribute, SetPermissionsAttribute}, -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) - {GetReadOnlyAttribute, SetReadOnlyAttribute}, +#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) || defined(__CYGWIN__) + {GetUnixFileAttributes, SetUnixFileAttributes}, +#endif +#if defined(__CYGWIN__) + {GetUnixFileAttributes, SetUnixFileAttributes}, #endif #ifdef MAC_OSX_TCL {TclMacOSXGetFileAttribute, TclMacOSXSetFileAttribute}, @@ -2246,11 +2275,139 @@ DefaultTempDir(void) return TCL_TEMPORARY_FILE_DIRECTORY; } -#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) +#if defined(__CYGWIN__) + +static void +StatError( + Tcl_Interp *interp, /* The interp that has the error */ + Tcl_Obj *fileName) /* The name of the file which caused the + * error. */ +{ + TclWinConvertError(GetLastError()); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); +} + +static WCHAR * +winPathFromNative( + const char *native) +{ + int size; + WCHAR *winPath; + + size = cygwin_conv_path(1, native, NULL, 0); + winPath = ckalloc(size); + cygwin_conv_path(1, native, winPath, size); + + return winPath; +} + +static const int attributeArray[] = { + 0x20, 0, 2, 0, 0, 1, 4}; + +/* + *---------------------------------------------------------------------- + * + * GetUnixFileAttributes + * + * Gets the readonly attribute of a file. + * + * Results: + * Standard TCL result. Returns a new Tcl_Obj in attributePtrPtr if there + * is no error. The object will have ref count 0. + * + * Side effects: + * A new object is allocated. + * + *---------------------------------------------------------------------- + */ + +static int +GetUnixFileAttributes( + Tcl_Interp *interp, /* The interp we are using for errors. */ + int objIndex, /* The index of the attribute. */ + Tcl_Obj *fileName, /* The name of the file (UTF-8). */ + Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ +{ + int fileAttributes; + const char *native = Tcl_FSGetNativePath(fileName); + WCHAR *winPath = winPathFromNative(native); + + fileAttributes = GetFileAttributesW(winPath); + ckfree(winPath); + + if (fileAttributes == -1) { + StatError(interp, fileName); + return TCL_ERROR; + } + + *attributePtrPtr = Tcl_NewIntObj((fileAttributes&attributeArray[objIndex])!=0); + + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * SetUnixFileAttributes + * + * Sets the readonly attribute of a file. + * + * Results: + * Standard TCL result. + * + * Side effects: + * The readonly attribute of the file is changed. + * + *--------------------------------------------------------------------------- + */ + +static int +SetUnixFileAttributes( + Tcl_Interp *interp, /* The interp we are using for errors. */ + int objIndex, /* The index of the attribute. */ + Tcl_Obj *fileName, /* The name of the file (UTF-8). */ + Tcl_Obj *attributePtr) /* The attribute to set. */ +{ + int yesNo, fileAttributes; + const char *native; + WCHAR *winPath; + + if (Tcl_GetBooleanFromObj(interp, attributePtr, &yesNo) != TCL_OK) { + return TCL_ERROR; + } + + native = Tcl_FSGetNativePath(fileName); + winPath = winPathFromNative(native); + + fileAttributes = GetFileAttributesW(winPath); + + if (fileAttributes == -1) { + ckfree(winPath); + StatError(interp, fileName); + return TCL_ERROR; + } + + if (yesNo) { + fileAttributes |= attributeArray[objIndex]; + } else { + fileAttributes &= ~attributeArray[objIndex]; + } + + if (!SetFileAttributesW(winPath, fileAttributes)) { + ckfree(winPath); + StatError(interp, fileName); + return TCL_ERROR; + } + + ckfree(winPath); + return TCL_OK; +} +#elif defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) /* *---------------------------------------------------------------------- * - * GetReadOnlyAttribute + * GetUnixFileAttributes * * Gets the readonly attribute (user immutable flag) of a file. * @@ -2265,7 +2422,7 @@ DefaultTempDir(void) */ static int -GetReadOnlyAttribute( +GetUnixFileAttributes( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ Tcl_Obj *fileName, /* The name of the file (UTF-8). */ @@ -2293,7 +2450,7 @@ GetReadOnlyAttribute( /* *--------------------------------------------------------------------------- * - * SetReadOnlyAttribute + * SetUnixFileAttributes * * Sets the readonly attribute (user immutable flag) of a file. * @@ -2307,7 +2464,7 @@ GetReadOnlyAttribute( */ static int -SetReadOnlyAttribute( +SetUnixFileAttributes( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ Tcl_Obj *fileName, /* The name of the file (UTF-8). */ diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h index 2ade1c0..f64d453 100644 --- a/unix/tclUnixPort.h +++ b/unix/tclUnixPort.h @@ -93,6 +93,9 @@ typedef off_t Tcl_SeekOffset; WCHAR *, int); __declspec(dllimport) extern __stdcall void OutputDebugStringW(const WCHAR *); __declspec(dllimport) extern __stdcall int IsDebuggerPresent(); + __declspec(dllimport) extern __stdcall int GetLastError(); + __declspec(dllimport) extern __stdcall int GetFileAttributesW(const WCHAR *); + __declspec(dllimport) extern __stdcall int SetFileAttributesW(const WCHAR *, int); __declspec(dllimport) extern int cygwin_conv_path(int, const void *, void *, int); __declspec(dllimport) extern int cygwin_conv_path_list(int, const void *, void *, int); -- cgit v0.12 From 07ba2fc47f5d9c888ccb11ca3666f215159b5f45 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 26 Mar 2014 14:34:56 +0000 Subject: Only write back file attributes if any of them really changed. --- unix/tclUnixFCmd.c | 23 +++++++++++------------ win/tclWinFCmd.c | 7 ++++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index 259c7e5..3b1b6ca 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -2289,11 +2289,12 @@ StatError( } static WCHAR * -winPathFromNative( - const char *native) +winPathFromObj( + Tcl_Obj *fileName) { - int size; - WCHAR *winPath; + int size; + const char *native = Tcl_FSGetNativePath(fileName); + WCHAR *winPath; size = cygwin_conv_path(1, native, NULL, 0); winPath = ckalloc(size); @@ -2330,8 +2331,7 @@ GetUnixFileAttributes( Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { int fileAttributes; - const char *native = Tcl_FSGetNativePath(fileName); - WCHAR *winPath = winPathFromNative(native); + WCHAR *winPath = winPathFromObj(fileName); fileAttributes = GetFileAttributesW(winPath); ckfree(winPath); @@ -2369,18 +2369,16 @@ SetUnixFileAttributes( Tcl_Obj *fileName, /* The name of the file (UTF-8). */ Tcl_Obj *attributePtr) /* The attribute to set. */ { - int yesNo, fileAttributes; - const char *native; + int yesNo, fileAttributes, old; WCHAR *winPath; if (Tcl_GetBooleanFromObj(interp, attributePtr, &yesNo) != TCL_OK) { return TCL_ERROR; } - native = Tcl_FSGetNativePath(fileName); - winPath = winPathFromNative(native); + winPath = winPathFromObj(fileName); - fileAttributes = GetFileAttributesW(winPath); + fileAttributes = old = GetFileAttributesW(winPath); if (fileAttributes == -1) { ckfree(winPath); @@ -2394,7 +2392,8 @@ SetUnixFileAttributes( fileAttributes &= ~attributeArray[objIndex]; } - if (!SetFileAttributesW(winPath, fileAttributes)) { + if ((fileAttributes != old) + && !SetFileAttributesW(winPath, fileAttributes)) { ckfree(winPath); StatError(interp, fileName); return TCL_ERROR; diff --git a/win/tclWinFCmd.c b/win/tclWinFCmd.c index 2700cb3..f14d9ff 100644 --- a/win/tclWinFCmd.c +++ b/win/tclWinFCmd.c @@ -1825,12 +1825,12 @@ SetWinFileAttributes( Tcl_Obj *fileName, /* The name of the file. */ Tcl_Obj *attributePtr) /* The new value of the attribute. */ { - DWORD fileAttributes; + DWORD fileAttributes, old; int yesNo, result; const TCHAR *nativeName; nativeName = Tcl_FSGetNativePath(fileName); - fileAttributes = GetFileAttributes(nativeName); + fileAttributes = old = GetFileAttributes(nativeName); if (fileAttributes == 0xffffffff) { StatError(interp, fileName); @@ -1848,7 +1848,8 @@ SetWinFileAttributes( fileAttributes &= ~(attributeArray[objIndex]); } - if (!SetFileAttributes(nativeName, fileAttributes)) { + if ((fileAttributes != old) + && !SetFileAttributes(nativeName, fileAttributes)) { StatError(interp, fileName); return TCL_ERROR; } -- cgit v0.12 From 8868d903d92c976f3c5eb3ea4a4a98862de6e6c0 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 27 Mar 2014 16:27:09 +0000 Subject: New test iortrans-4.8.1 exposes segfault bug [721ec69271]. --- tests/ioTrans.test | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/ioTrans.test b/tests/ioTrans.test index 5a8874c..b21d894 100644 --- a/tests/ioTrans.test +++ b/tests/ioTrans.test @@ -540,6 +540,25 @@ test iortrans-4.8 {chan read, read, bug 2921116} -setup { rename foo {} } -result {{read rt* {test data }} file*} +test iortrans-4.8.1 {chan read, bug 721ec69271} -setup { + set res {} +} -match glob -body { + proc foo {fd args} { + handle.initialize + handle.finalize + lappend ::res $args + # Kill and recreate transform while it is operating + chan pop $fd + chan push $fd [list foo $fd] + } + set c [chan push [set c [tempchan]] [list foo $c]] + chan configure $c -buffersize 2 + lappend res [read $c] +} -cleanup { + tempdone + rename foo {} +} -result {{read rt* {test data +}} file*} test iortrans-4.9 {chan read, gets, bug 2921116} -setup { set res {} } -match glob -body { -- cgit v0.12 From da36dfe69e58aec61afac3c396af8cf6107b0ff1 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 10 Apr 2014 07:57:18 +0000 Subject: Fix bug [e663138a06]: Test failures in "string is" --- generic/tclExecute.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 41730d3..6394a60 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -5990,6 +5990,15 @@ TEBCresume( if (GetNumberFromObj(NULL, OBJ_AT_TOS, &ptr1, &type1) != TCL_OK) { type1 = 0; } +#ifndef TCL_WIDE_INT_IS_LONG + else if (type1 == TCL_NUMBER_WIDE) { + /** See bug [e663138a06] */ + Tcl_WideInt value = (OBJ_AT_TOS)->internalRep.wideValue; + if ((-value <= ULONG_MAX) && (value <= ULONG_MAX)) { + type1 = TCL_NUMBER_LONG; + } + } +#endif TclNewIntObj(objResultPtr, type1); TRACE(("\"%.20s\" => %d\n", O2S(OBJ_AT_TOS), type1)); NEXT_INST_F(1, 1, 1); -- cgit v0.12 From 09e3a3c56b5d44c637c6ed0593257e51461e8861 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 11 Apr 2014 08:23:44 +0000 Subject: Fix [3118489] for Windows only: NUL in filenames. This allows various characters to be used in win32 filenames which are normally invalid, as described here: [http://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-specialchars]. The Cygwin shell can handle those same filenames as well. In other shells (cmd.exe/mSys) or on the Windows desktop the filenames will look strange, but that's all. --- tests/cmdAH.test | 3 +++ win/tclWinFile.c | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/cmdAH.test b/tests/cmdAH.test index 39e9ece..80706b6 100644 --- a/tests/cmdAH.test +++ b/tests/cmdAH.test @@ -141,6 +141,9 @@ test cmdAH-2.6.2 {cd} -constraints {unix nonPortable} -setup { } -cleanup { cd $dir } -result {/} +test cmdAH-2.6.3 {Tcl_CdObjCmd, bug #3118489} -constraints win -returnCodes error -body { + cd .\0 +} -result "couldn't change working directory to \".\0\": no such file or directory" test cmdAH-2.7 {Tcl_ConcatObjCmd} { concat } {} diff --git a/win/tclWinFile.c b/win/tclWinFile.c index 80d0915..c9b95a0 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -2897,7 +2897,7 @@ TclNativeCreateNativeRep( char *nativePathPtr, *str; Tcl_DString ds; Tcl_Obj *validPathPtr; - int len; + int len, i = 2; WCHAR *wp; if (TclFSCwdIsNative()) { @@ -2927,8 +2927,10 @@ TclNativeCreateNativeRep( Tcl_WinUtfToTChar(str, len, &ds); len = Tcl_DStringLength(&ds) + sizeof(WCHAR); wp = (WCHAR *) Tcl_DStringValue(&ds); - for (; *wp; ++wp) { - if (*wp=='/') { + for (i=sizeof(WCHAR); i|", *wp) ){ + *wp |= 0xF000; + }else if (*wp=='/') { *wp = '\\'; } } -- cgit v0.12 From 7fb053c9643440e5075f5e513853c9efff0ae44d Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 11 Apr 2014 09:55:15 +0000 Subject: Fix [3118489]: NUL in filenames, now fixed for both Windows and UNIX. For consistancy, any NUL character in a filename prevents the native filesystem to generate a native file representation for it. Other filesystems than the native one may still accept it, but it's not recommended. --- tests/cmdAH.test | 2 +- unix/tclUnixFile.c | 6 ++++++ win/tclWinFile.c | 9 +++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/cmdAH.test b/tests/cmdAH.test index 80706b6..04a86fa 100644 --- a/tests/cmdAH.test +++ b/tests/cmdAH.test @@ -141,7 +141,7 @@ test cmdAH-2.6.2 {cd} -constraints {unix nonPortable} -setup { } -cleanup { cd $dir } -result {/} -test cmdAH-2.6.3 {Tcl_CdObjCmd, bug #3118489} -constraints win -returnCodes error -body { +test cmdAH-2.6.3 {Tcl_CdObjCmd, bug #3118489} -returnCodes error -body { cd .\0 } -result "couldn't change working directory to \".\0\": no such file or directory" test cmdAH-2.7 {Tcl_ConcatObjCmd} { diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c index 5bfe5d9..2cb0027 100644 --- a/unix/tclUnixFile.c +++ b/unix/tclUnixFile.c @@ -1105,6 +1105,12 @@ TclNativeCreateNativeRep( str = Tcl_GetStringFromObj(validPathPtr, &len); Tcl_UtfToExternalDString(NULL, str, len, &ds); len = Tcl_DStringLength(&ds) + sizeof(char); + if (strlen(Tcl_DStringValue(&ds)) < len - sizeof(char)) { + /* See bug [3118489]: NUL in filenames */ + Tcl_DecrRefCount(validPathPtr); + Tcl_DStringFree(&ds); + return NULL; + } Tcl_DecrRefCount(validPathPtr); nativePathPtr = ckalloc(len); memcpy(nativePathPtr, Tcl_DStringValue(&ds), (size_t) len); diff --git a/win/tclWinFile.c b/win/tclWinFile.c index c9b95a0..fc0ac9e 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -1816,6 +1816,9 @@ TclpObjChdir( nativePath = Tcl_FSGetNativePath(pathPtr); + if (!nativePath) { + return -1; + } result = SetCurrentDirectory(nativePath); if (result == 0) { @@ -2929,6 +2932,12 @@ TclNativeCreateNativeRep( wp = (WCHAR *) Tcl_DStringValue(&ds); for (i=sizeof(WCHAR); i|", *wp) ){ + if (!*wp){ + /* See bug [3118489]: NUL in filenames */ + Tcl_DecrRefCount(validPathPtr); + Tcl_DStringFree(&ds); + return NULL; + } *wp |= 0xF000; }else if (*wp=='/') { *wp = '\\'; -- cgit v0.12 From 7b02be1867d1e46c5a4b5bc9f8925a4a6784c3fd Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 14 Apr 2014 18:45:04 +0000 Subject: [e663138a06] Fix the new INST_NUM_TYPE instruction so that the boundary cases of [string is] on integral values are computed right. Code is now correct, though still suffers from a large amount of ugly. --- generic/tclExecute.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 6394a60..2c136d7 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -5989,16 +5989,32 @@ TEBCresume( case INST_NUM_TYPE: if (GetNumberFromObj(NULL, OBJ_AT_TOS, &ptr1, &type1) != TCL_OK) { type1 = 0; - } + } else if (type1 == TCL_NUMBER_LONG) { + /* value is between LONG_MIN and LONG_MAX */ + /* [string is integer] is -UINT_MAX to UINT_MAX range */ + int i; + + if (Tcl_GetIntFromObj(NULL, OBJ_AT_TOS, &i) != TCL_OK) { + type1 = TCL_NUMBER_WIDE; + } #ifndef TCL_WIDE_INT_IS_LONG - else if (type1 == TCL_NUMBER_WIDE) { - /** See bug [e663138a06] */ - Tcl_WideInt value = (OBJ_AT_TOS)->internalRep.wideValue; - if ((-value <= ULONG_MAX) && (value <= ULONG_MAX)) { + } else if (type1 == TCL_NUMBER_WIDE) { + /* value is between WIDE_MIN and WIDE_MAX */ + /* [string is wideinteger] is -UWIDE_MAX to UWIDE_MAX range */ + int i; + if (Tcl_GetIntFromObj(NULL, OBJ_AT_TOS, &i) == TCL_OK) { type1 = TCL_NUMBER_LONG; } - } #endif + } else if (type1 == TCL_NUMBER_BIG) { + /* value is an integer outside the WIDE_MIN to WIDE_MAX range */ + /* [string is wideinteger] is -UWIDE_MAX to UWIDE_MAX range */ + Tcl_WideInt w; + + if (Tcl_GetWideIntFromObj(NULL, OBJ_AT_TOS, &w) == TCL_OK) { + type1 = TCL_NUMBER_WIDE; + } + } TclNewIntObj(objResultPtr, type1); TRACE(("\"%.20s\" => %d\n", O2S(OBJ_AT_TOS), type1)); NEXT_INST_F(1, 1, 1); -- cgit v0.12 From 363b6911107557283c7fec07e041e14c7af7eee3 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 15 Apr 2014 10:41:44 +0000 Subject: Test-cases which pick up the completion of bug-fix [e663138a06d98e48b5fbb42cc015cf1698f486cd|e663138a06]. Thanks, Don! --- tests/obj.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/obj.test b/tests/obj.test index 71a39b4..151abfb 100644 --- a/tests/obj.test +++ b/tests/obj.test @@ -605,7 +605,7 @@ test obj-33.2 {integer overflow on input} {longIs32bit wideBiggerThanInt} { set x 0xffff; append x ffff list [string is integer $x] [expr { wide($x) }] } {1 4294967295} -test obj-33.3 {integer overflow on input} {longIs32bit wideBiggerThanInt} { +test obj-33.3 {integer overflow on input} { set x 0x10000; append x 0000 list [string is integer $x] [expr { wide($x) }] } {0 4294967296} @@ -621,7 +621,7 @@ test obj-33.6 {integer overflow on input} {longIs32bit wideBiggerThanInt} { set x -0xffff; append x ffff list [string is integer $x] [expr { wide($x) }] } {1 -4294967295} -test obj-33.7 {integer overflow on input} {longIs32bit wideBiggerThanInt} { +test obj-33.7 {integer overflow on input} { set x -0x10000; append x 0000 list [string is integer $x] [expr { wide($x) }] } {0 -4294967296} -- cgit v0.12 From ba983af978b8a50b61dd8dbebf32bdeed71a9837 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Wed, 16 Apr 2014 11:20:54 +0000 Subject: Remove unused variable, don't use deprecated function, some formatting. --- generic/tclIORChan.c | 2 +- win/tclWinInit.c | 10 +++++----- win/tclWinSock.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index 16dc1ed..29819b6 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -2324,7 +2324,7 @@ InvokeTclMethod( Tcl_IncrRefCount(cmd); sr = Tcl_SaveInterpState(rcPtr->interp, 0 /* Dummy */); Tcl_Preserve(rcPtr->interp); - result = Tcl_GlobalEvalObj(rcPtr->interp, cmd); + result = Tcl_EvalObjEx(rcPtr->interp, cmd, TCL_EVAL_GLOBAL); /* * We do not try to extract the result information if the caller has no diff --git a/win/tclWinInit.c b/win/tclWinInit.c index d90d57a..8b600f6 100644 --- a/win/tclWinInit.c +++ b/win/tclWinInit.c @@ -135,11 +135,11 @@ TclpInitPlatform(void) tclPlatform = TCL_PLATFORM_WINDOWS; - /* - * Initialize the winsock library. On Windows XP and higher this - * can never fail. - */ - WSAStartup(wVersionRequested, &wsaData); + /* + * Initialize the winsock library. On Windows XP and higher this + * can never fail. + */ + WSAStartup(wVersionRequested, &wsaData); #ifdef STATIC_BUILD /* diff --git a/win/tclWinSock.c b/win/tclWinSock.c index 8881cf2..3990111 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -280,7 +280,7 @@ static const Tcl_ChannelType tcpChannelType = { static void InitSockets(void) { - DWORD id, err; + DWORD id; ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); if (!initialized) { @@ -2414,7 +2414,7 @@ SocketThread( * * Side effects: * The flags for the given socket are updated to reflect the event that - * occured. + * occurred. * *---------------------------------------------------------------------- */ -- cgit v0.12 From a99f768a32b42d04735d090f7d6fd8a0f75bc8ec Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 17 Apr 2014 14:01:14 +0000 Subject: Remove all win95-specific test-cases, since Windows 95 is not supported any more. --- tests/fCmd.test | 6 ---- tests/http.test | 12 +++---- tests/winFCmd.test | 96 ++---------------------------------------------------- tests/winFile.test | 18 ---------- tests/winPipe.test | 8 ----- 5 files changed, 6 insertions(+), 134 deletions(-) diff --git a/tests/fCmd.test b/tests/fCmd.test index 8f27ad4..3d22b09 100644 --- a/tests/fCmd.test +++ b/tests/fCmd.test @@ -511,12 +511,6 @@ test fCmd-6.6 {CopyRenameOneFile: errno != ENOENT} -setup { } -returnCodes error -cleanup { testchmod 755 td1 } -result {error renaming "tf1" to "td1/tf1": permission denied} -test fCmd-6.7 {CopyRenameOneFile: errno != ENOENT} -setup { - cleanup -} -constraints {win 95} -returnCodes error -body { - createfile tf1 - file rename tf1 $long -} -result [subst {error renaming "tf1" to "$long": file name too long}] test fCmd-6.9 {CopyRenameOneFile: errno == ENOENT} -setup { cleanup } -constraints {unix notRoot} -body { diff --git a/tests/http.test b/tests/http.test index a52cfb1..a0a26de 100644 --- a/tests/http.test +++ b/tests/http.test @@ -492,14 +492,10 @@ proc myProgress {token total current} { } set progress [list $total $current] } -if 0 { - # This test hangs on Windows95 because the client never gets EOF - set httpLog 1 - test http-4.6.1 {http::Event} knownBug { - set token [http::geturl $url -blocksize 50 -progress myProgress] - return $progress - } {111 111} -} +test http-4.6.1 {http::Event} knownBug { + set token [http::geturl $url -blocksize 50 -progress myProgress] + return $progress +} {111 111} test http-4.7 {http::Event} -body { set token [http::geturl $url -keepalive 0 -progress myProgress] return $progress diff --git a/tests/winFCmd.test b/tests/winFCmd.test index 28a0e9f..bd50328 100644 --- a/tests/winFCmd.test +++ b/tests/winFCmd.test @@ -208,22 +208,11 @@ test winFCmd-1.13 {TclpRenameFile: errno: EACCES} -setup { } -constraints {win win2000orXP testfile} -body { testfile mv nul tf1 } -returnCodes error -result EINVAL -test winFCmd-1.13.1 {TclpRenameFile: errno: EACCES} -setup { +test winFCmd-1.14 {TclpRenameFile: errno: EACCES} -setup { cleanup } -constraints {win nt winOlderThan2000 testfile} -body { testfile mv nul tf1 } -returnCodes error -result EACCES -test winFCmd-1.13.2 {TclpRenameFile: errno: ENOENT} -setup { - cleanup -} -constraints {win 95 testfile} -body { - testfile mv nul tf1 -} -returnCodes error -result ENOENT -test winFCmd-1.14 {TclpRenameFile: errno: EACCES} -setup { - cleanup -} -constraints {win 95 testfile} -body { - createfile tf1 - testfile mv tf1 nul -} -returnCodes error -result EACCES test winFCmd-1.15 {TclpRenameFile: errno: EEXIST} -setup { cleanup } -constraints {win nt testfile} -body { @@ -257,11 +246,6 @@ test winFCmd-1.19.1 {TclpRenameFile: errno == EACCES} -setup { } -constraints {win nt winOlderThan2000 testfile} -body { testfile mv nul tf1 } -returnCodes error -result EACCES -test winFCmd-1.19.2 {TclpRenameFile: errno == ENOENT} -setup { - cleanup -} -constraints {win 95 testfile} -body { - testfile mv nul tf1 -} -returnCodes error -result ENOENT test winFCmd-1.20 {TclpRenameFile: src is dir} -setup { cleanup } -constraints {win nt testfile} -body { @@ -474,29 +458,14 @@ test winFCmd-2.6 {TclpCopyFile: errno: ENOENT} -setup { } -returnCodes error -result ENOENT test winFCmd-2.7 {TclpCopyFile: errno: EACCES} -setup { cleanup -} -constraints {win 95 testfile} -body { - createfile tf1 - set fd [open tf2 w] - testfile cp tf1 tf2 -} -cleanup { - close $fd - cleanup -} -returnCodes error -result EACCES -test winFCmd-2.8 {TclpCopyFile: errno: EACCES} -setup { - cleanup } -constraints {win win2000orXP testfile} -body { testfile cp nul tf1 } -returnCodes error -result EINVAL -test winFCmd-2.8.1 {TclpCopyFile: errno: EACCES} -setup { +test winFCmd-2.8 {TclpCopyFile: errno: EACCES} -setup { cleanup } -constraints {win nt winOlderThan2000 testfile} -body { testfile cp nul tf1 } -returnCodes error -result EACCES -test winFCmd-2.9 {TclpCopyFile: errno: ENOENT} -setup { - cleanup -} -constraints {win 95 testfile} -body { - testfile cp nul tf1 -} -returnCodes error -result ENOENT test winFCmd-2.10 {TclpCopyFile: CopyFile succeeds} -setup { cleanup } -constraints {win testfile} -body { @@ -573,17 +542,6 @@ test winFCmd-2.17 {TclpCopyFile: dst is readonly} -setup { catch {testchmod 666 tf2} cleanup } -result {1 tf1} -test winFCmd-2.18 {TclpCopyFile: still can't copy onto dst} -setup { - cleanup -} -constraints {win 95 testfile testchmod} -body { - createfile tf1 - createfile tf2 - testchmod 000 tf2 - set fd [open tf2] - set msg [list [catch {testfile cp tf1 tf2} msg] $msg] - close $fd - lappend msg [file writable tf2] -} -result {1 EACCES 0} test winFCmd-3.1 {TclpDeleteFile: errno: EACCES} -body { testfile rm $cdfile $cdrom/dummy~~.fil @@ -666,9 +624,6 @@ test winFCmd-3.11 {TclpDeleteFile: still can't remove path} -setup { test winFCmd-4.1 {TclpCreateDirectory: errno: EACCES} -body { testfile mkdir $cdrom/dummy~~.dir } -constraints {win nt cdrom testfile} -returnCodes error -result EACCES -test winFCmd-4.2 {TclpCreateDirectory: errno: EACCES} -body { - testfile mkdir $cdrom/dummy~~.dir -} -constraints {win 95 cdrom testfile} -returnCodes error -result ENOSPC test winFCmd-4.3 {TclpCreateDirectory: errno: EEXIST} -setup { cleanup } -constraints {win testfile} -body { @@ -764,11 +719,6 @@ test winFCmd-6.9 {TclpRemoveDirectory: errno == EACCES} -setup { catch {testchmod 666 td1} cleanup } -result {td1 EACCES} -test winFCmd-6.10 {TclpRemoveDirectory: attr == -1} -setup { - cleanup -} -constraints {win 95 testfile} -body { - testfile rmdir nul -} -returnCodes error -result {nul EACCES} test winFCmd-6.11 {TclpRemoveDirectory: attr == -1} -setup { cleanup } -constraints {win nt testfile} -body { @@ -776,16 +726,6 @@ test winFCmd-6.11 {TclpRemoveDirectory: attr == -1} -setup { # WinXP returns EEXIST, WinNT seems to return EACCES. No policy # decision has been made as to which is correct. } -returnCodes error -match regexp -result {^/ E(ACCES|EXIST)$} -# This next test has a very hokey way of matching... -test winFCmd-6.12 {TclpRemoveDirectory: errno == EACCES} -setup { - cleanup -} -constraints {win 95 testfile} -body { - createfile tf1 - set res [catch {testfile rmdir tf1} msg] - # get rid of path - set msg [list [file tail [lindex $msg 0]] [lindex $msg 1]] - list $res $msg -} -result {1 {tf1 ENOTDIR}} test winFCmd-6.13 {TclpRemoveDirectory: write-protected} -setup { cleanup } -constraints {winVista testfile testchmod} -body { @@ -798,16 +738,6 @@ test winFCmd-6.13 {TclpRemoveDirectory: write-protected} -setup { cleanup } -returnCodes error -result {td1 EACCES} # This next test has a very hokey way of matching... -test winFCmd-6.14 {TclpRemoveDirectory: check if empty dir} -setup { - cleanup -} -constraints {win 95 testfile} -body { - file mkdir td1/td2 - set res [catch {testfile rmdir td1} msg] - # get rid of path - set msg [list [file tail [lindex $msg 0]] [lindex $msg 1]] - list $res $msg -} -result {1 {td1 EEXIST}} -# This next test has a very hokey way of matching... test winFCmd-6.15 {TclpRemoveDirectory: !recursive} -setup { cleanup } -constraints {win testfile} -body { @@ -887,11 +817,6 @@ test winFCmd-7.7 {TraverseWinTree: append \ to source if necessary} -setup { } -cleanup { cleanup } -result {tf1} -test winFCmd-7.8 {TraverseWinTree: append \ to source if necessary} -body { - # cdrom can return either d:\ or D:/, but we only care about the errcode - testfile rmdir $cdrom/ -} -constraints {win 95 cdrom testfile} -returnCodes error -match glob \ - -result {* EACCES} ; # was EEXIST, but changed for win98. test winFCmd-7.9 {TraverseWinTree: append \ to source if necessary} -body { testfile rmdir $cdrom/ } -constraints {win nt cdrom testfile} -returnCodes error -match glob \ @@ -930,14 +855,6 @@ test winFCmd-7.13 {TraverseWinTree: append \ to target if necessary} -setup { } -cleanup { cleanup } -result {tf1} -test winFCmd-7.14 {TraverseWinTree: append \ to target if necessary} -setup { - cleanup -} -constraints {win 95 testfile} -body { - file mkdir td1 - testfile cpdir td1 / -} -cleanup { - cleanup -} -returnCodes error -result {/ EEXIST} test winFCmd-7.15 {TraverseWinTree: append \ to target if necessary} -setup { cleanup } -constraints {win nt testfile} -body { @@ -1038,15 +955,6 @@ test winFCmd-9.1 {TraversalDelete: DOTREE_F} -setup { createfile td1/tf1 testfile rmdir -force td1 } -result {} -test winFCmd-9.2 {TraversalDelete: DOTREE_F} -setup { - cleanup -} -constraints {win 95 testfile} -body { - file mkdir td1 - set fd [open td1/tf1 w] - testfile rmdir -force td1 -} -cleanup { - close $fd -} -returnCodes error -result {td1\tf1 EACCES} test winFCmd-9.3 {TraversalDelete: DOTREE_PRED} -setup { cleanup } -constraints {winVista testfile testchmod} -body { diff --git a/tests/winFile.test b/tests/winFile.test index fba9bcb..2c47f5f 100644 --- a/tests/winFile.test +++ b/tests/winFile.test @@ -37,24 +37,6 @@ test winFile-1.2 {TclpGetUserHome} -constraints {win nt nonPortable} -body { # The administrator account should always exist. glob ~administrator } -match glob -result * -test winFile-1.3 {TclpGetUserHome} -constraints {win 95} -body { - # Find some user in system.ini and then see if they have a home. - - set f [open $::env(windir)/system.ini] - while {[gets $f line] >= 0} { - if {$line ne {[Password Lists]}} { - continue - } - gets $f - set name [lindex [split [gets $f] =] 0] - if {$name ne ""} { - return [catch {glob ~$name}] - } - } - return 0 ;# didn't find anything... -} -cleanup { - catch {close $f} -} -result {0} test winFile-1.4 {TclpGetUserHome} {win nt nonPortable} { catch {glob ~stanton@workgroup} } {0} diff --git a/tests/winPipe.test b/tests/winPipe.test index d2e804d..9c6f94d 100644 --- a/tests/winPipe.test +++ b/tests/winPipe.test @@ -82,10 +82,6 @@ test winpipe-1.4 {32 bit comprehensive tests: a lot from pipe} {win nt exec cat3 exec [interpreter] $path(more) < $path(big) | $cat32 > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } "{$big} stderr32" -test winpipe-1.5 {32 bit comprehensive tests: a lot from pipe} {win 95 exec cat32} { - exec command /c type $path(big) |& $cat32 > $path(stdout) 2> $path(stderr) - list [contents $path(stdout)] [contents $path(stderr)] -} "{$big} stderr32" test winpipe-1.6 {32 bit comprehensive tests: from console} \ {win cat32 AllocConsole} { # would block waiting for human input @@ -174,10 +170,6 @@ test winpipe-1.21 {32 bit comprehensive tests: read/write application} \ catch {close $f} set r } "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -test winpipe-1.22 {Checking command.com for Win95/98 hanging} {win 95 exec} { - exec command.com /c dir /b - set result 1 -} 1 test winpipe-4.1 {Tcl_WaitPid} {win nt exec cat32} { proc readResults {f} { -- cgit v0.12 From 790e5adaf4cabf6c9dcaa3d109427dbe18f786ff Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 24 Apr 2014 15:27:58 +0000 Subject: Make sure the ReflectedChannel struct is freed in the handler thread, where it was allocated. This constraint allows the struct to safely hold Tcl_Obj values, which has been convenient for storing callback commands. --- generic/tclIORChan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index e462f61..94428bb 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -1145,6 +1145,7 @@ ReflectClose( if (result != TCL_OK) { FreeReceivedError(&p); } + return EOK; } #endif @@ -1169,8 +1170,6 @@ ReflectClose( Tcl_DeleteEvents(ReflectEventDelete, rcPtr); - Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); - if (result != TCL_OK) { PassReceivedErrorInterp(interp, &p); } @@ -2903,6 +2902,7 @@ ForwardProc( Tcl_GetChannelName(rcPtr->chan)); Tcl_DeleteHashEntry(hPtr); + Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); break; case ForwardedInput: { -- cgit v0.12 From 0781259dd17444340c1a926c4cd2b5ade72bfebe Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 25 Apr 2014 17:34:11 +0000 Subject: Test iortrans-4.8.2 demos an infinite loop. Possible trouble with pushback buffers. --- generic/tclIO.c | 5 +++++ tests/ioTrans.test | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/generic/tclIO.c b/generic/tclIO.c index e6439ef..41ac1e1 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -5611,6 +5611,11 @@ DoReadChars( ResetFlag(statePtr, CHANNEL_BLOCKED); } result = GetInput(chanPtr); +if (chanPtr != statePtr->topChanPtr) { +Tcl_Release(chanPtr); +chanPtr = statePtr->topChanPtr; +Tcl_Preserve(chanPtr); +} if (result != 0) { if (result == EAGAIN) { break; diff --git a/tests/ioTrans.test b/tests/ioTrans.test index b21d894..3bbd170 100644 --- a/tests/ioTrans.test +++ b/tests/ioTrans.test @@ -559,6 +559,26 @@ test iortrans-4.8.1 {chan read, bug 721ec69271} -setup { rename foo {} } -result {{read rt* {test data }} file*} +test iortrans-4.8.2 {chan read, bug 721ec69271} -setup { + set res {} +} -match glob -body { + proc foo {fd args} { + handle.initialize + handle.finalize + lappend ::res $args + # Kill and recreate transform while it is operating + chan pop $fd + chan push $fd [list foo $fd] + return x + } + set c [chan push [set c [tempchan]] [list foo $c]] + chan configure $c -buffersize 1 + lappend res [read $c] +} -cleanup { + tempdone + rename foo {} +} -result {{read rt* {test data +}} file*} test iortrans-4.9 {chan read, gets, bug 2921116} -setup { set res {} } -match glob -body { -- cgit v0.12 From 4119a864755c221944bcd1967b8243a2acc3d9aa Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 25 Apr 2014 19:51:36 +0000 Subject: Disable buffer recycling, which creates mysteries. --- generic/tclIO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 41ac1e1..df863cc 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -2342,7 +2342,7 @@ RecycleBuffer( * Do we have to free the buffer to the OS? */ - if (mustDiscard) { + if (1 || mustDiscard) { ReleaseChannelBuffer(bufPtr); return; } -- cgit v0.12 From 9a76d245a9dcf48449c6f147252a9be6b43abf09 Mon Sep 17 00:00:00 2001 From: ferrieux Date: Mon, 28 Apr 2014 20:28:10 +0000 Subject: Clarify fcopy manpage regarding its bidirectional uses. [1350564] --- doc/fcopy.n | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/doc/fcopy.n b/doc/fcopy.n index ec3d5c6..071896c 100644 --- a/doc/fcopy.n +++ b/doc/fcopy.n @@ -46,8 +46,11 @@ non-blocking mode; the \fBfcopy\fR command takes care of that automatically. However, it is necessary to enter the event loop by using the \fBvwait\fR command or by using Tk. .PP -You are not allowed to do other I/O operations with -\fIinchan\fR or \fIoutchan\fR during a background \fBfcopy\fR. +You are not allowed to do other input operations with \fIinchan\fR, or +output operations with \fIoutchan\fR, during a background +\fBfcopy\fR. The converse is entirely legitimate, as exhibited by the +bidirectional fcopy example below. +.PP If either \fIinchan\fR or \fIoutchan\fR get closed while the copy is in progress, the current copy is stopped and the command callback is \fInot\fR made. @@ -57,7 +60,7 @@ then all data already queued for \fIoutchan\fR is written out. Note that \fIinchan\fR can become readable during a background copy. You should turn off any \fBfileevent\fR handlers during a background copy so those handlers do not interfere with the copy. -Any I/O attempted by a \fBfileevent\fR handler will get a +Any wrong-sided I/O attempted (by a \fBfileevent\fR handler or otherwise) will get a .QW "channel busy" error. .PP @@ -149,6 +152,24 @@ set total 0 -command [list CopyMore $in $out $chunk] vwait done .CE +.PP +The fourth example starts an asynchronous, bidirectional fcopy between +two sockets. Those could also be pipes from two [open "|hal 9000" r+] +(though their conversation would remain secret to the script, since +all four fileevent slots are busy). +.PP +.CS +set flows 2 +proc Done {dir args} { + global flows done + puts "$dir is over." + incr flows -1 + if {$flows<=0} {set done 1} +} +\fBfcopy\fR $sok1 $sok2 -command [list Done UP] +\fBfcopy\fR $sok2 $sok1 -command [list Done DOWN] +vwait done +.CE .SH "SEE ALSO" eof(n), fblocked(n), fconfigure(n), file(n) .SH KEYWORDS -- cgit v0.12 From 10d7a2ac566063ffdd10a932a0d610ae6ecd62dd Mon Sep 17 00:00:00 2001 From: dkf Date: Wed, 30 Apr 2014 21:24:39 +0000 Subject: [82e7f67325] Fix an evil refcount problem in compiled [string replace]. --- generic/tclExecute.c | 14 ++++++++++++-- tests/stringComp.test | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 2c136d7..4ecca5b 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -5702,11 +5702,21 @@ TEBCresume( length - toIdx); } } else { - objResultPtr = value3Ptr; + /* + * Be careful with splicing the stack in this case; we have a + * refCount:1 object in value3Ptr and we want to append to it and + * make it be the refCount:1 object at the top of the stack + * afterwards. [Bug 82e7f67325] + */ + if (toIdx < length) { - Tcl_AppendUnicodeToObj(objResultPtr, ustring1 + toIdx + 1, + Tcl_AppendUnicodeToObj(value3Ptr, ustring1 + toIdx + 1, length - toIdx); } + TRACE_APPEND(("\"%.30s\"\n", O2S(value3Ptr))); + TclDecrRefCount(valuePtr); + OBJ_AT_TOS = value3Ptr; /* Tricky! */ + NEXT_INST_F(1, 0, 0); } TclDecrRefCount(value3Ptr); TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr))); diff --git a/tests/stringComp.test b/tests/stringComp.test index 9e00ce7..39dac78 100644 --- a/tests/stringComp.test +++ b/tests/stringComp.test @@ -26,6 +26,22 @@ catch [list package require -exact Tcltest [info patchlevel]] # Some tests require the testobj command testConstraint testobj [expr {[info commands testobj] != {}}] +testConstraint memory [llength [info commands memory]] +if {[testConstraint memory]} { + proc getbytes {} { + set lines [split [memory info] \n] + return [lindex $lines 3 3] + } + proc leaktest {script {iterations 3}} { + set end [getbytes] + for {set i 0} {$i < $iterations} {incr i} { + uplevel 1 $script + set tmp $end + set end [getbytes] + } + return [expr {$end - $tmp}] + } +} test stringComp-1.1 {error conditions} { proc foo {} {string gorp a b} @@ -687,7 +703,23 @@ test stringComp-12.1 {Bug 3588366: end-offsets before start} { ## not yet bc ## string replace -## not yet bc +test stringComp-14.1 {Bug 82e7f67325} { + apply {{} { + set a [join {a b} {}] + lappend b [string length [string replace ___! 0 2 $a]] + lappend b [string length [string replace ___! 0 2 $a[unset a]]] + }} +} {3 3} +test stringComp-14.2 {Bug 82e7f67325} { + # As in stringComp-14.1, but make sure we don't retain too many refs + leaktest { + apply {{} { + set a [join {a b} {}] + lappend b [string length [string replace ___! 0 2 $a]] + lappend b [string length [string replace ___! 0 2 $a[unset a]]] + }} + } +} {0} ## string tolower ## not yet bc -- cgit v0.12 From f715c2fad2a69457bbcbdf99167c66a3f62ed3a5 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 1 May 2014 01:15:42 +0000 Subject: missing constraint --- tests/stringComp.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stringComp.test b/tests/stringComp.test index 39dac78..0d134b5 100644 --- a/tests/stringComp.test +++ b/tests/stringComp.test @@ -710,7 +710,7 @@ test stringComp-14.1 {Bug 82e7f67325} { lappend b [string length [string replace ___! 0 2 $a[unset a]]] }} } {3 3} -test stringComp-14.2 {Bug 82e7f67325} { +test stringComp-14.2 {Bug 82e7f67325} memory { # As in stringComp-14.1, but make sure we don't retain too many refs leaktest { apply {{} { -- cgit v0.12 From f90303fa441e484833044f364aae0974a6a705d4 Mon Sep 17 00:00:00 2001 From: dkf Date: Thu, 1 May 2014 09:11:09 +0000 Subject: make doubly sure that things which should be unshared stay unshared --- tests/stringComp.test | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/stringComp.test b/tests/stringComp.test index 0d134b5..165ef20 100644 --- a/tests/stringComp.test +++ b/tests/stringComp.test @@ -704,20 +704,20 @@ test stringComp-12.1 {Bug 3588366: end-offsets before start} { ## string replace test stringComp-14.1 {Bug 82e7f67325} { - apply {{} { - set a [join {a b} {}] + apply {x { + set a [join $x {}] lappend b [string length [string replace ___! 0 2 $a]] lappend b [string length [string replace ___! 0 2 $a[unset a]]] - }} + }} {a b} } {3 3} test stringComp-14.2 {Bug 82e7f67325} memory { # As in stringComp-14.1, but make sure we don't retain too many refs leaktest { - apply {{} { - set a [join {a b} {}] + apply {x { + set a [join $x {}] lappend b [string length [string replace ___! 0 2 $a]] lappend b [string length [string replace ___! 0 2 $a[unset a]]] - }} + }} {a b} } } {0} -- cgit v0.12 From b18161555e63f857014d2306adcb9fbcad3c6144 Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 1 May 2014 16:33:39 +0000 Subject: Stop the segfault in iogt-2.4. First by changing the UpdateInterest() call that triggers it. "downChanPtr" may no longer be the right argument at that point. Second, after ending the segfault, the test became an infinite loop (nested unstacking?! whoa.), so revised the test to one that terminates (and passes). Left behind a comment that the recursive unstacking case may require more examination. --- generic/tclIO.c | 9 ++++++++- tests/iogt.test | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 776ff12..a83cdcd 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -1876,6 +1876,13 @@ Tcl_UnstackChannel( * into the old structure. */ + /* + * TODO: Figure out how to handle the situation where the chan + * operations called below by this unstacking operation cause + * another unstacking recursively. In that case the downChanPtr + * value we're holding on to will not be the right thing. + */ + Channel *downChanPtr = chanPtr->downChanPtr; /* @@ -1980,7 +1987,7 @@ Tcl_UnstackChannel( */ Tcl_EventuallyFree(chanPtr, TCL_DYNAMIC); - UpdateInterest(downChanPtr); + UpdateInterest(statePtr->topChanPtr); if (result != 0) { Tcl_SetErrno(result); diff --git a/tests/iogt.test b/tests/iogt.test index bd3c67b..ded8bb9 100644 --- a/tests/iogt.test +++ b/tests/iogt.test @@ -228,7 +228,7 @@ proc id_torture {chan op data} { delete/read - clear_read {;#ignore} flush/write - - flush/read - + flush/read {} write - read { testchannel unstack $chan -- cgit v0.12 From 4f1714013f16d9993d2d68175d81fdb91ffc8190 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 2 May 2014 12:39:14 +0000 Subject: Re-enable buffer recycling. --- generic/tclIO.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index a83cdcd..8ae2fd2 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -2360,7 +2360,7 @@ RecycleBuffer( mustDiscard = 1; } - if (1 || mustDiscard) { + if (mustDiscard) { ReleaseChannelBuffer(bufPtr); return; } -- cgit v0.12 From 3452d681c93ec5cab5edc2d45bbd0d02f9beadb1 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 2 May 2014 13:02:48 +0000 Subject: Fully restore topChan resetting to accommodate self-restacking channels. --- generic/tclIO.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 8ae2fd2..adea32e 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -4554,9 +4554,12 @@ Tcl_GetsObj( * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ - /* - chanPtr = statePtr->topChanPtr; - */ + + if (chanPtr != statePtr->topChanPtr) { + Tcl_Release(chanPtr); + chanPtr = statePtr->topChanPtr; + Tcl_Preserve(chanPtr); + } bufPtr = gs.bufPtr; if (bufPtr == NULL) { @@ -4590,9 +4593,11 @@ Tcl_GetsObj( * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ - /* - chanPtr = statePtr->topChanPtr; - */ + if (chanPtr != statePtr->topChanPtr) { + Tcl_Release(chanPtr); + chanPtr = statePtr->topChanPtr; + Tcl_Preserve(chanPtr); + } bufPtr = statePtr->inQueueHead; if (bufPtr != NULL) { bufPtr->nextRemoved = oldRemoved; @@ -4632,9 +4637,11 @@ Tcl_GetsObj( * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ - /* - chanPtr = statePtr->topChanPtr; - */ + if (chanPtr != statePtr->topChanPtr) { + Tcl_Release(chanPtr); + chanPtr = statePtr->topChanPtr; + Tcl_Preserve(chanPtr); + } UpdateInterest(chanPtr); Tcl_Release(chanPtr); return copiedTotal; @@ -5638,11 +5645,11 @@ DoReadChars( ResetFlag(statePtr, CHANNEL_BLOCKED); } result = GetInput(chanPtr); -if (chanPtr != statePtr->topChanPtr) { -Tcl_Release(chanPtr); -chanPtr = statePtr->topChanPtr; -Tcl_Preserve(chanPtr); -} + if (chanPtr != statePtr->topChanPtr) { + Tcl_Release(chanPtr); + chanPtr = statePtr->topChanPtr; + Tcl_Preserve(chanPtr); + } if (result != 0) { if (result == EAGAIN) { break; @@ -5673,9 +5680,11 @@ Tcl_Preserve(chanPtr); * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ - /* - chanPtr = statePtr->topChanPtr; - */ + if (chanPtr != statePtr->topChanPtr) { + Tcl_Release(chanPtr); + chanPtr = statePtr->topChanPtr; + Tcl_Preserve(chanPtr); + } UpdateInterest(chanPtr); Tcl_Release(chanPtr); return copied; -- cgit v0.12 From ab2c4a52f1dbcc67939ad86233d21cf7fc38a5cd Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 2 May 2014 14:45:03 +0000 Subject: Add some comments about possible other self-restacking troubles. --- generic/tclIO.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index adea32e..58c7b3c 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -1747,6 +1747,10 @@ Tcl_StackChannel( statePtr->csPtrR = NULL; statePtr->csPtrW = NULL; + /* + * TODO: Examine what can go wrong if Tcl_Flush() call disturbs + * the stacking state of this channel during its operations. + */ if (Tcl_Flush((Tcl_Channel) prevChanPtr) != TCL_OK) { statePtr->csPtrR = csPtrR; statePtr->csPtrW = csPtrW; @@ -9786,12 +9790,15 @@ StackSetBlockMode( { int result = 0; Tcl_DriverBlockModeProc *blockModeProc; + ChannelState *statePtr = chanPtr->state; /* * Start at the top of the channel stack + * TODO: Examine what can go wrong when blockModeProc calls + * disturb the stacking state of the channel. */ - chanPtr = chanPtr->state->topChanPtr; + chanPtr = statePtr->topChanPtr; while (chanPtr != NULL) { blockModeProc = Tcl_ChannelBlockModeProc(chanPtr->typePtr); if (blockModeProc != NULL) { -- cgit v0.12