summaryrefslogtreecommitdiffstats
path: root/win/tclWinChan.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinChan.c')
-rw-r--r--win/tclWinChan.c484
1 files changed, 289 insertions, 195 deletions
diff --git a/win/tclWinChan.c b/win/tclWinChan.c
index 66b332d..48acacb 100644
--- a/win/tclWinChan.c
+++ b/win/tclWinChan.c
@@ -8,8 +8,6 @@
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tclWinChan.c,v 1.44 2005/07/24 22:56:46 dkf Exp $
*/
#include "tclWinInt.h"
@@ -85,7 +83,7 @@ static ThreadSpecificData *FileInit(void);
static int FileInputProc(ClientData instanceData, char *buf,
int toRead, int *errorCode);
static int FileOutputProc(ClientData instanceData,
- CONST char *buf, int toWrite, int *errorCode);
+ const char *buf, int toWrite, int *errorCode);
static int FileSeekProc(ClientData instanceData, long offset,
int mode, int *errorCode);
static Tcl_WideInt FileWideSeekProc(ClientData instanceData,
@@ -96,14 +94,15 @@ static void FileThreadActionProc(ClientData instanceData,
int action);
static int FileTruncateProc(ClientData instanceData,
Tcl_WideInt length);
-
+static DWORD FileGetType(HANDLE handle);
+static int NativeIsComPort(CONST TCHAR *nativeName);
/*
* This structure describes the channel type structure for file based IO.
*/
-static Tcl_ChannelType fileChannelType = {
+static const Tcl_ChannelType fileChannelType = {
"file", /* Type name. */
- TCL_CHANNEL_VERSION_4, /* v4 channel */
+ TCL_CHANNEL_VERSION_5, /* v5 channel */
FileCloseProc, /* Close proc. */
FileInputProc, /* Input proc. */
FileOutputProc, /* Output proc. */
@@ -118,25 +117,8 @@ static Tcl_ChannelType fileChannelType = {
NULL, /* handler proc. */
FileWideSeekProc, /* Wide seek proc. */
FileThreadActionProc, /* Thread action proc. */
- FileTruncateProc, /* Truncate proc. */
+ FileTruncateProc /* Truncate proc. */
};
-
-#ifdef HAVE_NO_SEH
-/*
- * Unlike Borland and Microsoft, we don't register exception handlers by
- * pushing registration records onto the runtime stack. Instead, we register
- * them by creating an EXCEPTION_REGISTRATION within the activation record.
- */
-
-typedef struct EXCEPTION_REGISTRATION {
- struct EXCEPTION_REGISTRATION* link;
- EXCEPTION_DISPOSITION (*handler)(
- struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);
- void* ebp;
- void* esp;
- int status;
-} EXCEPTION_REGISTRATION;
-#endif
/*
*----------------------------------------------------------------------
@@ -155,7 +137,7 @@ typedef struct EXCEPTION_REGISTRATION {
*/
static ThreadSpecificData *
-FileInit()
+FileInit(void)
{
ThreadSpecificData *tsdPtr =
(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
@@ -187,8 +169,8 @@ FileInit()
*/
static void
-FileChannelExitHandler(clientData)
- ClientData clientData; /* Old window proc */
+FileChannelExitHandler(
+ ClientData clientData) /* Old window proc */
{
Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL);
}
@@ -211,9 +193,9 @@ FileChannelExitHandler(clientData)
*/
void
-FileSetupProc(data, flags)
- ClientData data; /* Not used. */
- int flags; /* Event flags as passed to Tcl_DoOneEvent. */
+FileSetupProc(
+ ClientData data, /* Not used. */
+ int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
FileInfo *infoPtr;
Tcl_Time blockTime = { 0, 0 };
@@ -254,9 +236,9 @@ FileSetupProc(data, flags)
*/
static void
-FileCheckProc(data, flags)
- ClientData data; /* Not used. */
- int flags; /* Event flags as passed to Tcl_DoOneEvent. */
+FileCheckProc(
+ ClientData data, /* Not used. */
+ int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
FileEvent *evPtr;
FileInfo *infoPtr;
@@ -275,7 +257,7 @@ FileCheckProc(data, flags)
infoPtr = infoPtr->nextPtr) {
if (infoPtr->watchMask && !(infoPtr->flags & FILE_PENDING)) {
infoPtr->flags |= FILE_PENDING;
- evPtr = (FileEvent *) ckalloc(sizeof(FileEvent));
+ evPtr = ckalloc(sizeof(FileEvent));
evPtr->header.proc = FileEventProc;
evPtr->infoPtr = infoPtr;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
@@ -305,9 +287,9 @@ FileCheckProc(data, flags)
*/
static int
-FileEventProc(evPtr, flags)
- Tcl_Event *evPtr; /* Event to service. */
- int flags; /* Flags that indicate what events to handle,
+FileEventProc(
+ Tcl_Event *evPtr, /* Event to service. */
+ int flags) /* Flags that indicate what events to handle,
* such as TCL_FILE_EVENTS. */
{
FileEvent *fileEvPtr = (FileEvent *)evPtr;
@@ -353,12 +335,12 @@ FileEventProc(evPtr, flags)
*/
static int
-FileBlockProc(instanceData, mode)
- ClientData instanceData; /* Instance data for channel. */
- int mode; /* TCL_MODE_BLOCKING or
+FileBlockProc(
+ ClientData instanceData, /* Instance data for channel. */
+ int mode) /* TCL_MODE_BLOCKING or
* TCL_MODE_NONBLOCKING. */
{
- FileInfo *infoPtr = (FileInfo *) instanceData;
+ FileInfo *infoPtr = instanceData;
/*
* Files on Windows can not be switched between blocking and nonblocking,
@@ -392,11 +374,11 @@ FileBlockProc(instanceData, mode)
*/
static int
-FileCloseProc(instanceData, interp)
- ClientData instanceData; /* Pointer to FileInfo structure. */
- Tcl_Interp *interp; /* Not used. */
+FileCloseProc(
+ ClientData instanceData, /* Pointer to FileInfo structure. */
+ Tcl_Interp *interp) /* Not used. */
{
- FileInfo *fileInfoPtr = (FileInfo *) instanceData;
+ FileInfo *fileInfoPtr = instanceData;
FileInfo *infoPtr;
ThreadSpecificData *tsdPtr;
int errorCode = 0;
@@ -442,7 +424,7 @@ FileCloseProc(instanceData, interp)
break;
}
}
- ckfree((char *)fileInfoPtr);
+ ckfree(fileInfoPtr);
return errorCode;
}
@@ -465,13 +447,13 @@ FileCloseProc(instanceData, interp)
*/
static int
-FileSeekProc(instanceData, offset, mode, errorCodePtr)
- ClientData instanceData; /* File state. */
- long offset; /* Offset to seek to. */
- int mode; /* Relative to where should we seek? */
- int *errorCodePtr; /* To store error code. */
+FileSeekProc(
+ ClientData instanceData, /* File state. */
+ long offset, /* Offset to seek to. */
+ int mode, /* Relative to where should we seek? */
+ int *errorCodePtr) /* To store error code. */
{
- FileInfo *infoPtr = (FileInfo *) instanceData;
+ FileInfo *infoPtr = instanceData;
LONG newPos, newPosHigh, oldPos, oldPosHigh;
DWORD moveMethod;
@@ -490,7 +472,7 @@ FileSeekProc(instanceData, offset, mode, errorCodePtr)
oldPosHigh = 0;
oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh, FILE_CURRENT);
- if (oldPos == INVALID_SET_FILE_POINTER) {
+ if (oldPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
if (winError != NO_ERROR) {
@@ -502,7 +484,7 @@ FileSeekProc(instanceData, offset, mode, errorCodePtr)
newPosHigh = (offset < 0 ? -1 : 0);
newPos = SetFilePointer(infoPtr->handle, offset, &newPosHigh, moveMethod);
- if (newPos == INVALID_SET_FILE_POINTER) {
+ if (newPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
if (winError != NO_ERROR) {
@@ -543,13 +525,13 @@ FileSeekProc(instanceData, offset, mode, errorCodePtr)
*/
static Tcl_WideInt
-FileWideSeekProc(instanceData, offset, mode, errorCodePtr)
- ClientData instanceData; /* File state. */
- Tcl_WideInt offset; /* Offset to seek to. */
- int mode; /* Relative to where should we seek? */
- int *errorCodePtr; /* To store error code. */
+FileWideSeekProc(
+ ClientData instanceData, /* File state. */
+ Tcl_WideInt offset, /* Offset to seek to. */
+ int mode, /* Relative to where should we seek? */
+ int *errorCodePtr) /* To store error code. */
{
- FileInfo *infoPtr = (FileInfo *) instanceData;
+ FileInfo *infoPtr = instanceData;
DWORD moveMethod;
LONG newPos, newPosHigh;
@@ -565,7 +547,7 @@ FileWideSeekProc(instanceData, offset, mode, errorCodePtr)
newPosHigh = Tcl_WideAsLong(offset >> 32);
newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(offset),
&newPosHigh, moveMethod);
- if (newPos == INVALID_SET_FILE_POINTER) {
+ if (newPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
if (winError != NO_ERROR) {
@@ -574,7 +556,7 @@ FileWideSeekProc(instanceData, offset, mode, errorCodePtr)
return -1;
}
}
- return (Tcl_LongAsWide(newPos) | (Tcl_LongAsWide(newPosHigh) << 32));
+ return (((Tcl_WideInt)((unsigned)newPos)) | (Tcl_LongAsWide(newPosHigh) << 32));
}
/*
@@ -594,11 +576,11 @@ FileWideSeekProc(instanceData, offset, mode, errorCodePtr)
*/
static int
-FileTruncateProc(instanceData, length)
- ClientData instanceData; /* File state. */
- Tcl_WideInt length; /* Length to truncate at. */
+FileTruncateProc(
+ ClientData instanceData, /* File state. */
+ Tcl_WideInt length) /* Length to truncate at. */
{
- FileInfo *infoPtr = (FileInfo *) instanceData;
+ FileInfo *infoPtr = instanceData;
LONG newPos, newPosHigh, oldPos, oldPosHigh;
/*
@@ -607,7 +589,7 @@ FileTruncateProc(instanceData, length)
oldPosHigh = 0;
oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh, FILE_CURRENT);
- if (oldPos == INVALID_SET_FILE_POINTER) {
+ if (oldPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
if (winError != NO_ERROR) {
TclWinConvertError(winError);
@@ -622,7 +604,7 @@ FileTruncateProc(instanceData, length)
newPosHigh = Tcl_WideAsLong(length >> 32);
newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(length),
&newPosHigh, FILE_BEGIN);
- if (newPos == INVALID_SET_FILE_POINTER) {
+ if (newPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
if (winError != NO_ERROR) {
TclWinConvertError(winError);
@@ -668,19 +650,22 @@ FileTruncateProc(instanceData, length)
*/
static int
-FileInputProc(instanceData, buf, bufSize, errorCode)
- ClientData instanceData; /* File state. */
- char *buf; /* Where to store data read. */
- int bufSize; /* Num bytes available in buffer. */
- int *errorCode; /* Where to store error code. */
+FileInputProc(
+ ClientData instanceData, /* File state. */
+ char *buf, /* Where to store data read. */
+ int bufSize, /* Num bytes available in buffer. */
+ int *errorCode) /* Where to store error code. */
{
- FileInfo *infoPtr;
+ FileInfo *infoPtr = instanceData;
DWORD bytesRead;
*errorCode = 0;
- infoPtr = (FileInfo *) instanceData;
/*
+ * 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
@@ -720,13 +705,13 @@ FileInputProc(instanceData, buf, bufSize, errorCode)
*/
static int
-FileOutputProc(instanceData, buf, toWrite, errorCode)
- ClientData instanceData; /* File state. */
- CONST char *buf; /* The data buffer. */
- int toWrite; /* How many bytes to write? */
- int *errorCode; /* Where to store error code. */
+FileOutputProc(
+ ClientData instanceData, /* File state. */
+ const char *buf, /* The data buffer. */
+ int toWrite, /* How many bytes to write? */
+ int *errorCode) /* Where to store error code. */
{
- FileInfo *infoPtr = (FileInfo *) instanceData;
+ FileInfo *infoPtr = instanceData;
DWORD bytesWritten;
*errorCode = 0;
@@ -767,13 +752,13 @@ FileOutputProc(instanceData, buf, toWrite, errorCode)
*/
static void
-FileWatchProc(instanceData, mask)
- ClientData instanceData; /* File state. */
- int mask; /* What events to watch for; OR-ed combination
+FileWatchProc(
+ ClientData instanceData, /* File state. */
+ int mask) /* What events to watch for; OR-ed combination
* of TCL_READABLE, TCL_WRITABLE and
* TCL_EXCEPTION. */
{
- FileInfo *infoPtr = (FileInfo *) instanceData;
+ FileInfo *infoPtr = instanceData;
Tcl_Time blockTime = { 0, 0 };
/*
@@ -806,12 +791,12 @@ FileWatchProc(instanceData, mask)
*/
static int
-FileGetHandleProc(instanceData, direction, handlePtr)
- ClientData instanceData; /* The file state. */
- int direction; /* TCL_READABLE or TCL_WRITABLE */
- ClientData *handlePtr; /* Where to store the handle. */
+FileGetHandleProc(
+ ClientData instanceData, /* The file state. */
+ int direction, /* TCL_READABLE or TCL_WRITABLE */
+ ClientData *handlePtr) /* Where to store the handle. */
{
- FileInfo *infoPtr = (FileInfo *) instanceData;
+ FileInfo *infoPtr = instanceData;
if (direction & infoPtr->validMask) {
*handlePtr = (ClientData) infoPtr->handle;
@@ -840,23 +825,23 @@ FileGetHandleProc(instanceData, direction, handlePtr)
*/
Tcl_Channel
-TclpOpenFileChannel(interp, pathPtr, mode, permissions)
- Tcl_Interp *interp; /* Interpreter for error reporting; can be
+TclpOpenFileChannel(
+ Tcl_Interp *interp, /* Interpreter for error reporting; can be
* NULL. */
- Tcl_Obj *pathPtr; /* Name of file to open. */
- int mode; /* POSIX mode. */
- int permissions; /* If the open involves creating a file, with
+ Tcl_Obj *pathPtr, /* Name of file to open. */
+ int mode, /* POSIX mode. */
+ int permissions) /* If the open involves creating a file, with
* what modes to create it? */
{
Tcl_Channel channel = 0;
- int channelPermissions;
- DWORD accessMode, createMode, shareMode, flags, consoleParams, type;
- CONST TCHAR *nativeName;
+ int channelPermissions = 0;
+ DWORD accessMode = 0, createMode, shareMode, flags;
+ const TCHAR *nativeName;
HANDLE handle;
char channelName[16 + TCL_INTEGER_SPACE];
TclFile readFile = NULL, writeFile = NULL;
- nativeName = (TCHAR*) Tcl_FSGetNativePath(pathPtr);
+ nativeName = Tcl_FSGetNativePath(pathPtr);
if (nativeName == NULL) {
return NULL;
}
@@ -904,6 +889,33 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)
}
/*
+ * [2413550] Avoid double-open of serial ports on Windows
+ * Special handling for Windows serial ports by a "name-hint"
+ * to directly open it with the OVERLAPPED flag set.
+ */
+
+ if( NativeIsComPort(nativeName) ) {
+
+ handle = TclWinSerialOpen(INVALID_HANDLE_VALUE, nativeName, accessMode);
+ if (handle == INVALID_HANDLE_VALUE) {
+ TclWinConvertError(GetLastError());
+ if (interp != (Tcl_Interp *) NULL) {
+ Tcl_AppendResult(interp, "couldn't open serial \"",
+ TclGetString(pathPtr), "\": ",
+ Tcl_PosixError(interp), NULL);
+ }
+ return NULL;
+ }
+
+ /*
+ * For natively named Windows serial ports we are done.
+ */
+ channel = TclWinOpenSerialChannel(handle, channelName,
+ channelPermissions);
+
+ return channel;
+ }
+ /*
* If the file is being created, get the file attributes from the
* permissions argument, else use the existing file attributes.
*/
@@ -915,7 +927,7 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)
flags = FILE_ATTRIBUTE_READONLY;
}
} else {
- flags = (*tclWinProcs->getFileAttributesProc)(nativeName);
+ flags = GetFileAttributes(nativeName);
if (flags == 0xFFFFFFFF) {
flags = 0;
}
@@ -931,8 +943,8 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)
* Now we get to create the file.
*/
- handle = (*tclWinProcs->createFileProc)(nativeName, accessMode,
- shareMode, NULL, createMode, flags, (HANDLE) NULL);
+ handle = CreateFile(nativeName, accessMode, shareMode,
+ NULL, createMode, flags, (HANDLE) NULL);
if (handle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
@@ -942,49 +954,33 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)
}
TclWinConvertError(err);
if (interp != (Tcl_Interp *) NULL) {
- Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr),
- "\": ", Tcl_PosixError(interp), (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "couldn't open \"%s\": %s",
+ TclGetString(pathPtr), Tcl_PosixError(interp)));
}
return NULL;
}
- type = GetFileType(handle);
-
- /*
- * If the file is a character device, we need to try to figure out whether
- * it is a serial port, a console, or something else. We test for the
- * console case first because this is more common.
- */
-
- if (type == FILE_TYPE_CHAR) {
- if (GetConsoleMode(handle, &consoleParams)) {
- type = FILE_TYPE_CONSOLE;
- } else {
- DCB dcb;
-
- dcb.DCBlength = sizeof(DCB);
- if (GetCommState(handle, &dcb)) {
- type = FILE_TYPE_SERIAL;
- }
- }
- }
-
channel = NULL;
- switch (type) {
+ switch (FileGetType(handle)) {
case FILE_TYPE_SERIAL:
/*
+ * Natively named serial ports "com1-9", "\\\\.\\comXX" are
+ * already done with the code above.
+ * Here we handle all other serial port names.
+ *
* Reopen channel for OVERLAPPED operation. Normally this shouldn't
* fail, because the channel exists.
*/
- handle = TclWinSerialReopen(handle, nativeName, accessMode);
+ handle = TclWinSerialOpen(handle, nativeName, accessMode);
if (handle == INVALID_HANDLE_VALUE) {
TclWinConvertError(GetLastError());
if (interp != (Tcl_Interp *) NULL) {
- Tcl_AppendResult(interp, "couldn't reopen serial \"",
- TclGetString(pathPtr), "\": ",
- Tcl_PosixError(interp), (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "couldn't reopen serial \"%s\": %s",
+ TclGetString(pathPtr), Tcl_PosixError(interp)));
}
return NULL;
}
@@ -1018,8 +1014,11 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)
*/
channel = NULL;
- Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr),
- "\": bad file type", (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "couldn't open \"%s\": bad file type",
+ TclGetString(pathPtr)));
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "BAD_TYPE",
+ NULL);
break;
}
@@ -1043,19 +1042,18 @@ TclpOpenFileChannel(interp, pathPtr, mode, permissions)
*/
Tcl_Channel
-Tcl_MakeFileChannel(rawHandle, mode)
- ClientData rawHandle; /* OS level handle */
- int mode; /* ORed combination of TCL_READABLE and
+Tcl_MakeFileChannel(
+ ClientData rawHandle, /* OS level handle */
+ int mode) /* ORed combination of TCL_READABLE and
* TCL_WRITABLE to indicate file mode. */
{
-#ifdef HAVE_NO_SEH
- EXCEPTION_REGISTRATION registration;
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
+ TCLEXCEPTION_REGISTRATION registration;
#endif
char channelName[16 + TCL_INTEGER_SPACE];
Tcl_Channel channel = NULL;
HANDLE handle = (HANDLE) rawHandle;
HANDLE dupedHandle;
- DWORD consoleParams, type;
TclFile readFile = NULL, writeFile = NULL;
BOOL result;
@@ -1063,32 +1061,7 @@ Tcl_MakeFileChannel(rawHandle, mode)
return NULL;
}
- /*
- * GetFileType() returns FILE_TYPE_UNKNOWN for invalid handles.
- */
-
- type = GetFileType(handle);
-
- /*
- * If the file is a character device, we need to try to figure out whether
- * it is a serial port, a console, or something else. We test for the
- * console case first because this is more common.
- */
-
- if (type == FILE_TYPE_CHAR) {
- if (GetConsoleMode(handle, &consoleParams)) {
- type = FILE_TYPE_CONSOLE;
- } else {
- DCB dcb;
-
- dcb.DCBlength = sizeof(DCB);
- if (GetCommState(handle, &dcb)) {
- type = FILE_TYPE_SERIAL;
- }
- }
- }
-
- switch (type) {
+ switch (FileGetType(handle)) {
case FILE_TYPE_SERIAL:
channel = TclWinOpenSerialChannel(handle, channelName, mode);
break;
@@ -1140,12 +1113,7 @@ Tcl_MakeFileChannel(rawHandle, mode)
*/
result = 0;
-#ifndef HAVE_NO_SEH
- __try {
- CloseHandle(dupedHandle);
- result = 1;
- } __except (EXCEPTION_EXECUTE_HANDLER) {}
-#else
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
/*
* Don't have SEH available, do things the hard way. Note that this
* needs to be one block of asm, to avoid stack imbalance; also, it is
@@ -1161,7 +1129,7 @@ Tcl_MakeFileChannel(rawHandle, mode)
"movl %[dupedHandle], %%ebx" "\n\t"
/*
- * Construct an EXCEPTION_REGISTRATION to protect the call to
+ * Construct an TCLEXCEPTION_REGISTRATION to protect the call to
* CloseHandle.
*/
@@ -1175,7 +1143,7 @@ Tcl_MakeFileChannel(rawHandle, mode)
"movl $0, 0x10(%%edx)" "\n\t" /* status */
/*
- * Link the EXCEPTION_REGISTRATION on the chain.
+ * Link the TCLEXCEPTION_REGISTRATION on the chain.
*/
"movl %%edx, %%fs:0" "\n\t"
@@ -1188,7 +1156,7 @@ Tcl_MakeFileChannel(rawHandle, mode)
"call _CloseHandle@4" "\n\t"
/*
- * Come here on normal exit. Recover the EXCEPTION_REGISTRATION
+ * Come here on normal exit. Recover the TCLEXCEPTION_REGISTRATION
* and put a TRUE status return into it.
*/
@@ -1198,7 +1166,7 @@ Tcl_MakeFileChannel(rawHandle, mode)
"jmp 2f" "\n"
/*
- * Come here on an exception. Recover the EXCEPTION_REGISTRATION
+ * Come here on an exception. Recover the TCLEXCEPTION_REGISTRATION
*/
"1:" "\t"
@@ -1207,7 +1175,7 @@ Tcl_MakeFileChannel(rawHandle, mode)
/*
* Come here however we exited. Restore context from the
- * EXCEPTION_REGISTRATION in case the stack is unbalanced.
+ * TCLEXCEPTION_REGISTRATION in case the stack is unbalanced.
*/
"2:" "\t"
@@ -1225,7 +1193,15 @@ Tcl_MakeFileChannel(rawHandle, mode)
"%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
);
result = registration.status;
-
+#else
+#ifndef HAVE_NO_SEH
+ __try {
+#endif
+ CloseHandle(dupedHandle);
+ result = 1;
+#ifndef HAVE_NO_SEH
+ } __except (EXCEPTION_EXECUTE_HANDLER) {}
+#endif
#endif
if (result == FALSE) {
return NULL;
@@ -1261,15 +1237,16 @@ Tcl_MakeFileChannel(rawHandle, mode)
*/
Tcl_Channel
-TclpGetDefaultStdChannel(type)
- int type; /* One of TCL_STDIN, TCL_STDOUT, or
+TclpGetDefaultStdChannel(
+ int type) /* One of TCL_STDIN, TCL_STDOUT, or
* TCL_STDERR. */
{
Tcl_Channel channel;
HANDLE handle;
- int mode;
- char *bufMode;
- DWORD handleId; /* Standard handle to retrieve. */
+ int mode = -1;
+ const char *bufMode = NULL;
+ DWORD handleId = (DWORD) -1;
+ /* Standard handle to retrieve. */
switch (type) {
case TCL_STDIN:
@@ -1317,7 +1294,7 @@ TclpGetDefaultStdChannel(type)
if (Tcl_SetChannelOption(NULL,channel,"-translation","auto")!=TCL_OK ||
Tcl_SetChannelOption(NULL,channel,"-eofchar","\032 {}")!=TCL_OK ||
Tcl_SetChannelOption(NULL,channel,"-buffering",bufMode)!=TCL_OK) {
- Tcl_Close((Tcl_Interp *) NULL, channel);
+ Tcl_Close(NULL, channel);
return (Tcl_Channel) NULL;
}
return channel;
@@ -1343,13 +1320,13 @@ TclpGetDefaultStdChannel(type)
*/
Tcl_Channel
-TclWinOpenFileChannel(handle, channelName, permissions, appendMode)
- HANDLE handle; /* Win32 HANDLE to swallow */
- char *channelName; /* Buffer to receive channel name */
- int permissions; /* OR'ed combination of TCL_READABLE,
+TclWinOpenFileChannel(
+ HANDLE handle, /* Win32 HANDLE to swallow */
+ char *channelName, /* Buffer to receive channel name */
+ int permissions, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, or TCL_EXCEPTION, indicating
* which operations are valid on the file. */
- int appendMode; /* OR'ed combination of bits indicating what
+ int appendMode) /* OR'ed combination of bits indicating what
* additional configuration of the channel is
* present. */
{
@@ -1367,7 +1344,7 @@ TclWinOpenFileChannel(handle, channelName, permissions, appendMode)
}
}
- infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo));
+ infoPtr = ckalloc(sizeof(FileInfo));
/*
* TIP #218. Removed the code inserting the new structure into the global
@@ -1381,10 +1358,10 @@ TclWinOpenFileChannel(handle, channelName, permissions, appendMode)
infoPtr->flags = appendMode;
infoPtr->handle = handle;
infoPtr->dirty = 0;
- wsprintfA(channelName, "file%lx", (int) infoPtr);
+ sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t) infoPtr);
infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName,
- (ClientData) infoPtr, permissions);
+ infoPtr, permissions);
/*
* Files have default translation of AUTO and ^Z eof char, which means
@@ -1417,7 +1394,7 @@ TclWinOpenFileChannel(handle, channelName, permissions, appendMode)
*/
void
-TclWinFlushDirtyChannels()
+TclWinFlushDirtyChannels(void)
{
FileInfo *infoPtr;
ThreadSpecificData *tsdPtr = FileInit();
@@ -1453,12 +1430,12 @@ TclWinFlushDirtyChannels()
*/
static void
-FileThreadActionProc(instanceData, action)
- ClientData instanceData;
- int action;
+FileThreadActionProc(
+ ClientData instanceData,
+ int action)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- FileInfo *infoPtr = (FileInfo *) instanceData;
+ FileInfo *infoPtr = instanceData;
if (action == TCL_CHANNEL_THREAD_INSERT) {
infoPtr->nextPtr = tsdPtr->firstFilePtr;
@@ -1489,6 +1466,123 @@ FileThreadActionProc(instanceData, action)
}
/*
+ *----------------------------------------------------------------------
+ *
+ * FileGetType --
+ *
+ * Given a file handle, return its type
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+DWORD
+FileGetType(
+ HANDLE handle) /* Opened file handle */
+{
+ DWORD type;
+
+ type = GetFileType(handle);
+
+ /*
+ * If the file is a character device, we need to try to figure out whether
+ * it is a serial port, a console, or something else. We test for the
+ * console case first because this is more common.
+ */
+
+ if ((type == FILE_TYPE_CHAR)
+ || ((type == FILE_TYPE_UNKNOWN) && !GetLastError())) {
+ DWORD consoleParams;
+
+ if (GetConsoleMode(handle, &consoleParams)) {
+ type = FILE_TYPE_CONSOLE;
+ } else {
+ DCB dcb;
+
+ dcb.DCBlength = sizeof(DCB);
+ if (GetCommState(handle, &dcb)) {
+ type = FILE_TYPE_SERIAL;
+ }
+ }
+ }
+
+ return type;
+}
+
+ /*
+ *----------------------------------------------------------------------
+ *
+ * NativeIsComPort --
+ *
+ * Determines if a path refers to a Windows serial port.
+ * A simple and efficient solution is to use a "name hint" to detect
+ * COM ports by their filename instead of resorting to a syscall
+ * to detect serialness after the fact.
+ * The following patterns cover common serial port names:
+ * COM[1-9]:?
+ * //./COM[0-9]+
+ * \\.\COM[0-9]+
+ *
+ * Results:
+ * 1 = serial port, 0 = not.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+NativeIsComPort(
+ const TCHAR *nativePath) /* Path of file to access, native encoding. */
+{
+ const WCHAR *p = (const WCHAR *) nativePath;
+ int i, len = wcslen(p);
+
+ /*
+ * 1. Look for com[1-9]:?
+ */
+
+ if ( (len >= 4) && (len <= 5)
+ && (_wcsnicmp(p, L"com", 3) == 0) ) {
+ /*
+ * The 4th character must be a digit 1..9 optionally followed by a ":"
+ */
+
+ if ( (p[3] < L'1') || (p[3] > L'9') ) {
+ return 0;
+ }
+ if ( (len == 5) && (p[4] != L':') ) {
+ return 0;
+ }
+ return 1;
+ }
+
+ /*
+ * 2. Look for //./com[0-9]+ or \\.\com[0-9]+
+ */
+
+ if ( (len >= 8) && (
+ (_wcsnicmp(p, L"//./com", 7) == 0)
+ || (_wcsnicmp(p, L"\\\\.\\com", 7) == 0) ) )
+ {
+ /*
+ * Charaters 8..end must be a digits 0..9
+ */
+
+ for ( i=7; i<len; i++ ) {
+ if ( (p[i] < '0') || (p[i] > '9') ) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4