From 298f69f947759d7c1fabe350452fcf9303c89376 Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 18 Jun 2001 13:13:23 +0000 Subject: Unix channels now have the right type associated with them [bug #219137] A couple of nasty faults/assumptions in unixInit.test are fixed too. --- ChangeLog | 17 +++++++++++ tests/unixInit.test | 29 +++++++++++++----- unix/tclUnixChan.c | 87 +++++++++++++++++++++++++++++++++++------------------ 3 files changed, 96 insertions(+), 37 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7cf1714..ea31e4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2001-06-18 Donal K. Fellows + + * tests/unixInit.test (unixInit-1.2,unixInit-2.8): Added test for + code described below, and fixed a couple of errors that caused + problems during testing; the code to determine the installedTcl + constraint was wrong, and test unixInit-2.8 assumed that /tmp/lib + was free for use and could be deleted, which clashed nastily with + my installation and made other tests fail unnecessarily! + + * unix/tclUnixChan.c (TtyInit,TclpOpenFileChannel, + Tcl_MakeFileChannel,TclpGetDefaultStdChannel): Alterations so that + the standard channels - stdin, stdout and stderr - have the + correct type and fconfigure options. This required making the + initialisation of serial lines a little more sophisticated to + make the console behave correctly in interactive mode... [Bug + #219137 and duplicates] + 2001-06-16 Don Porter * generic/tclInt.decls: diff --git a/tests/unixInit.test b/tests/unixInit.test index 3017587..4c11741 100644 --- a/tests/unixInit.test +++ b/tests/unixInit.test @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: unixInit.test,v 1.14 2001/01/04 21:30:49 dgp Exp $ +# RCS: @(#) $Id: unixInit.test,v 1.15 2001/06/18 13:13:23 dkf Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest @@ -27,10 +27,10 @@ set env(LANG) C # Some tests will fail if they are run on a machine that doesn't have # this Tcl version installed (as opposed to built) on it. if {[catch { - set f [open "|[list $::tcltest::tcltest exit]" w+] + set f [open "|[list $::tcltest::tcltest]" w+] exec kill -PIPE [pid $f] close $f -}]} { +} msg]} { set ::tcltest::testConstraints(installedTcl) 0 } else { set ::tcltest::testConstraints(installedTcl) 1 @@ -59,6 +59,19 @@ test unixInit-1.1 {TclpInitPlatform: ignore SIGPIPE} {unixOnly installedTcl} { set x } {0 1} +# This test is really a test of code in tclUnixChan.c, but the +# channels are set up as part of initialisation of the interpreter so +# the test seems to me to fit here as well as anywhere else. +test unixInit-1.2 {initialisation: channel type deduction} {unixOnly installedTcl} { + set sock [socket localhost echo] + set pipe [open |[list $::tcltest::tcltest >@$sock] w] + puts $pipe {puts [fconfigure stdout -peername]; exit} + close $pipe + gets $sock channeltype + close $sock + set channeltype +} {127.0.0.1 localhost 7} + proc getlibpath "{program [list $::tcltest::tcltest]}" { set f [open "|$program" w+] fconfigure $f -buffering none @@ -152,12 +165,12 @@ test unixInit-2.7 {TclpInitLibraryPath: compiled-in library path} \ } {} test unixInit-2.8 {TclpInitLibraryPath: all absolute pathtype} {unixOnly} { file delete -force /tmp/sparkly - file delete -force /tmp/lib + file delete -force /tmp/library file mkdir /tmp/sparkly file copy $::tcltest::tcltest /tmp/sparkly/tcltest - file mkdir /tmp/lib/tcl[info tclversion] - close [open /tmp/lib/tcl[info tclversion]/init.tcl w] + file mkdir /tmp/library/tcl[info tclversion] + close [open /tmp/library/tcl[info tclversion]/init.tcl w] set allAbsolute 1 foreach dir [getlibpath /tmp/sparkly/tcltest] { @@ -165,7 +178,7 @@ test unixInit-2.8 {TclpInitLibraryPath: all absolute pathtype} {unixOnly} { && [string equal absolute [file pathtype $dir]]}] } file delete -force /tmp/sparkly - file delete -force /tmp/lib + file delete -force /tmp/library set allAbsolute } 1 test unixInit-3.1 {TclpSetInitialEncodings} {unixOnly installedTcl} { @@ -215,7 +228,7 @@ test unixInit-5.1 {Tcl_Init} {emptyTest unixOnly} { test unixInit-6.1 {Tcl_SourceRCFile} {emptyTest unixOnly} { } {} - + # cleanup if {[info exists oldlibrary]} { set env(TCL_LIBRARY) $oldlibrary diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index 1bf9d54..d31cc6c 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixChan.c,v 1.19 2000/10/28 00:29:58 hobbs Exp $ + * RCS: @(#) $Id: tclUnixChan.c,v 1.20 2001/06/18 13:13:23 dkf Exp $ */ #include "tclInt.h" /* Internal definitions for Tcl. */ @@ -217,7 +217,7 @@ static void TtyGetAttributes _ANSI_ARGS_((int fd, static int TtyGetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, char *optionName, Tcl_DString *dsPtr)); -static FileState * TtyInit _ANSI_ARGS_((int fd)); +static FileState * TtyInit _ANSI_ARGS_((int fd, int initialize)); static int TtyParseMode _ANSI_ARGS_((Tcl_Interp *interp, CONST char *mode, int *speedPtr, int *parityPtr, int *dataPtr, int *stopPtr)); @@ -1201,54 +1201,61 @@ TtyParseMode(interp, mode, speedPtr, parityPtr, dataPtr, stopPtr) * Given file descriptor that refers to a serial port, * initialize the serial port to a set of sane values so that * Tcl can talk to a device located on the serial port. + * Note that no initialization happens if the initialize flag + * is not set; this is necessary for the correct handling of + * UNIX console TTYs at startup. * * Results: - * None. + * A pointer to a FileState suitable for use with Tcl_CreateChannel + * and the ttyChannelType structure. * * Side effects: * Serial device initialized to non-blocking raw mode, similar to - * sockets. All other modes can be simulated on top of this in Tcl. + * sockets (if initialize flag is non-zero.) All other modes can + * be simulated on top of this in Tcl. * *--------------------------------------------------------------------------- */ static FileState * -TtyInit(fd) +TtyInit(fd, initialize) int fd; /* Open file descriptor for serial port to * be initialized. */ + int initialize; { - IOSTATE iostate; TtyState *ttyPtr; ttyPtr = (TtyState *) ckalloc((unsigned) sizeof(TtyState)); GETIOSTATE(fd, &ttyPtr->savedState); - iostate = ttyPtr->savedState; + if (initialize) { + IOSTATE iostate = ttyPtr->savedState; #ifdef USE_TERMIOS - iostate.c_iflag = IGNBRK; - iostate.c_oflag = 0; - iostate.c_lflag = 0; - iostate.c_cflag |= CREAD; - iostate.c_cc[VMIN] = 1; - iostate.c_cc[VTIME] = 0; + iostate.c_iflag = IGNBRK; + iostate.c_oflag = 0; + iostate.c_lflag = 0; + iostate.c_cflag |= CREAD; + iostate.c_cc[VMIN] = 1; + iostate.c_cc[VTIME] = 0; #endif /* USE_TERMIOS */ #ifdef USE_TERMIO - iostate.c_iflag = IGNBRK; - iostate.c_oflag = 0; - iostate.c_lflag = 0; - iostate.c_cflag |= CREAD; - iostate.c_cc[VMIN] = 1; - iostate.c_cc[VTIME] = 0; + iostate.c_iflag = IGNBRK; + iostate.c_oflag = 0; + iostate.c_lflag = 0; + iostate.c_cflag |= CREAD; + iostate.c_cc[VMIN] = 1; + iostate.c_cc[VTIME] = 0; #endif /* USE_TERMIO */ #ifdef USE_SGTTY - iostate.sg_flags &= (EVENP | ODDP); - iostate.sg_flags |= RAW; + iostate.sg_flags &= (EVENP | ODDP); + iostate.sg_flags |= RAW; #endif /* USE_SGTTY */ - SETIOSTATE(fd, &iostate); + SETIOSTATE(fd, &iostate); + } return &ttyPtr->fs; } @@ -1354,7 +1361,7 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) translation = "auto crlf"; channelTypePtr = &ttyChannelType; - fsPtr = TtyInit(fd); + fsPtr = TtyInit(fd, 1); } else #endif /* SUPPORTS_TTY */ { @@ -1428,16 +1435,17 @@ Tcl_MakeFileChannel(handle, mode) FileState *fsPtr; char channelName[16 + TCL_INTEGER_SPACE]; int fd = (int) handle; + Tcl_ChannelType *channelTypePtr; #ifdef DEPRECATED ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #endif + int socketType = 0; + int argLength = sizeof(int); if (mode == 0) { return NULL; } - sprintf(channelName, "file%d", fd); - /* * Look to see if a channel with this fd and the same mode already exists. @@ -1453,7 +1461,24 @@ Tcl_MakeFileChannel(handle, mode) } #endif - fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); +#ifdef SUPPORTS_TTY + if (isatty(fd)) { + fsPtr = TtyInit(fd, 0); + channelTypePtr = &ttyChannelType; + sprintf(channelName, "serial%d", fd); + } else +#endif + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (VOID *)&socketType, + &argLength) == 0 && socketType == SOCK_STREAM) { + /* + * The mode parameter gets lost here, unfortunately. + */ + return Tcl_MakeTcpClientChannel((ClientData) fd); + } else { + channelTypePtr = &fileChannelType; + fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); + sprintf(channelName, "file%d", fd); + } #ifdef DEPRECATED fsPtr->nextPtr = tsdPtr->firstFilePtr; @@ -1461,9 +1486,9 @@ Tcl_MakeFileChannel(handle, mode) #endif fsPtr->fd = fd; fsPtr->validMask = mode | TCL_EXCEPTION; - fsPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName, + fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, (ClientData) fsPtr, mode); - + return fsPtr->channel; } @@ -2515,7 +2540,11 @@ TclpGetDefaultStdChannel(type) * Set up the normal channel options for stdio handles. */ - Tcl_SetChannelOption(NULL, channel, "-translation", "auto"); + if (Tcl_GetChannelType(channel) == &fileChannelType) { + Tcl_SetChannelOption(NULL, channel, "-translation", "auto"); + } else { + Tcl_SetChannelOption(NULL, channel, "-translation", "auto crlf"); + } Tcl_SetChannelOption(NULL, channel, "-buffering", bufMode); return channel; } -- cgit v0.12