summaryrefslogtreecommitdiffstats
path: root/win/tclWinSerial.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinSerial.c')
-rw-r--r--win/tclWinSerial.c501
1 files changed, 276 insertions, 225 deletions
diff --git a/win/tclWinSerial.c b/win/tclWinSerial.c
index ba71aad..6487fe4 100644
--- a/win/tclWinSerial.c
+++ b/win/tclWinSerial.c
@@ -10,16 +10,10 @@
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* Serial functionality implemented by Rolf.Schroedter@dlr.de
- *
- * RCS: @(#) $Id: tclWinSerial.c,v 1.31 2005/07/24 22:56:49 dkf Exp $
*/
#include "tclWinInt.h"
-#include <fcntl.h>
-#include <io.h>
-#include <sys/stat.h>
-
/*
* The following variable is used to tell whether this module has been
* initialized.
@@ -167,46 +161,45 @@ static COMMTIMEOUTS no_timeout = {
* Declarations for functions used only in this file.
*/
-static int SerialBlockProc(ClientData instanceData,
- int mode);
-static void SerialCheckProc(ClientData clientData,
- int flags);
-static int SerialCloseProc(ClientData instanceData,
- Tcl_Interp *interp);
-static int SerialEventProc(Tcl_Event *evPtr, int flags);
-static void SerialExitHandler(ClientData clientData);
-static int SerialGetHandleProc(ClientData instanceData,
- int direction, ClientData *handlePtr);
-static ThreadSpecificData * SerialInit(void);
-static int SerialInputProc(ClientData instanceData,
- char *buf, int toRead, int *errorCode);
-static int SerialOutputProc(ClientData instanceData,
- CONST char *buf, int toWrite,
- int *errorCode);
-static void SerialSetupProc(ClientData clientData,
- int flags);
-static void SerialWatchProc(ClientData instanceData,
- int mask);
-static void ProcExitHandler(ClientData clientData);
-static int SerialGetOptionProc(ClientData instanceData,
- Tcl_Interp *interp, CONST char *optionName,
- Tcl_DString *dsPtr);
-static int SerialSetOptionProc(ClientData instanceData,
- Tcl_Interp *interp, CONST char *optionName,
- CONST char *value);
-static DWORD WINAPI SerialWriterThread(LPVOID arg);
-
-static void SerialThreadActionProc(ClientData instanceData,
- int action);
+static int SerialBlockProc(ClientData instanceData, int mode);
+static void SerialCheckProc(ClientData clientData, int flags);
+static int SerialCloseProc(ClientData instanceData,
+ Tcl_Interp *interp);
+static int SerialEventProc(Tcl_Event *evPtr, int flags);
+static void SerialExitHandler(ClientData clientData);
+static int SerialGetHandleProc(ClientData instanceData,
+ int direction, ClientData *handlePtr);
+static ThreadSpecificData *SerialInit(void);
+static int SerialInputProc(ClientData instanceData, char *buf,
+ int toRead, int *errorCode);
+static int SerialOutputProc(ClientData instanceData,
+ const char *buf, int toWrite, int *errorCode);
+static void SerialSetupProc(ClientData clientData, int flags);
+static void SerialWatchProc(ClientData instanceData, int mask);
+static void ProcExitHandler(ClientData clientData);
+static int SerialGetOptionProc(ClientData instanceData,
+ Tcl_Interp *interp, const char *optionName,
+ Tcl_DString *dsPtr);
+static int SerialSetOptionProc(ClientData instanceData,
+ Tcl_Interp *interp, const char *optionName,
+ const char *value);
+static DWORD WINAPI SerialWriterThread(LPVOID arg);
+static void SerialThreadActionProc(ClientData instanceData,
+ int action);
+static int SerialBlockingRead(SerialInfo *infoPtr, LPVOID buf,
+ DWORD bufSize, LPDWORD lpRead, LPOVERLAPPED osPtr);
+static int SerialBlockingWrite(SerialInfo *infoPtr, LPVOID buf,
+ DWORD bufSize, LPDWORD lpWritten,
+ LPOVERLAPPED osPtr);
/*
* This structure describes the channel type structure for command serial
* based IO.
*/
-static Tcl_ChannelType serialChannelType = {
+static const Tcl_ChannelType serialChannelType = {
"serial", /* Type name. */
- TCL_CHANNEL_VERSION_4, /* v4 channel */
+ TCL_CHANNEL_VERSION_5, /* v5 channel */
SerialCloseProc, /* Close proc. */
SerialInputProc, /* Input proc. */
SerialOutputProc, /* Output proc. */
@@ -221,6 +214,7 @@ static Tcl_ChannelType serialChannelType = {
NULL, /* handler proc. */
NULL, /* wide seek proc */
SerialThreadActionProc, /* thread action proc */
+ NULL /* truncate */
};
/*
@@ -240,7 +234,7 @@ static Tcl_ChannelType serialChannelType = {
*/
static ThreadSpecificData *
-SerialInit()
+SerialInit(void)
{
ThreadSpecificData *tsdPtr;
@@ -380,7 +374,7 @@ SerialGetMilliseconds(void)
{
Tcl_Time time;
- TclpGetTime(&time);
+ Tcl_GetTime(&time);
return (time.sec * 1000 + time.usec / 1000);
}
@@ -533,7 +527,7 @@ SerialCheckProc(
if (needEvent) {
infoPtr->flags |= SERIAL_PENDING;
- evPtr = (SerialEvent *) ckalloc(sizeof(SerialEvent));
+ evPtr = ckalloc(sizeof(SerialEvent));
evPtr->header.proc = SerialEventProc;
evPtr->infoPtr = infoPtr;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
@@ -662,7 +656,6 @@ SerialCloseProc(
CloseHandle(serialPtr->writeThread);
CloseHandle(serialPtr->osWrite.hEvent);
- DeleteCriticalSection(&serialPtr->csWrite);
CloseHandle(serialPtr->evWritable);
CloseHandle(serialPtr->evStartWriter);
CloseHandle(serialPtr->evStopWriter);
@@ -672,6 +665,8 @@ SerialCloseProc(
}
serialPtr->validMask &= ~TCL_WRITABLE;
+ DeleteCriticalSection(&serialPtr->csWrite);
+
/*
* Don't close the Win32 handle if the handle is a standard channel during
* the thread exit process. Otherwise, one thread may kill the stdio of
@@ -711,7 +706,7 @@ SerialCloseProc(
ckfree(serialPtr->writeBuf);
serialPtr->writeBuf = NULL;
}
- ckfree((char*) serialPtr);
+ ckfree(serialPtr);
if (errorCode == 0) {
return result;
@@ -722,7 +717,7 @@ SerialCloseProc(
/*
*----------------------------------------------------------------------
*
- * blockingRead --
+ * SerialBlockingRead --
*
* Perform a blocking read into the buffer given. Returns count of how
* many bytes were actually read, and an error indication.
@@ -738,12 +733,12 @@ SerialCloseProc(
*/
static int
-blockingRead(
+SerialBlockingRead(
SerialInfo *infoPtr, /* Serial info structure */
LPVOID buf, /* The input buffer pointer */
- DWORD bufSize, /* The number of bytes to read */
- LPDWORD lpRead, /* Returns number of bytes read */
- LPOVERLAPPED osPtr ) /* OVERLAPPED structure */
+ DWORD bufSize, /* The number of bytes to read */
+ LPDWORD lpRead, /* Returns number of bytes read */
+ LPOVERLAPPED osPtr) /* OVERLAPPED structure */
{
/*
* Perform overlapped blocking read.
@@ -785,7 +780,7 @@ blockingRead(
/*
*----------------------------------------------------------------------
*
- * blockingWrite --
+ * SerialBlockingWrite --
*
* Perform a blocking write from the buffer given. Returns count of how
* many bytes were actually written, and an error indication.
@@ -801,10 +796,10 @@ blockingRead(
*/
static int
-blockingWrite(
+SerialBlockingWrite(
SerialInfo *infoPtr, /* Serial info structure */
- LPVOID buf, /* The output buffer pointer */
- DWORD bufSize, /* The number of bytes to write */
+ LPVOID buf, /* The output buffer pointer */
+ DWORD bufSize, /* The number of bytes to write */
LPDWORD lpWritten, /* Returns number of bytes written */
LPOVERLAPPED osPtr) /* OVERLAPPED structure */
{
@@ -937,7 +932,7 @@ SerialInputProc(
bufSize = cStat.cbInQue;
}
} else {
- errno = *errorCode = EAGAIN;
+ errno = *errorCode = EWOULDBLOCK;
return -1;
}
} else {
@@ -964,7 +959,7 @@ SerialInputProc(
* checked the number of available bytes.
*/
- if (blockingRead(infoPtr, (LPVOID) buf, (DWORD) bufSize, &bytesRead,
+ if (SerialBlockingRead(infoPtr, (LPVOID) buf, (DWORD) bufSize, &bytesRead,
&infoPtr->osRead) == FALSE) {
TclWinConvertError(GetLastError());
*errorCode = errno;
@@ -1001,7 +996,7 @@ SerialInputProc(
static int
SerialOutputProc(
ClientData instanceData, /* Serial state. */
- CONST char *buf, /* The data buffer. */
+ const char *buf, /* The data buffer. */
int toWrite, /* How many bytes to write? */
int *errorCode) /* Where to store error code. */
{
@@ -1076,7 +1071,7 @@ SerialOutputProc(
ckfree(infoPtr->writeBuf);
}
infoPtr->writeBufLen = toWrite;
- infoPtr->writeBuf = ckalloc((unsigned int) toWrite);
+ infoPtr->writeBuf = ckalloc(toWrite);
}
memcpy(infoPtr->writeBuf, buf, (size_t) toWrite);
infoPtr->toWrite = toWrite;
@@ -1090,7 +1085,7 @@ SerialOutputProc(
* avoids an unnecessary copy.
*/
- if (!blockingWrite(infoPtr, (LPVOID) buf, (DWORD) toWrite,
+ if (!SerialBlockingWrite(infoPtr, (LPVOID) buf, (DWORD) toWrite,
&bytesWritten, &infoPtr->osWrite)) {
goto writeError;
}
@@ -1147,9 +1142,9 @@ SerialOutputProc(
static int
SerialEventProc(
- Tcl_Event *evPtr, /* Event to service. */
- int flags) /* Flags that indicate what events to handle, such as
- * TCL_FILE_EVENTS. */
+ Tcl_Event *evPtr, /* Event to service. */
+ int flags) /* Flags that indicate what events to handle,
+ * such as TCL_FILE_EVENTS. */
{
SerialEvent *serialEvPtr = (SerialEvent *)evPtr;
SerialInfo *infoPtr;
@@ -1257,8 +1252,7 @@ SerialWatchProc(
* Remove the serial port from the list of watched serial ports.
*/
- for (nextPtrPtr=&(tsdPtr->firstSerialPtr), ptr=*nextPtrPtr;
- ptr!=NULL;
+ for (nextPtrPtr=&(tsdPtr->firstSerialPtr), ptr=*nextPtrPtr; ptr!=NULL;
nextPtrPtr=&ptr->nextPtr, ptr=*nextPtrPtr) {
if (infoPtr == ptr) {
*nextPtrPtr = ptr->nextPtr;
@@ -1316,7 +1310,8 @@ SerialGetHandleProc(
*/
static DWORD WINAPI
-SerialWriterThread(LPVOID arg)
+SerialWriterThread(
+ LPVOID arg)
{
SerialInfo *infoPtr = (SerialInfo *)arg;
DWORD bytesWritten, toWrite, waitResult;
@@ -1365,7 +1360,7 @@ SerialWriterThread(LPVOID arg)
if (infoPtr->writeError) {
break;
}
- if (blockingWrite(infoPtr, (LPVOID) buf, (DWORD) toWrite,
+ if (SerialBlockingWrite(infoPtr, (LPVOID) buf, (DWORD) toWrite,
&bytesWritten, &myWrite) == FALSE) {
infoPtr->writeError = GetLastError();
break;
@@ -1415,30 +1410,35 @@ SerialWriterThread(LPVOID arg)
/*
*----------------------------------------------------------------------
*
- * TclWinSerialReopen --
+ * TclWinSerialOpen --
*
- * Reopens the serial port with the OVERLAPPED FLAG set
+ * Opens or Reopens the serial port with the OVERLAPPED FLAG set
*
* Results:
- * Returns the new handle, or INVALID_HANDLE_VALUE. Normally there
- * shouldn't be any error, because the same channel has previously been
- * succeesfully opened.
+ * Returns the new handle, or INVALID_HANDLE_VALUE.
+ * If an existing channel is specified it is closed and reopened.
*
* Side effects:
- * May close the original handle
+ * May close/reopen the original handle
*
*----------------------------------------------------------------------
*/
HANDLE
-TclWinSerialReopen(handle, name, access)
- HANDLE handle;
- CONST TCHAR *name;
- DWORD access;
+TclWinSerialOpen(
+ HANDLE handle,
+ const TCHAR *name,
+ DWORD access)
{
- ThreadSpecificData *tsdPtr;
+ SerialInit();
- tsdPtr = SerialInit();
+ /*
+ * If an open channel is specified, close it
+ */
+
+ if ( handle != INVALID_HANDLE_VALUE && CloseHandle(handle) == FALSE) {
+ return INVALID_HANDLE_VALUE;
+ }
/*
* Multithreaded I/O needs the overlapped flag set otherwise
@@ -1446,11 +1446,9 @@ TclWinSerialReopen(handle, name, access)
* finished
*/
- if (CloseHandle(handle) == FALSE) {
- return INVALID_HANDLE_VALUE;
- }
- handle = (*tclWinProcs->createFileProc)(name, access, 0, 0,
- OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+ handle = CreateFile(name, access, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, 0);
+
return handle;
}
@@ -1473,17 +1471,17 @@ TclWinSerialReopen(handle, name, access)
*/
Tcl_Channel
-TclWinOpenSerialChannel(handle, channelName, permissions)
- HANDLE handle;
- char *channelName;
- int permissions;
+TclWinOpenSerialChannel(
+ HANDLE handle,
+ char *channelName,
+ int permissions)
{
SerialInfo *infoPtr;
DWORD id;
SerialInit();
- infoPtr = (SerialInfo *) ckalloc((unsigned) sizeof(SerialInfo));
+ infoPtr = ckalloc(sizeof(SerialInfo));
memset(infoPtr, 0, sizeof(SerialInfo));
infoPtr->validMask = permissions;
@@ -1504,10 +1502,10 @@ TclWinOpenSerialChannel(handle, channelName, permissions)
* are shared between multiple channels (stdin/stdout).
*/
- wsprintfA(channelName, "file%lx", (int) infoPtr);
+ sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t) infoPtr);
infoPtr->channel = Tcl_CreateChannel(&serialChannelType, channelName,
- (ClientData) infoPtr, permissions);
+ infoPtr, permissions);
SetupComm(handle, infoPtr->sysBufRead, infoPtr->sysBufWrite);
@@ -1520,6 +1518,7 @@ TclWinOpenSerialChannel(handle, channelName, permissions)
SetCommTimeouts(handle, &no_timeout);
+ InitializeCriticalSection(&infoPtr->csWrite);
if (permissions & TCL_READABLE) {
infoPtr->osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
@@ -1532,7 +1531,6 @@ TclWinOpenSerialChannel(handle, channelName, permissions)
infoPtr->evWritable = CreateEvent(NULL, TRUE, TRUE, NULL);
infoPtr->evStartWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
infoPtr->evStopWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
- InitializeCriticalSection(&infoPtr->csWrite);
infoPtr->writeThread = CreateThread(NULL, 256, SerialWriterThread,
infoPtr, 0, &id);
}
@@ -1565,9 +1563,9 @@ TclWinOpenSerialChannel(handle, channelName, permissions)
*/
static void
-SerialErrorStr(error, dsPtr)
- DWORD error; /* Win32 serial error code. */
- Tcl_DString *dsPtr; /* Where to store string. */
+SerialErrorStr(
+ DWORD error, /* Win32 serial error code. */
+ Tcl_DString *dsPtr) /* Where to store string. */
{
if (error & CE_RXOVER) {
Tcl_DStringAppendElement(dsPtr, "RXOVER");
@@ -1615,9 +1613,9 @@ SerialErrorStr(error, dsPtr)
*/
static void
-SerialModemStatusStr(status, dsPtr)
- DWORD status; /* Win32 modem status. */
- Tcl_DString *dsPtr; /* Where to store string. */
+SerialModemStatusStr(
+ DWORD status, /* Win32 modem status. */
+ Tcl_DString *dsPtr) /* Where to store string. */
{
Tcl_DStringAppendElement(dsPtr, "CTS");
Tcl_DStringAppendElement(dsPtr, (status & MS_CTS_ON) ? "1" : "0");
@@ -1647,20 +1645,20 @@ SerialModemStatusStr(status, dsPtr)
*/
static int
-SerialSetOptionProc(instanceData, interp, optionName, value)
- ClientData instanceData; /* File state. */
- Tcl_Interp *interp; /* For error reporting - can be NULL. */
- CONST char *optionName; /* Which option to set? */
- CONST char *value; /* New value for option. */
+SerialSetOptionProc(
+ ClientData instanceData, /* File state. */
+ Tcl_Interp *interp, /* For error reporting - can be NULL. */
+ const char *optionName, /* Which option to set? */
+ const char *value) /* New value for option. */
{
SerialInfo *infoPtr;
DCB dcb;
BOOL result, flag;
size_t len, vlen;
Tcl_DString ds;
- CONST TCHAR *native;
+ const TCHAR *native;
int argc;
- CONST char **argv;
+ const char **argv;
infoPtr = (SerialInfo *) instanceData;
@@ -1678,20 +1676,18 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) {
if (!GetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't get comm state", (char *)NULL);
- }
- return TCL_ERROR;
+ goto getStateFailed;
}
native = Tcl_WinUtfToTChar(value, -1, &ds);
- result = (*tclWinProcs->buildCommDCBProc)(native, &dcb);
+ result = BuildCommDCB(native, &dcb);
Tcl_DStringFree(&ds);
if (result == FALSE) {
- if (interp) {
- Tcl_AppendResult(interp,
- "bad value for -mode: should be baud,parity,data,stop",
- (char *) NULL);
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "bad value \"%s\" for -mode: should be baud,parity,data,stop",
+ value));
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);
}
return TCL_ERROR;
}
@@ -1706,10 +1702,7 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
dcb.fAbortOnError = FALSE;
if (!SetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't set comm state", (char *)NULL);
- }
- return TCL_ERROR;
+ goto setStateFailed;
}
return TCL_OK;
}
@@ -1720,10 +1713,7 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) {
if (!GetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't get comm state", (char *)NULL);
- }
- return TCL_ERROR;
+ goto getStateFailed;
}
/*
@@ -1744,32 +1734,30 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
dcb.XonLim = (WORD) (infoPtr->sysBufRead*1/2);
dcb.XoffLim = (WORD) (infoPtr->sysBufRead*1/4);
- if (strnicmp(value, "NONE", vlen) == 0) {
+ if (strncasecmp(value, "NONE", vlen) == 0) {
/*
* Leave all handshake options disabled.
*/
- } else if (strnicmp(value, "XONXOFF", vlen) == 0) {
+ } else if (strncasecmp(value, "XONXOFF", vlen) == 0) {
dcb.fOutX = dcb.fInX = TRUE;
- } else if (strnicmp(value, "RTSCTS", vlen) == 0) {
+ } else if (strncasecmp(value, "RTSCTS", vlen) == 0) {
dcb.fOutxCtsFlow = TRUE;
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
- } else if (strnicmp(value, "DTRDSR", vlen) == 0) {
+ } else if (strncasecmp(value, "DTRDSR", vlen) == 0) {
dcb.fOutxDsrFlow = TRUE;
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
} else {
- if (interp) {
- Tcl_AppendResult(interp, "bad value for -handshake: ",
- "must be one of xonxoff, rtscts, dtrdsr or none",
- (char *) NULL);
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "bad value \"%s\" for -handshake: must be one of"
+ " xonxoff, rtscts, dtrdsr or none", value));
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "HANDSHAKE", NULL);
}
return TCL_ERROR;
}
if (!SetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't set comm state", (char *)NULL);
- }
- return TCL_ERROR;
+ goto setStateFailed;
}
return TCL_OK;
}
@@ -1780,31 +1768,55 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) {
if (!GetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't get comm state", (char *)NULL);
- }
- return TCL_ERROR;
+ goto getStateFailed;
}
if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
return TCL_ERROR;
}
- if (argc == 2) {
- dcb.XonChar = argv[0][0];
- dcb.XoffChar = argv[1][0];
- } else {
- if (interp) {
- Tcl_AppendResult(interp, "bad value for -xchar: ",
- "should be a list of two elements", (char *) NULL);
+ if (argc != 2) {
+ badXchar:
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "bad value for -xchar: should be a list of"
+ " two elements with each a single character", -1));
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "XCHAR", NULL);
}
+ ckfree(argv);
return TCL_ERROR;
}
- if (!SetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't set comm state", (char *)NULL);
+ /*
+ * These dereferences are safe, even in the zero-length string cases,
+ * because that just makes the xon/xoff character into NUL. When the
+ * character looks like it is UTF-8 encoded, decode it before casting
+ * into the format required for the Win guts. Note that this does not
+ * convert character sets; it is expected that when people set the
+ * control characters to something large and custom, they'll know the
+ * hex/octal value rather than the printable form.
+ */
+
+ dcb.XonChar = argv[0][0];
+ dcb.XoffChar = argv[1][0];
+ if (argv[0][0] & 0x80 || argv[1][0] & 0x80) {
+ Tcl_UniChar character;
+ int charLen;
+
+ charLen = Tcl_UtfToUniChar(argv[0], &character);
+ if (argv[0][charLen]) {
+ goto badXchar;
}
- return TCL_ERROR;
+ dcb.XonChar = (char) character;
+ charLen = Tcl_UtfToUniChar(argv[1], &character);
+ if (argv[1][charLen]) {
+ goto badXchar;
+ }
+ dcb.XoffChar = (char) character;
+ }
+ ckfree(argv);
+
+ if (!SetCommState(infoPtr->handle, &dcb)) {
+ goto setStateFailed;
}
return TCL_OK;
}
@@ -1814,60 +1826,78 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
*/
if ((len > 4) && (strncmp(optionName, "-ttycontrol", len) == 0)) {
+ int i, result = TCL_OK;
+
if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
return TCL_ERROR;
}
if ((argc % 2) == 1) {
- if (interp) {
- Tcl_AppendResult(interp, "bad value for -ttycontrol: ",
- "should be a list of signal,value pairs",
- (char *) NULL);
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "bad value \"%s\" for -ttycontrol: should be "
+ "a list of signal,value pairs", value));
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTYCONTROL", NULL);
}
+ ckfree(argv);
return TCL_ERROR;
}
- while (argc > 1) {
- if (Tcl_GetBoolean(interp, argv[1], &flag) == TCL_ERROR) {
- return TCL_ERROR;
+
+ for (i = 0; i < argc - 1; i += 2) {
+ if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) {
+ result = TCL_ERROR;
+ break;
}
- if (strnicmp(argv[0], "DTR", strlen(argv[0])) == 0) {
- if (!EscapeCommFunction(infoPtr->handle, flag ?
- (DWORD) SETDTR : (DWORD) CLRDTR)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't set DTR signal",
- (char *) NULL);
+ if (strncasecmp(argv[i], "DTR", strlen(argv[i])) == 0) {
+ if (!EscapeCommFunction(infoPtr->handle,
+ (DWORD) (flag ? SETDTR : CLRDTR))) {
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "can't set DTR signal", -1));
+ Tcl_SetErrorCode(interp, "TCL", "OPERATION",
+ "FCONFIGURE", "TTY_SIGNAL", NULL);
}
- return TCL_ERROR;
+ result = TCL_ERROR;
+ break;
}
- } else if (strnicmp(argv[0], "RTS", strlen(argv[0])) == 0) {
- if (!EscapeCommFunction(infoPtr->handle, flag ?
- (DWORD) SETRTS : (DWORD) CLRRTS)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't set RTS signal",
- (char *) NULL);
+ } else if (strncasecmp(argv[i], "RTS", strlen(argv[i])) == 0) {
+ if (!EscapeCommFunction(infoPtr->handle,
+ (DWORD) (flag ? SETRTS : CLRRTS))) {
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "can't set RTS signal", -1));
+ Tcl_SetErrorCode(interp, "TCL", "OPERATION",
+ "FCONFIGURE", "TTY_SIGNAL", NULL);
}
- return TCL_ERROR;
+ result = TCL_ERROR;
+ break;
}
- } else if (strnicmp(argv[0], "BREAK", strlen(argv[0])) == 0) {
- if (!EscapeCommFunction(infoPtr->handle, flag ?
- (DWORD) SETBREAK : (DWORD) CLRBREAK)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't set BREAK signal",
- (char *) NULL);
+ } else if (strncasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) {
+ if (!EscapeCommFunction(infoPtr->handle,
+ (DWORD) (flag ? SETBREAK : CLRBREAK))) {
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "can't set BREAK signal", -1));
+ Tcl_SetErrorCode(interp, "TCL", "OPERATION",
+ "FCONFIGURE", "TTY_SIGNAL", NULL);
}
- return TCL_ERROR;
+ result = TCL_ERROR;
+ break;
}
} else {
- if (interp) {
- Tcl_AppendResult(interp, "bad signal for -ttycontrol: ",
- "must be DTR, RTS or BREAK", (char *) NULL);
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "bad signal name \"%s\" for -ttycontrol: must be"
+ " DTR, RTS or BREAK", argv[i]));
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTY_SIGNAL",
+ NULL);
}
- return TCL_ERROR;
+ result = TCL_ERROR;
+ break;
}
- argc -= 2;
- argv += 2;
- } /* while (argc > 1) */
+ }
- return TCL_OK;
+ ckfree(argv);
+ return result;
}
/*
@@ -1892,18 +1922,24 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
inSize = atoi(argv[0]);
outSize = atoi(argv[1]);
}
- if ((inSize <= 0) || (outSize <= 0)) {
- if (interp) {
- Tcl_AppendResult(interp, "bad value for -sysbuffer: ",
- "should be a list of one or two integers > 0",
- (char *) NULL);
+ ckfree(argv);
+
+ if ((argc < 1) || (argc > 2) || (inSize <= 0) || (outSize <= 0)) {
+ if (interp != NULL) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "bad value \"%s\" for -sysbuffer: should be "
+ "a list of one or two integers > 0", value));
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "SYS_BUFFER", NULL);
}
return TCL_ERROR;
}
+
if (!SetupComm(infoPtr->handle, inSize, outSize)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't setup comm buffers",
- (char *) NULL);
+ if (interp != NULL) {
+ TclWinConvertError(GetLastError());
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "can't setup comm buffers: %s",
+ Tcl_PosixError(interp)));
}
return TCL_ERROR;
}
@@ -1916,20 +1952,12 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
*/
if (!GetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't get comm state",
- (char *) NULL);
- }
- return TCL_ERROR;
+ goto getStateFailed;
}
dcb.XonLim = (WORD) (infoPtr->sysBufRead*1/2);
dcb.XoffLim = (WORD) (infoPtr->sysBufRead*1/4);
if (!SetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't set comm state",
- (char *) NULL);
- }
- return TCL_ERROR;
+ goto setStateFailed;
}
return TCL_OK;
}
@@ -1939,7 +1967,7 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
*/
if ((len > 1) && (strncmp(optionName, "-pollinterval", len) == 0)) {
- if (Tcl_GetInt(interp, value, &(infoPtr->blockTime)) != TCL_OK ) {
+ if (Tcl_GetInt(interp, value, &(infoPtr->blockTime)) != TCL_OK) {
return TCL_ERROR;
}
return TCL_OK;
@@ -1958,9 +1986,11 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
}
tout.ReadTotalTimeoutConstant = msec;
if (!SetCommTimeouts(infoPtr->handle, &tout)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't set comm timeouts",
- (char *) NULL);
+ if (interp != NULL) {
+ TclWinConvertError(GetLastError());
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "can't set comm timeouts: %s",
+ Tcl_PosixError(interp)));
}
return TCL_ERROR;
}
@@ -1970,6 +2000,22 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
return Tcl_BadChannelOption(interp, optionName,
"mode handshake pollinterval sysbuffer timeout ttycontrol xchar");
+
+ getStateFailed:
+ if (interp != NULL) {
+ TclWinConvertError(GetLastError());
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "can't get comm state: %s", Tcl_PosixError(interp)));
+ }
+ return TCL_ERROR;
+
+ setStateFailed:
+ if (interp != NULL) {
+ TclWinConvertError(GetLastError());
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "can't set comm state: %s", Tcl_PosixError(interp)));
+ }
+ return TCL_ERROR;
}
/*
@@ -1994,11 +2040,11 @@ SerialSetOptionProc(instanceData, interp, optionName, value)
*/
static int
-SerialGetOptionProc(instanceData, interp, optionName, dsPtr)
- ClientData instanceData; /* File state. */
- Tcl_Interp *interp; /* For error reporting - can be NULL. */
- CONST char *optionName; /* Option to get. */
- Tcl_DString *dsPtr; /* Where to store value(s). */
+SerialGetOptionProc(
+ ClientData instanceData, /* File state. */
+ Tcl_Interp *interp, /* For error reporting - can be NULL. */
+ const char *optionName, /* Option to get. */
+ Tcl_DString *dsPtr) /* Where to store value(s). */
{
SerialInfo *infoPtr;
DCB dcb;
@@ -2022,12 +2068,14 @@ SerialGetOptionProc(instanceData, interp, optionName, dsPtr)
}
if (len==0 || (len>2 && (strncmp(optionName, "-mode", len) == 0))) {
char parity;
- char *stop;
+ const char *stop;
char buf[2 * TCL_INTEGER_SPACE + 16];
if (!GetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't get comm state", (char *)NULL);
+ if (interp != NULL) {
+ TclWinConvertError(GetLastError());
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "can't get comm state: %s", Tcl_PosixError(interp)));
}
return TCL_ERROR;
}
@@ -2094,8 +2142,10 @@ SerialGetOptionProc(instanceData, interp, optionName, dsPtr)
valid = 1;
if (!GetCommState(infoPtr->handle, &dcb)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't get comm state", (char *)NULL);
+ if (interp != NULL) {
+ TclWinConvertError(GetLastError());
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "can't get comm state: %s", Tcl_PosixError(interp)));
}
return TCL_ERROR;
}
@@ -2149,8 +2199,8 @@ SerialGetOptionProc(instanceData, interp, optionName, dsPtr)
*/
EnterCriticalSection(&infoPtr->csWrite);
- ClearCommError( infoPtr->handle, &error, &cStat );
- count = (int)cStat.cbOutQue + infoPtr->writeQueue;
+ ClearCommError(infoPtr->handle, &error, &cStat);
+ count = (int) cStat.cbOutQue + infoPtr->writeQueue;
LeaveCriticalSection(&infoPtr->csWrite);
wsprintfA(buf, "%d", inBuffered + cStat.cbInQue);
@@ -2170,8 +2220,10 @@ SerialGetOptionProc(instanceData, interp, optionName, dsPtr)
DWORD status;
if (!GetCommModemStatus(infoPtr->handle, &status)) {
- if (interp) {
- Tcl_AppendResult(interp, "can't get tty status", (char *)NULL);
+ if (interp != NULL) {
+ TclWinConvertError(GetLastError());
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "can't get tty status: %s", Tcl_PosixError(interp)));
}
return TCL_ERROR;
}
@@ -2181,10 +2233,9 @@ SerialGetOptionProc(instanceData, interp, optionName, dsPtr)
if (valid) {
return TCL_OK;
- } else {
- return Tcl_BadChannelOption(interp, optionName,
- "mode pollinterval lasterror queue sysbuffer ttystatus xchar");
}
+ return Tcl_BadChannelOption(interp, optionName,
+ "mode pollinterval lasterror queue sysbuffer ttystatus xchar");
}
/*
@@ -2204,9 +2255,9 @@ SerialGetOptionProc(instanceData, interp, optionName, dsPtr)
*/
static void
-SerialThreadActionProc(instanceData, action)
- ClientData instanceData;
- int action;
+SerialThreadActionProc(
+ ClientData instanceData,
+ int action)
{
SerialInfo *infoPtr = (SerialInfo *) instanceData;