diff options
Diffstat (limited to 'win/tclWinSerial.c')
-rw-r--r-- | win/tclWinSerial.c | 501 |
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; |