Attachment "tclUnixChan.c.patch" to
ticket [438509ffff]
added by
schroedter
2002-02-26 20:49:02.
*** tclUnixChan.c.old Tue Feb 26 08:05:26 2002
--- tclUnixChan.c Tue Feb 26 14:34:07 2002
***************
*** 45,60 ****
--- 45,81 ----
#ifdef USE_TERMIOS
# include <termios.h>
+ # include <sys/ioctl.h>
# define IOSTATE struct termios
# define GETIOSTATE(fd, statePtr) tcgetattr((fd), (statePtr))
# define SETIOSTATE(fd, statePtr) tcsetattr((fd), TCSADRAIN, (statePtr))
+ # define GETCONTROL(fd, intPtr) ioctl((fd), TIOCMGET, (intPtr))
+ # define SETCONTROL(fd, intPtr) ioctl((fd), TIOCMSET, (intPtr))
+ # define TTYFLUSH(fd) tcflush((fd), TCIOFLUSH);
+ # ifdef FIONREAD
+ # define GETREADQUEUE(fd, int) ioctl((fd), FIONREAD, &(int))
+ # elif defined(FIORDCHK)
+ # define GETREADQUEUE(fd, int) int = ioctl((fd), FIORDCHK, NULL)
+ # endif
+ # ifdef TIOCOUTQ
+ # define GETWRITEQUEUE(fd, int) ioctl((fd), TIOCOUTQ, &(int))
+ # endif
+ # if defined(TIOCSBRK) && defined(TIOCCBRK)
+ # define SETBREAK(fd, flag) \
+ ioctl((fd), (unsigned) ((flag) ? TIOCSBRK:TIOCCBRK), NULL)
+ # endif
+ # if !defined(CRTSCTS) && defined(CNEW_RTSCTS)
+ # define CRTSCTS CNEW_RTSCTS
+ # endif
#else /* !USE_TERMIOS */
+
#ifdef USE_TERMIO
# include <termio.h>
# define IOSTATE struct termio
# define GETIOSTATE(fd, statePtr) ioctl((fd), TCGETA, (statePtr))
# define SETIOSTATE(fd, statePtr) ioctl((fd), TCSETAW, (statePtr))
#else /* !USE_TERMIO */
+
#ifdef USE_SGTTY
# include <sgtty.h>
# define IOSTATE struct sgttyb
***************
*** 63,68 ****
--- 84,90 ----
#else /* !USE_SGTTY */
# undef SUPPORTS_TTY
#endif /* !USE_SGTTY */
+
#endif /* !USE_TERMIO */
#endif /* !USE_TERMIOS */
***************
*** 220,225 ****
--- 242,249 ----
Tcl_Interp *interp, CONST char *optionName,
Tcl_DString *dsPtr));
static FileState * TtyInit _ANSI_ARGS_((int fd, int initialize));
+ static int TtyOutputProc _ANSI_ARGS_((ClientData instanceData,
+ CONST char *buf, int toWrite, int *errorCode));
static int TtyParseMode _ANSI_ARGS_((Tcl_Interp *interp,
CONST char *mode, int *speedPtr, int *parityPtr,
int *dataPtr, int *stopPtr));
***************
*** 264,270 ****
TCL_CHANNEL_VERSION_2, /* v2 channel */
TtyCloseProc, /* Close proc. */
FileInputProc, /* Input proc. */
! FileOutputProc, /* Output proc. */
NULL, /* Seek proc. */
TtySetOptionProc, /* Set option proc. */
TtyGetOptionProc, /* Get option proc. */
--- 288,294 ----
TCL_CHANNEL_VERSION_2, /* v2 channel */
TtyCloseProc, /* Close proc. */
FileInputProc, /* Input proc. */
! TtyOutputProc, /* Output proc. */
NULL, /* Seek proc. */
TtySetOptionProc, /* Set option proc. */
TtyGetOptionProc, /* Get option proc. */
***************
*** 631,641 ****
* 0 if successful, errno if failed.
*
* Side effects:
! * Restores the settings and closes the device of the channel.
*
*----------------------------------------------------------------------
*/
-
static int
TtyCloseProc(instanceData, interp)
ClientData instanceData; /* Tty state. */
--- 655,664 ----
* 0 if successful, errno if failed.
*
* Side effects:
! * Closes the device of the channel.
*
*----------------------------------------------------------------------
*/
static int
TtyCloseProc(instanceData, interp)
ClientData instanceData; /* Tty state. */
***************
*** 644,658 ****
--- 667,761 ----
TtyState *ttyPtr;
ttyPtr = (TtyState *) instanceData;
+ #ifdef TTYFLUSH
+ TTYFLUSH(ttyPtr->fs.fd);
+ #endif
+ /* Don't unsave TTY state, tcl may be used as a simpler 'stty' */
+ #if 0
if (ttyPtr->stateUpdated) {
SETIOSTATE(ttyPtr->fs.fd, &ttyPtr->savedState);
}
+ #endif
return FileCloseProc(instanceData, interp);
}
/*
*----------------------------------------------------------------------
*
+ * TtyOutputProc--
+ *
+ * This procedure is invoked from the generic IO level to write
+ * output to a TTY channel.
+ *
+ * Results:
+ * The number of bytes written is returned or -1 on error. An
+ * output argument contains a POSIX error code if an error occurred,
+ * or zero.
+ *
+ * Side effects:
+ * Writes output on the output device of the channel
+ * if the channel is not designated to be closed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ static int
+ TtyOutputProc(instanceData, buf, toWrite, errorCodePtr)
+ ClientData instanceData; /* File state. */
+ CONST char *buf; /* The data buffer. */
+ int toWrite; /* How many bytes to write? */
+ int *errorCodePtr; /* Where to store error code. */
+ {
+ if ( TclInExit() ) {
+ /*
+ * Do not write data during Tcl exit.
+ * Serial port may block preventing Tcl from exit.
+ */
+ return toWrite;
+ } else {
+ return FileOutputProc(instanceData, buf, toWrite, errorCodePtr);
+ }
+ }
+
+ #ifdef USE_TERMIOS
+
+ /*
+ *----------------------------------------------------------------------
+ *
+ * TtyModemStatusStr --
+ *
+ * Converts a RS232 modem status list of readable flags
+ *
+ *----------------------------------------------------------------------
+ */
+ static void
+ TtyModemStatusStr(status, dsPtr)
+ int status; /* RS232 modem status */
+ Tcl_DString *dsPtr; /* Where to store string */
+ {
+ #ifdef TIOCM_CTS
+ Tcl_DStringAppendElement(dsPtr, "CTS");
+ Tcl_DStringAppendElement(dsPtr, (status & TIOCM_CTS) ? "1" : "0" );
+ #endif
+ #ifdef TIOCM_DSR
+ Tcl_DStringAppendElement(dsPtr, "DSR");
+ Tcl_DStringAppendElement(dsPtr, (status & TIOCM_DSR) ? "1" : "0" );
+ #endif
+ #ifdef TIOCM_RNG
+ Tcl_DStringAppendElement(dsPtr, "RING");
+ Tcl_DStringAppendElement(dsPtr, (status & TIOCM_RNG) ? "1" : "0" );
+ #endif
+ #ifdef TIOCM_CD
+ Tcl_DStringAppendElement(dsPtr, "DCD");
+ Tcl_DStringAppendElement(dsPtr, (status & TIOCM_CD) ? "1" : "0" );
+ #endif
+ }
+
+ #endif
+
+ /*
+ *----------------------------------------------------------------------
+ *
* TtySetOptionProc --
*
* Sets an option on a channel.
***************
*** 676,686 ****
CONST char *value; /* New value for option. */
{
FileState *fsPtr = (FileState *) instanceData;
! unsigned int len;
TtyAttrs tty;
len = strlen(optionName);
! if ((len > 1) && (strncmp(optionName, "-mode", len) == 0)) {
if (TtyParseMode(interp, value, &tty.baud, &tty.parity, &tty.data,
&tty.stop) != TCL_OK) {
return TCL_ERROR;
--- 779,799 ----
CONST char *value; /* New value for option. */
{
FileState *fsPtr = (FileState *) instanceData;
! unsigned int len, vlen;
TtyAttrs tty;
+ #ifdef USE_TERMIOS
+ int flag, control, argc;
+ CONST char **argv;
+ IOSTATE iostate;
+ #endif
len = strlen(optionName);
! vlen = strlen(value);
!
! /*
! * Option -mode baud,parity,databits,stopbits
! */
! if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) {
if (TtyParseMode(interp, value, &tty.baud, &tty.parity, &tty.data,
&tty.stop) != TCL_OK) {
return TCL_ERROR;
***************
*** 692,700 ****
TtySetAttributes(fsPtr->fd, &tty);
((TtyState *) fsPtr)->stateUpdated = 1;
return TCL_OK;
} else {
! return Tcl_BadChannelOption(interp, optionName, "mode");
}
}
/*
--- 805,985 ----
TtySetAttributes(fsPtr->fd, &tty);
((TtyState *) fsPtr)->stateUpdated = 1;
return TCL_OK;
+ }
+
+ #ifdef USE_TERMIOS
+
+ /*
+ * Option -handshake none|xonxoff|rtscts|dtrdsr
+ */
+ if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) {
+ /*
+ * Reset all handshake options
+ * DTR and RTS are ON by default
+ */
+ GETIOSTATE(fsPtr->fd, &iostate);
+ iostate.c_iflag &= ~(IXON | IXOFF | IXANY);
+ #ifdef CRTSCTS
+ iostate.c_cflag &= ~CRTSCTS;
+ #endif
+ if (strncasecmp(value, "NONE", vlen) == 0) {
+ /* leave all handshake options disabled */
+ } else if (strncasecmp(value, "XONXOFF", vlen) == 0) {
+ iostate.c_iflag |= (IXON | IXOFF | IXANY);
+ } else if (strncasecmp(value, "RTSCTS", vlen) == 0) {
+ #ifdef CRTSCTS
+ iostate.c_cflag |= CRTSCTS;
+ #else
+ if (interp) {
+ Tcl_AppendResult(interp, "-handshake RTSCTS ",
+ "not supported for this platform",
+ (char *) NULL);
+ }
+ return TCL_ERROR;
+ #endif
+ } else if (strncasecmp(value, "DTRDSR", vlen) == 0) {
+ if (interp) {
+ Tcl_AppendResult(interp, "-handshake DTRDSR ",
+ "not supported for this platform",
+ (char *) NULL);
+ }
+ return TCL_ERROR;
} else {
! if (interp) {
! Tcl_AppendResult(interp, "bad value for -handshake: ",
! "must be one of xonxoff, rtscts, dtrdsr or none",
! (char *) NULL);
! return TCL_ERROR;
! }
! }
! SETIOSTATE(fsPtr->fd, &iostate);
! return TCL_OK;
! }
!
! /*
! * Option -xchar {\x11 \x13}
! */
! if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) {
!
! GETIOSTATE(fsPtr->fd, &iostate);
! if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
! return TCL_ERROR;
! }
! if (argc == 2) {
! iostate.c_cc[VSTART] = argv[0][0];
! iostate.c_cc[VSTOP] = argv[1][0];
! } else {
! if (interp) {
! Tcl_AppendResult(interp,
! "bad value for -xchar: should be a list of two elements",
! (char *) NULL);
! }
! return TCL_ERROR;
}
+ SETIOSTATE(fsPtr->fd, &iostate);
+ return TCL_OK;
+ }
+
+ /*
+ * Option -timeout msec
+ */
+ if ((len > 2) && (strncmp(optionName, "-timeout", len) == 0)) {
+ int msec;
+
+ GETIOSTATE(fsPtr->fd, &iostate);
+ if ( Tcl_GetInt(interp, value, &msec) != TCL_OK ) {
+ return TCL_ERROR;
+ }
+ iostate.c_cc[VMIN] = 0;
+ iostate.c_cc[VTIME] = (msec == 0) ? 0 : (msec < 100) ? 1 : (msec+50)/100;
+ SETIOSTATE(fsPtr->fd, &iostate);
+ return TCL_OK;
+ }
+
+ /*
+ * Option -ttycontrol {DTR 1 RTS 0 BREAK 0}
+ */
+ if ((len > 4) && (strncmp(optionName, "-ttycontrol", len) == 0)) {
+
+ 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);
+ }
+ return TCL_ERROR;
+ }
+
+ GETCONTROL(fsPtr->fd, &control);
+ while (argc > 1) {
+ if (Tcl_GetBoolean(interp, argv[1], &flag) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ if (strncasecmp(argv[0], "DTR", strlen(argv[0])) == 0) {
+ #ifdef TIOCM_DTR
+ if (flag ) {
+ control |= TIOCM_DTR;
+ } else {
+ control &= ~TIOCM_DTR;
+ }
+ #else
+ if (interp) {
+ Tcl_AppendResult(interp, "-ttycontrol DTR ",
+ "not supported for this platform",
+ (char *) NULL);
+ }
+ return TCL_ERROR;
+ #endif
+ } else if (strncasecmp(argv[0], "RTS", strlen(argv[0])) == 0) {
+ #ifdef TIOCM_RTS
+ if (flag ) {
+ control |= TIOCM_RTS;
+ } else {
+ control &= ~TIOCM_RTS;
+ }
+ #else
+ if (interp) {
+ Tcl_AppendResult(interp, "-ttycontrol RTS ",
+ "not supported for this platform",
+ (char *) NULL);
+ }
+ return TCL_ERROR;
+ #endif
+ } else if (strncasecmp(argv[0], "BREAK", strlen(argv[0])) == 0) {
+ #ifdef SETBREAK
+ SETBREAK(fsPtr->fd, flag);
+ #else
+ if (interp) {
+ Tcl_AppendResult(interp, "-ttycontrol BREAK ",
+ "not supported for this platform",
+ (char *) NULL);
+ }
+ return TCL_ERROR;
+ #endif
+ } else {
+ if (interp) {
+ Tcl_AppendResult(interp,
+ "bad signal for -ttycontrol: must be ",
+ "DTR, RTS or BREAK", (char *) NULL);
+ }
+ return TCL_ERROR;
+ }
+ argc -= 2, argv += 2;
+ } /* while (argc > 1) */
+
+ SETCONTROL(fsPtr->fd, &control);
+ return TCL_OK;
+ }
+
+ return Tcl_BadChannelOption(interp, optionName,
+ "mode handshake timeout ttycontrol xchar ");
+
+ #else /* not USE_TERMIOS */
+ return Tcl_BadChannelOption(interp, optionName, "mode");
+ #endif
}
/*
***************
*** 730,750 ****
unsigned int len;
char buf[3 * TCL_INTEGER_SPACE + 16];
TtyAttrs tty;
if (optionName == NULL) {
- Tcl_DStringAppendElement(dsPtr, "-mode");
len = 0;
} else {
len = strlen(optionName);
}
if ((len == 0) ||
! ((len > 1) && (strncmp(optionName, "-mode", len) == 0))) {
TtyGetAttributes(fsPtr->fd, &tty);
sprintf(buf, "%d,%c,%d,%d", tty.baud, tty.parity, tty.data, tty.stop);
Tcl_DStringAppendElement(dsPtr, buf);
return TCL_OK;
} else {
! return Tcl_BadChannelOption(interp, optionName, "mode");
}
}
--- 1015,1108 ----
unsigned int len;
char buf[3 * TCL_INTEGER_SPACE + 16];
TtyAttrs tty;
+ int valid = 0; /* flag if valid option parsed */
if (optionName == NULL) {
len = 0;
} else {
len = strlen(optionName);
}
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-mode");
+ }
if ((len == 0) ||
! ((len > 2) && (strncmp(optionName, "-mode", len) == 0))) {
! valid = 1;
TtyGetAttributes(fsPtr->fd, &tty);
sprintf(buf, "%d,%c,%d,%d", tty.baud, tty.parity, tty.data, tty.stop);
Tcl_DStringAppendElement(dsPtr, buf);
+ }
+
+ #ifdef USE_TERMIOS
+ /*
+ * get option -xchar
+ */
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-xchar");
+ Tcl_DStringStartSublist(dsPtr);
+ }
+ if ((len == 0) ||
+ ((len > 1) && (strncmp(optionName, "-xchar", len) == 0))) {
+
+ IOSTATE iostate;
+ valid = 1;
+
+ GETIOSTATE(fsPtr->fd, &iostate);
+ sprintf(buf, "%c", iostate.c_cc[VSTART]);
+ Tcl_DStringAppendElement(dsPtr, buf);
+ sprintf(buf, "%c", iostate.c_cc[VSTOP]);
+ Tcl_DStringAppendElement(dsPtr, buf);
+ }
+ if (len == 0) {
+ Tcl_DStringEndSublist(dsPtr);
+ }
+
+ /*
+ * get option -queue
+ * option is readonly and returned by [fconfigure chan -queue]
+ * but not returned by unnamed [fconfigure chan]
+ */
+ if ( (len > 1) && (strncmp(optionName, "-queue", len) == 0) ) {
+ int inQueue=0, outQueue=0;
+ int inBuffered, outBuffered;
+ valid = 1;
+ #ifdef GETREADQUEUE
+ GETREADQUEUE(fsPtr->fd, inQueue);
+ #endif
+ #ifdef GETWRITEQUEUE
+ GETWRITEQUEUE(fsPtr->fd, outQueue);
+ #endif
+ inBuffered = Tcl_InputBuffered(fsPtr->channel);
+ outBuffered = Tcl_OutputBuffered(fsPtr->channel);
+
+ sprintf(buf, "%d", inBuffered+inQueue);
+ Tcl_DStringAppendElement(dsPtr, buf);
+ sprintf(buf, "%d", outBuffered+outQueue);
+ Tcl_DStringAppendElement(dsPtr, buf);
+ }
+
+ /*
+ * get option -ttystatus
+ * option is readonly and returned by [fconfigure chan -ttystatus]
+ * but not returned by unnamed [fconfigure chan]
+ */
+ if ( (len > 4) && (strncmp(optionName, "-ttystatus", len) == 0) ) {
+ int status;
+ valid = 1;
+ GETCONTROL(fsPtr->fd, &status);
+ TtyModemStatusStr(status, dsPtr);
+ }
+ #endif
+
+ if (valid) {
return TCL_OK;
} else {
! return Tcl_BadChannelOption(interp, optionName,
! #ifdef USE_TERMIOS
! "mode queue ttystatus xchar");
! #else
! "mode");
! #endif
}
}