Attachment "219146.0.diff" to
ticket [219269ffff]
added by
andreas_kupries
2001-04-10 06:13:54.
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.416
diff -u -r1.416 ChangeLog
--- ChangeLog 2001/04/09 23:02:21 1.416
+++ ChangeLog 2001/04/09 23:10:12
@@ -1,3 +1,10 @@
+2001-04-10 Andreas Kupries <[email protected]>
+
+ * unix/tclUnixChan (TclpOpenFileChannel, Tcl_MakeFileChannel):
+ Extended to detect the type of the opened/specified file
+ descriptor (socket, tty, ...) and to create the appropriate tcl
+ channel for it. [Bug #219146, #219269].
+
2001-04-09 Kevin B. Kenny <[email protected]>
* unix/tcl.m4: Added _REENTRANT to Solaris build so that thread
Index: unix/tclUnixChan.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixChan.c,v
retrieving revision 1.19
diff -u -r1.19 tclUnixChan.c
--- unix/tclUnixChan.c 2000/10/28 00:29:58 1.19
+++ unix/tclUnixChan.c 2001/04/09 23:10:20
@@ -178,6 +178,7 @@
static int CreateSocketAddress _ANSI_ARGS_(
(struct sockaddr_in *sockaddrPtr,
char *host, int port));
+static Tcl_Channel CreateSocketForFd _ANSI_ARGS_ ((int fd));
static int FileBlockModeProc _ANSI_ARGS_((
ClientData instanceData, int mode));
static int FileCloseProc _ANSI_ARGS_((ClientData instanceData,
@@ -193,6 +194,7 @@
long offset, int mode, int *errorCode));
static void FileWatchProc _ANSI_ARGS_((ClientData instanceData,
int mask));
+static Tcl_Channel CreateFileForFd _ANSI_ARGS_ ((int fd, int mode));
static void TcpAccept _ANSI_ARGS_((ClientData data, int mask));
static int TcpBlockModeProc _ANSI_ARGS_((ClientData data,
int mode));
@@ -226,6 +228,7 @@
static int TtySetOptionProc _ANSI_ARGS_((ClientData instanceData,
Tcl_Interp *interp, char *optionName,
char *value));
+static Tcl_Channel CreateTtyForFd _ANSI_ARGS_ ((int fd, int mode));
#endif /* SUPPORTS_TTY */
static int WaitForConnect _ANSI_ARGS_((TcpState *statePtr,
int *errorCodePtr));
@@ -605,6 +608,49 @@
}
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * CreateFileForFd --
+ *
+ * This function creates and initializes a file channel for an
+ * existing file descriptor.
+ *
+ * Results:
+ * A reference to the new channel or NULL.
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_Channel
+CreateFileForFd (fd, mode)
+ int fd;
+ int mode;
+{
+ FileState *fsPtr;
+ char channelName[16 + TCL_INTEGER_SPACE];
+
+ fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));
+ if (fsPtr == NULL) {
+ return NULL;
+ }
+
+#ifdef DEPRECATED
+ fsPtr->nextPtr = tsdPtr->firstFilePtr;
+ tsdPtr->firstFilePtr = fsPtr;
+#endif
+ fsPtr->fd = fd;
+ fsPtr->validMask = mode | TCL_EXCEPTION;
+
+ sprintf(channelName, "file%d", fd);
+ fsPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName,
+ (ClientData) fsPtr, mode);
+ return fsPtr->channel;
+}
+
#ifdef SUPPORTS_TTY
/*
@@ -1203,7 +1249,7 @@
* Tcl can talk to a device located on the serial port.
*
* Results:
- * None.
+ * A reference to the allocated TtyState.
*
* Side effects:
* Serial device initialized to non-blocking raw mode, similar to
@@ -1257,6 +1303,65 @@
/*
*----------------------------------------------------------------------
*
+ * CreateTtyForFd --
+ *
+ * This function creates and initializes a tty channel for an
+ * existing file descriptor.
+ *
+ * Results:
+ * A reference to the new channel or NULL.
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_Channel
+CreateTtyForFd (fd, mode)
+ int fd;
+ int mode;
+{
+ /*
+ * Initialize the serial port to a set of sane parameters.
+ * Especially important if the remote device is set to echo and
+ * the serial port driver was also set to echo -- as soon as a char
+ * were sent to the serial port, the remote device would echo it,
+ * then the serial driver would echo it back to the device, etc.
+ */
+
+ FileState *ttyPtr;
+ char channelName [16 + TCL_INTEGER_SPACE];
+
+ ttyPtr = TtyInit(fd); /* Actually a (TtyState*)! */
+
+ ttyPtr->validMask = mode | TCL_EXCEPTION;
+ ttyPtr->fd = fd;
+
+ sprintf(channelName, "file%d", fd);
+ ttyPtr->channel = Tcl_CreateChannel(&ttyChannelType, channelName,
+ (ClientData) ttyPtr, mode);
+
+ /*
+ * Gotcha. Most modems need a "\r" at the end of the command
+ * sequence. If you just send "at\n", the modem will not respond
+ * with "OK" because it never got a "\r" to actually invoke the
+ * command. So, by default, newlines are translated to "\r\n" on
+ * output to avoid "bug" reports that the serial port isn't working.
+ */
+
+ if (Tcl_SetChannelOption(NULL, ttyPtr->channel, "-translation",
+ "auto crlf") != TCL_OK) {
+ Tcl_Close(NULL, ttyPtr->channel);
+ return NULL;
+ }
+
+ return ttyPtr->channel;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclpOpenFileChannel --
*
* Open an file based channel on Unix systems.
@@ -1285,11 +1390,9 @@
* it? */
{
int fd, seekFlag, mode, channelPermissions;
- FileState *fsPtr;
- char *native, *translation;
- char channelName[16 + TCL_INTEGER_SPACE];
+ char *native;
Tcl_DString ds, buffer;
- Tcl_ChannelType *channelTypePtr;
+ Tcl_Channel chan;
#ifdef DEPRECATED
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#endif
@@ -1340,67 +1443,39 @@
fcntl(fd, F_SETFD, FD_CLOEXEC);
- sprintf(channelName, "file%d", fd);
-
#ifdef SUPPORTS_TTY
if (isatty(fd)) {
- /*
- * Initialize the serial port to a set of sane parameters.
- * Especially important if the remote device is set to echo and
- * the serial port driver was also set to echo -- as soon as a char
- * were sent to the serial port, the remote device would echo it,
- * then the serial driver would echo it back to the device, etc.
- */
-
- translation = "auto crlf";
- channelTypePtr = &ttyChannelType;
- fsPtr = TtyInit(fd);
- } else
+ chan = CreateTtyForFd (fd, channelPermissions);
+ } else
#endif /* SUPPORTS_TTY */
{
- translation = NULL;
- channelTypePtr = &fileChannelType;
- fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));
+ struct stat buf;
+ fstat (fd, &buf);
+
+ if (S_ISSOCK(buf.st_mode)) {
+ chan = CreateSocketForFd (fd);
+ } else {
+ chan = CreateFileForFd (fd, channelPermissions);
+ }
}
-#ifdef DEPRECATED
- fsPtr->nextPtr = tsdPtr->firstFilePtr;
- tsdPtr->firstFilePtr = fsPtr;
-#endif
- fsPtr->validMask = channelPermissions | TCL_EXCEPTION;
- fsPtr->fd = fd;
-
- fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName,
- (ClientData) fsPtr, channelPermissions);
+ if (chan == (Tcl_Channel) NULL) {
+ return chan;
+ }
if (seekFlag) {
- if (Tcl_Seek(fsPtr->channel, 0, SEEK_END) < 0) {
- if (interp != (Tcl_Interp *) NULL) {
+ if (Tcl_Seek(chan, 0, SEEK_END) < 0) {
+ if (interp != (Tcl_Interp *) NULL) {
Tcl_AppendResult(interp, "couldn't seek to end of file on \"",
- channelName, "\": ", Tcl_PosixError(interp), NULL);
+ Tcl_GetChannelName (chan), "\": ",
+ Tcl_PosixError(interp), NULL);
}
- Tcl_Close(NULL, fsPtr->channel);
+ Tcl_Close(NULL, chan);
return NULL;
}
}
-
- if (translation != NULL) {
- /*
- * Gotcha. Most modems need a "\r" at the end of the command
- * sequence. If you just send "at\n", the modem will not respond
- * with "OK" because it never got a "\r" to actually invoke the
- * command. So, by default, newlines are translated to "\r\n" on
- * output to avoid "bug" reports that the serial port isn't working.
- */
-
- if (Tcl_SetChannelOption(interp, fsPtr->channel, "-translation",
- translation) != TCL_OK) {
- Tcl_Close(NULL, fsPtr->channel);
- return NULL;
- }
- }
- return fsPtr->channel;
+ return chan;
}
/*
@@ -1425,8 +1500,6 @@
int mode; /* ORed combination of TCL_READABLE and
* TCL_WRITABLE to indicate file mode. */
{
- FileState *fsPtr;
- char channelName[16 + TCL_INTEGER_SPACE];
int fd = (int) handle;
#ifdef DEPRECATED
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -1436,9 +1509,6 @@
return NULL;
}
- sprintf(channelName, "file%d", fd);
-
-
/*
* Look to see if a channel with this fd and the same mode already exists.
* If the fd is used, but the mode doesn't match, return NULL.
@@ -1453,18 +1523,32 @@
}
#endif
- fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));
+ /*
+ * Try to determine the type of this fd (file, socket, tty, ...)
+ * and create the corresponding channel
+ */
-#ifdef DEPRECATED
- fsPtr->nextPtr = tsdPtr->firstFilePtr;
- tsdPtr->firstFilePtr = fsPtr;
-#endif
- fsPtr->fd = fd;
- fsPtr->validMask = mode | TCL_EXCEPTION;
- fsPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName,
- (ClientData) fsPtr, mode);
-
- return fsPtr->channel;
+#ifdef SUPPORTS_TTY
+ if (isatty(fd)) {
+ return CreateTtyForFd (fd, mode);
+ }
+#endif /* SUPPORTS_TTY */
+ {
+ struct stat buf;
+ fstat (fd, &buf);
+
+ if (S_ISSOCK(buf.st_mode)) {
+ return CreateSocketForFd (fd);
+ }
+
+ return CreateFileForFd (fd, mode);
+ }
+
+ /*
+ * Shouldn't be reached, ever.
+ */
+
+ return NULL;
}
/*
@@ -2228,6 +2312,57 @@
sockaddrPtr->sin_addr.s_addr = addr.s_addr;
return 1; /* Success. */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CreateSocketForFd --
+ *
+ * This function creates and initializes a tcp channel for an
+ * existing file descriptor.
+ *
+ * Results:
+ * A reference to the new channel or NULL.
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_Channel
+CreateSocketForFd (fd)
+ int fd;
+{
+ TcpState *tcpPtr;
+ char channelName [16 + TCL_INTEGER_SPACE];
+
+ tcpPtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState));
+ if (tcpPtr == NULL) {
+ return NULL;
+ }
+
+ tcpPtr->flags = 0;
+ tcpPtr->fd = fd;
+ tcpPtr->acceptProc = NULL;
+ tcpPtr->acceptProcData = (ClientData) NULL;
+
+ sprintf(channelName, "sock%d", fd);
+ tcpPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
+ (ClientData) tcpPtr,
+ (TCL_READABLE | TCL_WRITABLE));
+ /*
+ * Sockets connections use CR+LF as line separator (outgoing).
+ */
+
+ if (Tcl_SetChannelOption(NULL, tcpPtr->channel, "-translation",
+ "auto crlf") != TCL_OK) {
+ Tcl_Close(NULL, tcpPtr->channel);
+ return NULL;
+ }
+
+ return tcpPtr->channel;
}
/*