diff options
Diffstat (limited to 'unix/tclUnixChan.c')
| -rw-r--r-- | unix/tclUnixChan.c | 1822 | 
1 files changed, 262 insertions, 1560 deletions
| diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index 629f9d0..fdc9d1d 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -7,25 +7,16 @@   * Copyright (c) 1995-1997 Sun Microsystems, Inc.   * Copyright (c) 1998-1999 by Scriptics Corporation.   * - * 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.93 2008/03/03 14:54:43 rmax Exp $ + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   */  #include "tclInt.h"	/* Internal definitions for Tcl. */  #include "tclIO.h"	/* To get Channel type declaration. */ -#define SUPPORTS_TTY - -#undef DIRECT_BAUD -#ifdef B4800 -#   if (B4800 == 4800) -#	define DIRECT_BAUD -#   endif /* B4800 == 4800 */ -#endif /* B4800 */ - -#ifdef USE_TERMIOS +#undef SUPPORTS_TTY +#if defined(HAVE_TERMIOS_H) +#   define SUPPORTS_TTY 1  #   include <termios.h>  #   ifdef HAVE_SYS_IOCTL_H  #	include <sys/ioctl.h> @@ -33,60 +24,29 @@  #   ifdef HAVE_SYS_MODEM_H  #	include <sys/modem.h>  #   endif /* HAVE_SYS_MODEM_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))  #   ifdef FIONREAD  #	define GETREADQUEUE(fd, int)	ioctl((fd), FIONREAD, &(int))  #   elif defined(FIORDCHK)  #	define GETREADQUEUE(fd, int)	int = ioctl((fd), FIORDCHK, NULL) -#   endif /* FIONREAD */ +#   else +#       define GETREADQUEUE(fd, int)    int = 0 +#   endif +  #   ifdef TIOCOUTQ  #	define GETWRITEQUEUE(fd, int)	ioctl((fd), TIOCOUTQ, &(int)) -#   endif /* TIOCOUTQ */ -#   if defined(TIOCSBRK) && defined(TIOCCBRK) +#   else +#	define GETWRITEQUEUE(fd, int)	int = 0 +#   endif -/* - * Can't use ?: operator below because that messes up types on either Linux or - * Solaris (the two are mutually exclusive!) - */ - -#	define SETBREAK(fd, flag) \ -		if (flag) {				\ -		    ioctl((fd), TIOCSBRK, NULL);	\ -		} else {				\ -		    ioctl((fd), TIOCCBRK, NULL);	\ -		} -#   endif /* TIOCSBRK&TIOCCBRK */  #   if !defined(CRTSCTS) && defined(CNEW_RTSCTS)  #	define CRTSCTS CNEW_RTSCTS  #   endif /* !CRTSCTS&CNEW_RTSCTS */  #   if !defined(PAREXT) && defined(CMSPAR)  #	define PAREXT CMSPAR  #   endif /* !PAREXT&&CMSPAR */ -#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 -#   define GETIOSTATE(fd, statePtr)	ioctl((fd), TIOCGETP, (statePtr)) -#   define SETIOSTATE(fd, statePtr)	ioctl((fd), TIOCSETP, (statePtr)) -#else	/* !USE_SGTTY */ -#   undef SUPPORTS_TTY -#endif	/* !USE_SGTTY */ - -#endif	/* !USE_TERMIO */ -#endif	/* !USE_TERMIOS */ + +#endif	/* HAVE_TERMIOS_H */  /*   * Helper macros to make parts of this file clearer. The macros do exactly @@ -112,18 +72,6 @@ typedef struct FileState {  #ifdef SUPPORTS_TTY  /* - * The following structure describes per-instance state of a tty-based - * channel. - */ - -typedef struct TtyState { -    FileState fs;		/* Per-instance state of the file descriptor. -				 * Must be the first field. */ -    IOSTATE savedState;		/* Initial state of device. Used to reset -				 * state when device closed. */ -} TtyState; - -/*   * The following structure is used to set or get the serial port attributes in   * a platform-independant manner.   */ @@ -138,66 +86,16 @@ typedef struct TtyAttrs {  #endif	/* !SUPPORTS_TTY */  #define UNSUPPORTED_OPTION(detail) \ -    if (interp) {						\ -	Tcl_AppendResult(interp, (detail),			\ -		" not supported for this platform", NULL);	\ +    if (interp) {							\ +	Tcl_SetObjResult(interp, Tcl_ObjPrintf(				\ +		"%s not supported for this platform", (detail)));	\ +	Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL);		\      }  /* - * This structure describes per-instance state of a tcp based channel. - */ - -typedef struct TcpState { -    Tcl_Channel channel;	/* Channel associated with this file. */ -    int fd;			/* The socket itself. */ -    int flags;			/* ORed combination of the bitfields defined -				 * below. */ -    Tcl_TcpAcceptProc *acceptProc; -				/* Proc to call on accept. */ -    ClientData acceptProcData;	/* The data for the accept proc. */ -} TcpState; - -/* - * These bits may be ORed together into the "flags" field of a TcpState - * structure. - */ - -#define TCP_ASYNC_SOCKET	(1<<0)	/* Asynchronous socket. */ -#define TCP_ASYNC_CONNECT	(1<<1)	/* Async connect in progress. */ - -/* - * The following defines the maximum length of the listen queue. This is the - * number of outstanding yet-to-be-serviced requests for a connection on a - * server socket, more than this number of outstanding requests and the - * connection request will fail. - */ - -#ifndef SOMAXCONN -#   define SOMAXCONN	100 -#endif /* SOMAXCONN */ - -#if (SOMAXCONN < 100) -#   undef  SOMAXCONN -#   define SOMAXCONN	100 -#endif /* SOMAXCONN < 100 */ - -/* - * The following defines how much buffer space the kernel should maintain for - * a socket. - */ - -#define SOCKET_BUFSIZE	4096 - -/*   * Static routines for this file:   */ -static TcpState *	CreateSocket(Tcl_Interp *interp, int port, -			    const char *host, int server, const char *myaddr, -			    int myport, int async); -static int		CreateSocketAddress(struct sockaddr_in *sockaddrPtr, -			    const char *host, int port, int willBind, -			    const char **errorMsgPtr);  static int		FileBlockModeProc(ClientData instanceData, int mode);  static int		FileCloseProc(ClientData instanceData,  			    Tcl_Interp *interp); @@ -214,48 +112,28 @@ static int		FileTruncateProc(ClientData instanceData,  static Tcl_WideInt	FileWideSeekProc(ClientData instanceData,  			    Tcl_WideInt offset, int mode, int *errorCode);  static void		FileWatchProc(ClientData instanceData, int mask); -static void		TcpAccept(ClientData data, int mask); -static int		TcpBlockModeProc(ClientData data, int mode); -static int		TcpCloseProc(ClientData instanceData, -			    Tcl_Interp *interp); -static int		TcpGetHandleProc(ClientData instanceData, -			    int direction, ClientData *handlePtr); -static int		TcpGetOptionProc(ClientData instanceData, -			    Tcl_Interp *interp, const char *optionName, -			    Tcl_DString *dsPtr); -static int		TcpInputProc(ClientData instanceData, char *buf, -			    int toRead, int *errorCode); -static int		TcpOutputProc(ClientData instanceData, -			    const char *buf, int toWrite, int *errorCode); -static void		TcpWatchProc(ClientData instanceData, int mask);  #ifdef SUPPORTS_TTY  static void		TtyGetAttributes(int fd, TtyAttrs *ttyPtr);  static int		TtyGetOptionProc(ClientData instanceData,  			    Tcl_Interp *interp, const char *optionName,  			    Tcl_DString *dsPtr); -#ifndef DIRECT_BAUD -static int		TtyGetBaud(unsigned long speed); -static unsigned long	TtyGetSpeed(int baud); -#endif /* DIRECT_BAUD */ -static FileState *	TtyInit(int fd, int initialize); +static int		TtyGetBaud(speed_t speed); +static speed_t		TtyGetSpeed(int baud); +static void		TtyInit(int fd);  static void		TtyModemStatusStr(int status, Tcl_DString *dsPtr);  static int		TtyParseMode(Tcl_Interp *interp, const char *mode, -			    int *speedPtr, int *parityPtr, int *dataPtr, -			    int *stopPtr); +			    TtyAttrs *ttyPtr);  static void		TtySetAttributes(int fd, TtyAttrs *ttyPtr);  static int		TtySetOptionProc(ClientData instanceData,  			    Tcl_Interp *interp, const char *optionName,  			    const char *value);  #endif	/* SUPPORTS_TTY */ -static int		WaitForConnect(TcpState *statePtr, int *errorCodePtr); -static Tcl_Channel	MakeTcpClientChannelMode(ClientData tcpSocket, -			    int mode);  /*   * This structure describes the channel type structure for file based IO:   */ -static Tcl_ChannelType fileChannelType = { +static const Tcl_ChannelType fileChannelType = {      "file",			/* Type name. */      TCL_CHANNEL_VERSION_5,	/* v5 channel */      FileCloseProc,		/* Close proc. */ @@ -272,7 +150,7 @@ static Tcl_ChannelType fileChannelType = {      NULL,			/* handler proc. */      FileWideSeekProc,		/* wide seek proc. */      NULL, -    FileTruncateProc,		/* truncate proc. */ +    FileTruncateProc		/* truncate proc. */  };  #ifdef SUPPORTS_TTY @@ -281,7 +159,7 @@ static Tcl_ChannelType fileChannelType = {   * Note that this type is a subclass of the "file" type.   */ -static Tcl_ChannelType ttyChannelType = { +static const Tcl_ChannelType ttyChannelType = {      "tty",			/* Type name. */      TCL_CHANNEL_VERSION_5,	/* v5 channel */      FileCloseProc,		/* Close proc. */ @@ -298,34 +176,9 @@ static Tcl_ChannelType ttyChannelType = {      NULL,			/* handler proc. */      NULL,			/* wide seek proc. */      NULL,			/* thread action proc. */ -    NULL,			/* truncate proc. */ +    NULL			/* truncate proc. */  };  #endif	/* SUPPORTS_TTY */ - -/* - * This structure describes the channel type structure for TCP socket - * based IO: - */ - -static Tcl_ChannelType tcpChannelType = { -    "tcp",			/* Type name. */ -    TCL_CHANNEL_VERSION_5,	/* v5 channel */ -    TcpCloseProc,		/* Close proc. */ -    TcpInputProc,		/* Input proc. */ -    TcpOutputProc,		/* Output proc. */ -    NULL,			/* Seek proc. */ -    NULL,			/* Set option proc. */ -    TcpGetOptionProc,		/* Get option proc. */ -    TcpWatchProc,		/* Initialize notifier. */ -    TcpGetHandleProc,		/* Get OS handles out of channel. */ -    NULL,			/* close2proc. */ -    TcpBlockModeProc,		/* Set blocking or non-blocking mode.*/ -    NULL,			/* flush proc. */ -    NULL,			/* handler proc. */ -    NULL,			/* wide seek proc. */ -    NULL,			/* thread action proc. */ -    NULL,			/* truncate proc. */ -};  /*   *---------------------------------------------------------------------- @@ -348,11 +201,10 @@ static Tcl_ChannelType tcpChannelType = {  static int  FileBlockModeProc(      ClientData instanceData,	/* File state. */ -    int mode)			/* The mode to set. Can be one of -				 * TCL_MODE_BLOCKING or -				 * TCL_MODE_NONBLOCKING. */ +    int mode)			/* The mode to set. Can be TCL_MODE_BLOCKING +				 * or TCL_MODE_NONBLOCKING. */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      if (TclUnixSetBlockingMode(fsPtr->fd, mode) < 0) {  	return errno; @@ -387,7 +239,7 @@ FileInputProc(  				 * buffer? */      int *errorCodePtr)		/* Where to store error code. */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      int bytesRead;		/* How many bytes were actually read from the  				 * input device? */ @@ -433,7 +285,7 @@ FileOutputProc(      int toWrite,		/* How many bytes to write? */      int *errorCodePtr)		/* Where to store error code. */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      int written;      *errorCodePtr = 0; @@ -477,7 +329,7 @@ FileCloseProc(      ClientData instanceData,	/* File state. */      Tcl_Interp *interp)		/* For error reporting - unused. */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      int errorCode = 0;      Tcl_DeleteFileHandler(fsPtr->fd); @@ -492,7 +344,7 @@ FileCloseProc(  	    errorCode = errno;  	}      } -    ckfree((char *) fsPtr); +    ckfree(fsPtr);      return errorCode;  } @@ -523,7 +375,7 @@ FileSeekProc(  				 * one of SEEK_START, SEEK_SET or SEEK_END. */      int *errorCodePtr)		/* To store error code. */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      Tcl_WideInt oldLoc, newLoc;      /* @@ -584,7 +436,7 @@ FileWideSeekProc(  				 * one of SEEK_START, SEEK_CUR or SEEK_END. */      int *errorCodePtr)		/* To store error code. */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      Tcl_WideInt newLoc;      newLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) offset, mode); @@ -617,7 +469,7 @@ FileWatchProc(  				 * TCL_READABLE, TCL_WRITABLE and  				 * TCL_EXCEPTION. */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      /*       * Make sure we only register for events that are valid on this file. Note @@ -628,8 +480,7 @@ FileWatchProc(      mask &= fsPtr->validMask;      if (mask) {  	Tcl_CreateFileHandler(fsPtr->fd, mask, -		(Tcl_FileProc *) Tcl_NotifyChannel, -		(ClientData) fsPtr->channel); +		(Tcl_FileProc *) Tcl_NotifyChannel, fsPtr->channel);      } else {  	Tcl_DeleteFileHandler(fsPtr->fd);      } @@ -659,17 +510,16 @@ FileGetHandleProc(      int direction,		/* TCL_READABLE or TCL_WRITABLE */      ClientData *handlePtr)	/* Where to store the handle. */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      if (direction & fsPtr->validMask) { -	*handlePtr = (ClientData) INT2PTR(fsPtr->fd); +	*handlePtr = INT2PTR(fsPtr->fd);  	return TCL_OK;      }      return TCL_ERROR;  }  #ifdef SUPPORTS_TTY -#ifdef USE_TERMIOS  /*   *----------------------------------------------------------------------   * @@ -702,7 +552,6 @@ TtyModemStatusStr(      Tcl_DStringAppendElement(dsPtr, (status & TIOCM_CD) ? "1" : "0");  #endif /* TIOCM_CD */  } -#endif /* USE_TERMIOS */  /*   *---------------------------------------------------------------------- @@ -729,14 +578,12 @@ TtySetOptionProc(      const char *optionName,	/* Which option to set? */      const char *value)		/* New value for option. */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      unsigned int len, vlen;      TtyAttrs tty; -#ifdef USE_TERMIOS -    int flag, control, argc; +    int argc;      const char **argv; -    IOSTATE iostate; -#endif /* USE_TERMIOS */ +    struct termios iostate;      len = strlen(optionName);      vlen = strlen(value); @@ -744,9 +591,9 @@ TtySetOptionProc(      /*       * 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) { +	if (TtyParseMode(interp, value, &tty) != TCL_OK) {  	    return TCL_ERROR;  	} @@ -758,7 +605,6 @@ TtySetOptionProc(  	return TCL_OK;      } -#ifdef USE_TERMIOS      /*       * Option -handshake none|xonxoff|rtscts|dtrdsr @@ -769,34 +615,38 @@ TtySetOptionProc(  	 * Reset all handshake options. DTR and RTS are ON by default.  	 */ -	GETIOSTATE(fsPtr->fd, &iostate); +	tcgetattr(fsPtr->fd, &iostate);  	CLEAR_BITS(iostate.c_iflag, IXON | IXOFF | IXANY);  #ifdef CRTSCTS  	CLEAR_BITS(iostate.c_cflag, CRTSCTS);  #endif /* CRTSCTS */ -	if (strncasecmp(value, "NONE", vlen) == 0) { -	    /* leave all handshake options disabled */ -	} else if (strncasecmp(value, "XONXOFF", vlen) == 0) { +	if (Tcl_UtfNcasecmp(value, "NONE", vlen) == 0) { +	    /* +	     * Leave all handshake options disabled. +	     */ +	} else if (Tcl_UtfNcasecmp(value, "XONXOFF", vlen) == 0) {  	    SET_BITS(iostate.c_iflag, IXON | IXOFF | IXANY); -	} else if (strncasecmp(value, "RTSCTS", vlen) == 0) { +	} else if (Tcl_UtfNcasecmp(value, "RTSCTS", vlen) == 0) {  #ifdef CRTSCTS  	    SET_BITS(iostate.c_cflag, CRTSCTS);  #else /* !CRTSTS */  	    UNSUPPORTED_OPTION("-handshake RTSCTS");  	    return TCL_ERROR;  #endif /* CRTSCTS */ -	} else if (strncasecmp(value, "DTRDSR", vlen) == 0) { +	} else if (Tcl_UtfNcasecmp(value, "DTRDSR", vlen) == 0) {  	    UNSUPPORTED_OPTION("-handshake DTRDSR");  	    return TCL_ERROR;  	} else {  	    if (interp) { -		Tcl_AppendResult(interp, "bad value for -handshake: " -			"must be one of xonxoff, rtscts, dtrdsr or none", -			NULL); +		Tcl_SetObjResult(interp, Tcl_NewStringObj( +			"bad value for -handshake: must be one of" +			" xonxoff, rtscts, dtrdsr or none", -1)); +		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", +			"VALUE", NULL);  	    }  	    return TCL_ERROR;  	} -	SETIOSTATE(fsPtr->fd, &iostate); +	tcsetattr(fsPtr->fd, TCSADRAIN, &iostate);  	return TCL_OK;      } @@ -805,31 +655,34 @@ TtySetOptionProc(       */      if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) { -	GETIOSTATE(fsPtr->fd, &iostate); +	Tcl_DString ds; +  	if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {  	    return TCL_ERROR; -	} -	if (argc == 2) { -	    Tcl_DString ds; -	    Tcl_DStringInit(&ds); - -	    Tcl_UtfToExternalDString(NULL, argv[0], -1, &ds); -	    iostate.c_cc[VSTART] = *(const cc_t *) Tcl_DStringValue(&ds); -	    Tcl_DStringSetLength(&ds, 0); - -	    Tcl_UtfToExternalDString(NULL, argv[1], -1, &ds); -	    iostate.c_cc[VSTOP] = *(const cc_t *) Tcl_DStringValue(&ds); -	    Tcl_DStringFree(&ds); -	} else { +	} else if (argc != 2) {  	    if (interp) { -		Tcl_AppendResult(interp, "bad value for -xchar: " -			"should be a list of two elements", NULL); +		Tcl_SetObjResult(interp, Tcl_NewStringObj( +			"bad value for -xchar: should be a list of" +			" two elements", -1)); +		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", +			"VALUE", NULL);  	    } -	    ckfree((char *) argv); +	    ckfree(argv);  	    return TCL_ERROR;  	} -	SETIOSTATE(fsPtr->fd, &iostate); -	ckfree((char *) argv); + +	tcgetattr(fsPtr->fd, &iostate); + +	Tcl_UtfToExternalDString(NULL, argv[0], -1, &ds); +	iostate.c_cc[VSTART] = *(const cc_t *) Tcl_DStringValue(&ds); +	TclDStringClear(&ds); + +	Tcl_UtfToExternalDString(NULL, argv[1], -1, &ds); +	iostate.c_cc[VSTOP] = *(const cc_t *) Tcl_DStringValue(&ds); +	Tcl_DStringFree(&ds); +	ckfree(argv); + +	tcsetattr(fsPtr->fd, TCSADRAIN, &iostate);  	return TCL_OK;      } @@ -840,95 +693,91 @@ TtySetOptionProc(      if ((len > 2) && (strncmp(optionName, "-timeout", len) == 0)) {  	int msec; -	GETIOSTATE(fsPtr->fd, &iostate); +	tcgetattr(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); +	tcsetattr(fsPtr->fd, TCSADRAIN, &iostate);  	return TCL_OK;      }      /*       * Option -ttycontrol {DTR 1 RTS 0 BREAK 0}       */ -      if ((len > 4) && (strncmp(optionName, "-ttycontrol", len) == 0)) { -	int i; +#if defined(TIOCMGET) && defined(TIOCMSET) +	int i, control, flag;  	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", NULL); +		Tcl_SetObjResult(interp, Tcl_NewStringObj( +			"bad value for -ttycontrol: should be a list of" +			" signal,value pairs", -1)); +		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", +			"VALUE", NULL);  	    } -	    ckfree((char *) argv); +	    ckfree(argv);  	    return TCL_ERROR;  	} -	GETCONTROL(fsPtr->fd, &control); +	ioctl(fsPtr->fd, TIOCMGET, &control);  	for (i = 0; i < argc-1; i += 2) {  	    if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) { -		ckfree((char *) argv); +		ckfree(argv);  		return TCL_ERROR;  	    } -	    if (strncasecmp(argv[i], "DTR", strlen(argv[i])) == 0) { -#ifdef TIOCM_DTR +	    if (Tcl_UtfNcasecmp(argv[i], "DTR", strlen(argv[i])) == 0) {  		if (flag) {  		    SET_BITS(control, TIOCM_DTR);  		} else {  		    CLEAR_BITS(control, TIOCM_DTR);  		} -#else /* !TIOCM_DTR */ -		UNSUPPORTED_OPTION("-ttycontrol DTR"); -		ckfree((char *) argv); -		return TCL_ERROR; -#endif /* TIOCM_DTR */ -	    } else if (strncasecmp(argv[i], "RTS", strlen(argv[i])) == 0) { -#ifdef TIOCM_RTS +	    } else if (Tcl_UtfNcasecmp(argv[i], "RTS", strlen(argv[i])) == 0) {  		if (flag) {  		    SET_BITS(control, TIOCM_RTS);  		} else {  		    CLEAR_BITS(control, TIOCM_RTS);  		} -#else /* !TIOCM_RTS*/ -		UNSUPPORTED_OPTION("-ttycontrol RTS"); -		ckfree((char *) argv); -		return TCL_ERROR; -#endif /* TIOCM_RTS*/ -	    } else if (strncasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) { -#ifdef SETBREAK -		SETBREAK(fsPtr->fd, flag); -#else /* !SETBREAK */ +	    } else if (Tcl_UtfNcasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) { +#if defined(TIOCSBRK) && defined(TIOCCBRK) +		if (flag) { +		    ioctl(fsPtr->fd, TIOCSBRK, NULL); +		} else { +		    ioctl(fsPtr->fd, TIOCCBRK, NULL); +		} +#else /* TIOCSBRK & TIOCCBRK */  		UNSUPPORTED_OPTION("-ttycontrol BREAK"); -		ckfree((char *) argv); +		ckfree(argv);  		return TCL_ERROR; -#endif /* SETBREAK */ +#endif /* TIOCSBRK & TIOCCBRK */  	    } else {  		if (interp) { -		    Tcl_AppendResult(interp, "bad signal \"", argv[i], -			    "\" for -ttycontrol: must be " -			    "DTR, RTS or BREAK", NULL); +		    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +			    "bad signal \"%s\" for -ttycontrol: must be" +			    " DTR, RTS or BREAK", argv[i])); +		    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", +			"VALUE", NULL);  		} -		ckfree((char *) argv); +		ckfree(argv);  		return TCL_ERROR;  	    }  	} /* -ttycontrol options loop */ -	SETCONTROL(fsPtr->fd, &control); -	ckfree((char *) argv); +	ioctl(fsPtr->fd, TIOCMSET, &control); +	ckfree(argv);  	return TCL_OK; +#else /* TIOCMGET&TIOCMSET */ +	UNSUPPORTED_OPTION("-ttycontrol"); +#endif /* TIOCMGET&TIOCMSET */      }      return Tcl_BadChannelOption(interp, optionName,  	    "mode handshake timeout ttycontrol xchar"); - -#else /* !USE_TERMIOS */ -    return Tcl_BadChannelOption(interp, optionName, "mode"); -#endif /* USE_TERMIOS */  }  /* @@ -943,12 +792,8 @@ TtySetOptionProc(   *   * Results:   *	A standard Tcl result. Also sets the supplied DString to the string - *	value of the option(s) returned. - * - * Side effects: - *	The string returned by this function is in static storage and may be - *	reused at any time subsequent to the call. Sets error message if - *	needed (by calling Tcl_BadChannelOption). + *	value of the option(s) returned.  Sets error message if needed  + *	(by calling Tcl_BadChannelOption).   *   *----------------------------------------------------------------------   */ @@ -960,7 +805,7 @@ TtyGetOptionProc(      const char *optionName,	/* Option to get. */      Tcl_DString *dsPtr)		/* Where to store value(s). */  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      unsigned int len;      char buf[3*TCL_INTEGER_SPACE + 16];      int valid = 0;		/* Flag if valid option parsed. */ @@ -982,7 +827,6 @@ TtyGetOptionProc(  	Tcl_DStringAppendElement(dsPtr, buf);      } -#ifdef USE_TERMIOS      /*       * Get option -xchar       */ @@ -992,19 +836,19 @@ TtyGetOptionProc(  	Tcl_DStringStartSublist(dsPtr);      }      if (len==0 || (len>1 && strncmp(optionName, "-xchar", len)==0)) { -	IOSTATE iostate; +	struct termios iostate;  	Tcl_DString ds; -	valid = 1; -	GETIOSTATE(fsPtr->fd, &iostate); +	valid = 1; +	tcgetattr(fsPtr->fd, &iostate);  	Tcl_DStringInit(&ds); -	Tcl_ExternalToUtfDString(NULL,  (const char *) &iostate.c_cc[VSTART], 1, &ds); -	Tcl_DStringAppendElement(dsPtr, (const char *) Tcl_DStringValue(&ds)); -	Tcl_DStringSetLength(&ds, 0); +	Tcl_ExternalToUtfDString(NULL, (char *) &iostate.c_cc[VSTART], 1, &ds); +	Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); +	TclDStringClear(&ds); -	Tcl_ExternalToUtfDString(NULL,  (const char *) &iostate.c_cc[VSTOP], 1, &ds); -	Tcl_DStringAppendElement(dsPtr, (const char *) Tcl_DStringValue(&ds)); +	Tcl_ExternalToUtfDString(NULL, (char *) &iostate.c_cc[VSTOP], 1, &ds); +	Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds));  	Tcl_DStringFree(&ds);      }      if (len == 0) { @@ -1021,12 +865,8 @@ TtyGetOptionProc(  	int inQueue=0, outQueue=0, inBuffered, outBuffered;  	valid = 1; -#ifdef GETREADQUEUE  	GETREADQUEUE(fsPtr->fd, inQueue); -#endif /* GETREADQUEUE */ -#ifdef GETWRITEQUEUE  	GETWRITEQUEUE(fsPtr->fd, outQueue); -#endif /* GETWRITEQUEUE */  	inBuffered = Tcl_InputBuffered(fsPtr->channel);  	outBuffered = Tcl_OutputBuffered(fsPtr->channel); @@ -1036,6 +876,7 @@ TtyGetOptionProc(  	Tcl_DStringAppendElement(dsPtr, buf);      } +#if defined(TIOCMGET)      /*       * Get option -ttystatus       * Option is readonly and returned by [fconfigure chan -ttystatus] but not @@ -1045,27 +886,21 @@ TtyGetOptionProc(  	int status;  	valid = 1; -	GETCONTROL(fsPtr->fd, &status); +	ioctl(fsPtr->fd, TIOCMGET, &status);  	TtyModemStatusStr(status, dsPtr);      } -#endif /* USE_TERMIOS */ +#endif /* TIOCMGET */      if (valid) {  	return TCL_OK;      }      return Tcl_BadChannelOption(interp, optionName, "mode" -#ifdef USE_TERMIOS  	    " queue ttystatus xchar" -#endif /* USE_TERMIOS */  	    );  } -#ifdef DIRECT_BAUD -#   define TtyGetSpeed(baud)	((unsigned) (baud)) -#   define TtyGetBaud(speed)	((int) (speed)) -#else /* !DIRECT_BAUD */ -static struct {int baud; unsigned long speed;} speeds[] = { +static const struct {int baud; speed_t speed;} speeds[] = {  #ifdef B0      {0, B0},  #endif @@ -1161,20 +996,16 @@ static struct {int baud; unsigned long speed;} speeds[] = {   *   * TtyGetSpeed --   * - *	Given a baud rate, get the mask value that should be stored in the - *	termios, termio, or sgttyb structure in order to select that baud - *	rate. + *	Given an integer baud rate, get the speed_t value that should be + *	used to select that baud rate.   *   * Results:   *	As above.   * - * Side effects: - *	None. - *   *---------------------------------------------------------------------------   */ -static unsigned long +static speed_t  TtyGetSpeed(      int baud)			/* The baud rate to look up. */  { @@ -1207,21 +1038,17 @@ TtyGetSpeed(   *   * TtyGetBaud --   * - *	Given a speed mask value from a termios, termio, or sgttyb structure, - *	get the baus rate that corresponds to that mask value. + *	Return the integer baud rate corresponding to a given speed_t value.   *   * Results:   *	As above. If the mask value was not recognized, 0 is returned.   * - * Side effects: - *	None. - *   *---------------------------------------------------------------------------   */  static int  TtyGetBaud( -    unsigned long speed)	/* Speed mask value to look up. */ +    speed_t speed)		/* Speed mask value to look up. */  {      int i; @@ -1232,7 +1059,6 @@ TtyGetBaud(      }      return 0;  } -#endif /* !DIRECT_BAUD */  /*   *--------------------------------------------------------------------------- @@ -1257,12 +1083,11 @@ TtyGetAttributes(      TtyAttrs *ttyPtr)		/* Buffer filled with serial port  				 * attributes. */  { -    IOSTATE iostate; +    struct termios iostate;      int baud, parity, data, stop; -    GETIOSTATE(fd, &iostate); +    tcgetattr(fd, &iostate); -#ifdef USE_TERMIOS      baud = TtyGetBaud(cfgetospeed(&iostate));      parity = 'n'; @@ -1278,45 +1103,12 @@ TtyGetAttributes(      case PARENB		 : parity = 'e'; break;      case PARENB | PARODD : parity = 'o'; break;      } -#endif /* !PAREXT */ - -    data = iostate.c_cflag & CSIZE; -    data = (data == CS5) ? 5 : (data == CS6) ? 6 : (data == CS7) ? 7 : 8; - -    stop = (iostate.c_cflag & CSTOPB) ? 2 : 1; -#endif /* USE_TERMIOS */ - -#ifdef USE_TERMIO -    baud = TtyGetBaud(iostate.c_cflag & CBAUD); - -    parity = 'n'; -    switch (iostate.c_cflag & (PARENB | PARODD | PAREXT)) { -    case PARENB			  : parity = 'e'; break; -    case PARENB | PARODD	  : parity = 'o'; break; -    case PARENB |	   PAREXT : parity = 's'; break; -    case PARENB | PARODD | PAREXT : parity = 'm'; break; -    } +#endif /* PAREXT */      data = iostate.c_cflag & CSIZE;      data = (data == CS5) ? 5 : (data == CS6) ? 6 : (data == CS7) ? 7 : 8;      stop = (iostate.c_cflag & CSTOPB) ? 2 : 1; -#endif /* USE_TERMIO */ - -#ifdef USE_SGTTY -    baud = TtyGetBaud(iostate.sg_ospeed); - -    parity = 'n'; -    if (iostate.sg_flags & EVENP) { -	parity = 'e'; -    } else if (iostate.sg_flags & ODDP) { -	parity = 'o'; -    } - -    data = (iostate.sg_flags & (EVENP | ODDP)) ? 7 : 8; - -    stop = 1; -#endif /* USE_SGTTY */      ttyPtr->baud    = baud;      ttyPtr->parity  = parity; @@ -1347,12 +1139,10 @@ TtySetAttributes(      TtyAttrs *ttyPtr)		/* Buffer containing new attributes for serial  				 * port. */  { -    IOSTATE iostate; - -#ifdef USE_TERMIOS +    struct termios iostate;      int parity, data, flag; -    GETIOSTATE(fd, &iostate); +    tcgetattr(fd, &iostate);      cfsetospeed(&iostate, TtyGetSpeed(ttyPtr->baud));      cfsetispeed(&iostate, TtyGetSpeed(ttyPtr->baud)); @@ -1382,58 +1172,7 @@ TtySetAttributes(      CLEAR_BITS(iostate.c_cflag, PARENB | PARODD | CSIZE | CSTOPB);      SET_BITS(iostate.c_cflag, flag); -#endif	/* USE_TERMIOS */ - -#ifdef USE_TERMIO -    int parity, data, flag; - -    GETIOSTATE(fd, &iostate); -    CLEAR_BITS(iostate.c_cflag, CBAUD); -    SET_BITS(iostate.c_cflag, TtyGetSpeed(ttyPtr->baud)); - -    flag = 0; -    parity = ttyPtr->parity; -    if (parity != 'n') { -	SET_BITS(flag, PARENB); -	if ((parity == 'm') || (parity == 's')) { -	    SET_BITS(flag, PAREXT); -	} -	if ((parity == 'm') || (parity == 'o')) { -	    SET_BITS(flag, PARODD); -	} -    } -    data = ttyPtr->data; -    SET_BITS(flag, -	    (data == 5) ? CS5 : -	    (data == 6) ? CS6 : -	    (data == 7) ? CS7 : CS8); -    if (ttyPtr->stop == 2) { -	SET_BITS(flag, CSTOPB); -    } - -    CLEAR_BITS(iostate.c_cflag, PARENB | PARODD | PAREXT | CSIZE | CSTOPB); -    SET_BITS(iostate.c_cflag, flag); - -#endif	/* USE_TERMIO */ - -#ifdef USE_SGTTY -    int parity; - -    GETIOSTATE(fd, &iostate); -    iostate.sg_ospeed = TtyGetSpeed(ttyPtr->baud); -    iostate.sg_ispeed = TtyGetSpeed(ttyPtr->baud); - -    parity = ttyPtr->parity; -    if (parity == 'e') { -	CLEAR_BITS(iostate.sg_flags, ODDP); -	SET_BITS(iostate.sg_flags, EVENP); -    } else if (parity == 'o') { -	CLEAR_BITS(iostate.sg_flags, EVENP); -	SET_BITS(iostate.sg_flags, ODDP); -    } -#endif	/* USE_SGTTY */ - -    SETIOSTATE(fd, &iostate); +    tcsetattr(fd, TCSADRAIN, &iostate);  }  /* @@ -1449,9 +1188,6 @@ TtySetAttributes(   *	TCL_ERROR otherwise. If TCL_ERROR is returned, an error message is   *	left in the interp's result (if interp is non-NULL).   * - * Side effects: - *	None. - *   *---------------------------------------------------------------------------   */ @@ -1459,21 +1195,22 @@ static int  TtyParseMode(      Tcl_Interp *interp,		/* If non-NULL, interp for error return. */      const char *mode,		/* Mode string to be parsed. */ -    int *speedPtr,		/* Filled with baud rate from mode string. */ -    int *parityPtr,		/* Filled with parity from mode string. */ -    int *dataPtr,		/* Filled with data bits from mode string. */ -    int *stopPtr)		/* Filled with stop bits from mode string. */ +    TtyAttrs *ttyPtr)		/* Filled with data from mode string */  {      int i, end;      char parity; -    static const char *bad = "bad value for -mode"; +    const char *bad = "bad value for -mode"; -    i = sscanf(mode, "%d,%c,%d,%d%n", speedPtr, &parity, dataPtr, -	    stopPtr, &end); +    i = sscanf(mode, "%d,%c,%d,%d%n",  +	    &ttyPtr->baud, +	    &parity, +	    &ttyPtr->data, +	    &ttyPtr->stop, &end);      if ((i != 4) || (mode[end] != '\0')) {  	if (interp != NULL) { -	    Tcl_AppendResult(interp, bad, ": should be baud,parity,data,stop", -		    NULL); +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		    "%s: should be baud,parity,data,stop", bad)); +	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);  	}  	return TCL_ERROR;      } @@ -1481,35 +1218,46 @@ TtyParseMode(      /*       * Only allow setting mark/space parity on platforms that support it Make       * sure to allow for the case where strchr is a macro. [Bug: 5089] +     * +     * We cannot if/else/endif the strchr arguments, it has to be the whole +     * function. On AIX this function is apparently a macro, and macros do +     * not allow pre-processor directives in their arguments.       */ -#if defined(PAREXT) || defined(USE_TERMIO) -    if (strchr("noems", parity) == NULL) { +    if ( +#if defined(PAREXT) +        strchr("noems", parity)  #else -    if (strchr("noe", parity) == NULL) { -#endif /* PAREXT|USE_TERMIO */ +        strchr("noe", parity) +#endif /* PAREXT */ +                               == NULL) {  	if (interp != NULL) { -	    Tcl_AppendResult(interp, bad, " parity: should be ", -#if defined(PAREXT) || defined(USE_TERMIO) -		    "n, o, e, m, or s", +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		    "%s parity: should be %s", bad, +#if defined(PAREXT) +		    "n, o, e, m, or s"  #else -		    "n, o, or e", -#endif /* PAREXT|USE_TERMIO */ -		    NULL); +		    "n, o, or e" +#endif /* PAREXT */ +		    )); +	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);  	}  	return TCL_ERROR;      } -    *parityPtr = parity; -    if ((*dataPtr < 5) || (*dataPtr > 8)) { +    ttyPtr->parity = parity; +    if ((ttyPtr->data < 5) || (ttyPtr->data > 8)) {  	if (interp != NULL) { -	    Tcl_AppendResult(interp, bad, " data: should be 5, 6, 7, or 8", -		    NULL); +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		    "%s data: should be 5, 6, 7, or 8", bad)); +	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);  	}  	return TCL_ERROR;      } -    if ((*stopPtr < 0) || (*stopPtr > 2)) { +    if ((ttyPtr->stop < 0) || (ttyPtr->stop > 2)) {  	if (interp != NULL) { -	    Tcl_AppendResult(interp, bad, " stop: should be 1 or 2", NULL); +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		    "%s stop: should be 1 or 2", bad)); +	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);  	}  	return TCL_ERROR;      } @@ -1523,72 +1271,38 @@ TtyParseMode(   *   *	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: - *	A pointer to a FileState suitable for use with Tcl_CreateChannel and - *	the ttyChannelType structure. + *	located on the serial port.   *   * Side effects:   *	Serial device initialized to non-blocking raw mode, similar to sockets - *	(if initialize flag is non-zero.) All other modes can be simulated on - *	top of this in Tcl. + *	All other modes can be simulated on top of this in Tcl.   *   *---------------------------------------------------------------------------   */ -static FileState * +static void  TtyInit( -    int fd,			/* Open file descriptor for serial port to be -				 * initialized. */ -    int initialize) +    int fd)	/* Open file descriptor for serial port to be initialized. */  { -    TtyState *ttyPtr; -    int stateUpdated = 0; - -    ttyPtr = (TtyState *) ckalloc((unsigned) sizeof(TtyState)); -    GETIOSTATE(fd, &ttyPtr->savedState); -    if (initialize) { -	IOSTATE iostate = ttyPtr->savedState; - -#if defined(USE_TERMIOS) || defined(USE_TERMIO) -	if (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) { -	    stateUpdated = 1; -	} +    struct termios iostate; +    tcgetattr(fd, &iostate); + +    if (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; -	SET_BITS(iostate.c_cflag, CREAD); +	iostate.c_cflag |= CREAD;  	iostate.c_cc[VMIN] = 1;  	iostate.c_cc[VTIME] = 0; -#endif	/* USE_TERMIOS|USE_TERMIO */ -#ifdef USE_SGTTY -	if ((iostate.sg_flags & (EVENP | ODDP)) || -		!(iostate.sg_flags & RAW)) { -	    ttyPtr->stateUpdated = 1; -	} -	iostate.sg_flags &= EVENP | ODDP; -	SET_BITS(iostate.sg_flags, RAW); -#endif	/* USE_SGTTY */ - -	/* -	 * Only update if we're changing anything to avoid possible blocking. -	 */ - -	if (stateUpdated) { -	    SETIOSTATE(fd, &iostate); -	} +	tcsetattr(fd, TCSADRAIN, &iostate);      } - -    return &ttyPtr->fs;  }  #endif	/* SUPPORTS_TTY */ @@ -1624,7 +1338,7 @@ TclpOpenFileChannel(      FileState *fsPtr;      const char *native, *translation;      char channelName[16 + TCL_INTEGER_SPACE]; -    Tcl_ChannelType *channelTypePtr; +    const Tcl_ChannelType *channelTypePtr;      switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {      case O_RDONLY: @@ -1658,8 +1372,9 @@ TclpOpenFileChannel(      if (fd < 0) {  	if (interp != NULL) { -	    Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr), -		    "\": ", Tcl_PosixError(interp), NULL); +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		    "couldn't open \"%s\": %s", +		    TclGetString(pathPtr), Tcl_PosixError(interp)));  	}  	return NULL;      } @@ -1691,20 +1406,20 @@ TclpOpenFileChannel(  	translation = "auto crlf";  	channelTypePtr = &ttyChannelType; -	fsPtr = TtyInit(fd, 1); +	TtyInit(fd);      } else  #endif	/* SUPPORTS_TTY */      {  	translation = NULL;  	channelTypePtr = &fileChannelType; -	fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));      } +    fsPtr = ckalloc(sizeof(FileState));      fsPtr->validMask = channelPermissions | TCL_EXCEPTION;      fsPtr->fd = fd;      fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, -	    (ClientData) fsPtr, channelPermissions); +	    fsPtr, channelPermissions);      if (translation != NULL) {  	/* @@ -1750,7 +1465,7 @@ Tcl_MakeFileChannel(      FileState *fsPtr;      char channelName[16 + TCL_INTEGER_SPACE];      int fd = PTR2INT(handle); -    Tcl_ChannelType *channelTypePtr; +    const Tcl_ChannelType *channelTypePtr;      struct sockaddr sockaddr;      socklen_t sockaddrLen = sizeof(sockaddr); @@ -1762,25 +1477,24 @@ Tcl_MakeFileChannel(  #ifdef SUPPORTS_TTY      if (isatty(fd)) { -	fsPtr = TtyInit(fd, 0);  	channelTypePtr = &ttyChannelType;  	sprintf(channelName, "serial%d", fd);      } else  #endif /* SUPPORTS_TTY */ -    if (getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0 -	    && sockaddrLen > 0 -	    && sockaddr.sa_family == AF_INET) { -	return MakeTcpClientChannelMode((ClientData) INT2PTR(fd), mode); +    if ((getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0) +	&& (sockaddrLen > 0) +	&& (sockaddr.sa_family == AF_INET || sockaddr.sa_family == AF_INET6)) { +	return TclpMakeTcpClientChannelMode(INT2PTR(fd), mode);      } else {  	channelTypePtr = &fileChannelType; -	fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));  	sprintf(channelName, "file%d", fd);      } +    fsPtr = ckalloc(sizeof(FileState));      fsPtr->fd = fd;      fsPtr->validMask = mode | TCL_EXCEPTION;      fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, -	    (ClientData) fsPtr, mode); +	    fsPtr, mode);      return fsPtr->channel;  } @@ -1788,1025 +1502,6 @@ Tcl_MakeFileChannel(  /*   *----------------------------------------------------------------------   * - * TcpBlockModeProc -- - * - *	This function is invoked by the generic IO level to set blocking and - *	nonblocking mode on a TCP socket based channel. - * - * Results: - *	0 if successful, errno when failed. - * - * Side effects: - *	Sets the device into blocking or nonblocking mode. - * - *---------------------------------------------------------------------- - */ - -	/* ARGSUSED */ -static int -TcpBlockModeProc( -    ClientData instanceData,	/* Socket state. */ -    int mode)			/* The mode to set. Can be one of -				 * TCL_MODE_BLOCKING or -				 * TCL_MODE_NONBLOCKING. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; - -    if (mode == TCL_MODE_BLOCKING) { -	CLEAR_BITS(statePtr->flags, TCP_ASYNC_SOCKET); -    } else { -	SET_BITS(statePtr->flags, TCP_ASYNC_SOCKET); -    } -    if (TclUnixSetBlockingMode(statePtr->fd, mode) < 0) { -	return errno; -    } -    return 0; -} - -/* - *---------------------------------------------------------------------- - * - * WaitForConnect -- - * - *	Waits for a connection on an asynchronously opened socket to be - *	completed. - * - * Results: - *	None. - * - * Side effects: - *	The socket is connected after this function returns. - * - *---------------------------------------------------------------------- - */ - -static int -WaitForConnect( -    TcpState *statePtr,		/* State of the socket. */ -    int *errorCodePtr)		/* Where to store errors? */ -{ -    int timeOut;		/* How long to wait. */ -    int state;			/* Of calling TclWaitForFile. */ - -    /* -     * If an asynchronous connect is in progress, attempt to wait for it to -     * complete before reading. -     */ - -    if (statePtr->flags & TCP_ASYNC_CONNECT) { -	if (statePtr->flags & TCP_ASYNC_SOCKET) { -	    timeOut = 0; -	} else { -	    timeOut = -1; -	} -	errno = 0; -	state = TclUnixWaitForFile(statePtr->fd, -		TCL_WRITABLE | TCL_EXCEPTION, timeOut); -	if (!(statePtr->flags & TCP_ASYNC_SOCKET)) { -	    (void) TclUnixSetBlockingMode(statePtr->fd, TCL_MODE_BLOCKING); -	} -	if (state & TCL_EXCEPTION) { -	    return -1; -	} -	if (state & TCL_WRITABLE) { -	    CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT); -	} else if (timeOut == 0) { -	    *errorCodePtr = errno = EWOULDBLOCK; -	    return -1; -	} -    } -    return 0; -} - -/* - *---------------------------------------------------------------------- - * - * TcpInputProc -- - * - *	This function is invoked by the generic IO level to read input from a - *	TCP socket based channel. - * - *	NOTE: We cannot share code with FilePipeInputProc because here we must - *	use recv to obtain the input from the channel, not read. - * - * Results: - *	The number of bytes read is returned or -1 on error. An output - *	argument contains the POSIX error code on error, or zero if no error - *	occurred. - * - * Side effects: - *	Reads input from the input device of the channel. - * - *---------------------------------------------------------------------- - */ - -	/* ARGSUSED */ -static int -TcpInputProc( -    ClientData instanceData,	/* Socket state. */ -    char *buf,			/* Where to store data read. */ -    int bufSize,		/* How much space is available in the -				 * buffer? */ -    int *errorCodePtr)		/* Where to store error code. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; -    int bytesRead, state; - -    *errorCodePtr = 0; -    state = WaitForConnect(statePtr, errorCodePtr); -    if (state != 0) { -	return -1; -    } -    bytesRead = recv(statePtr->fd, buf, (size_t) bufSize, 0); -    if (bytesRead > -1) { -	return bytesRead; -    } -    if (errno == ECONNRESET) { -	/* -	 * Turn ECONNRESET into a soft EOF condition. -	 */ - -	return 0; -    } -    *errorCodePtr = errno; -    return -1; -} - -/* - *---------------------------------------------------------------------- - * - * TcpOutputProc -- - * - *	This function is invoked by the generic IO level to write output to a - *	TCP socket based channel. - * - *	NOTE: We cannot share code with FilePipeOutputProc because here we - *	must use send, not write, to get reliable error reporting. - * - * Results: - *	The number of bytes written is returned. An output argument is set to - *	a POSIX error code if an error occurred, or zero. - * - * Side effects: - *	Writes output on the output device of the channel. - * - *---------------------------------------------------------------------- - */ - -static int -TcpOutputProc( -    ClientData instanceData,	/* Socket state. */ -    const char *buf,		/* The data buffer. */ -    int toWrite,		/* How many bytes to write? */ -    int *errorCodePtr)		/* Where to store error code. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; -    int written; -    int state;				/* Of waiting for connection. */ - -    *errorCodePtr = 0; -    state = WaitForConnect(statePtr, errorCodePtr); -    if (state != 0) { -	return -1; -    } -    written = send(statePtr->fd, buf, (size_t) toWrite, 0); -    if (written > -1) { -	return written; -    } -    *errorCodePtr = errno; -    return -1; -} - -/* - *---------------------------------------------------------------------- - * - * TcpCloseProc -- - * - *	This function is invoked by the generic IO level to perform - *	channel-type-specific cleanup when a TCP socket based channel is - *	closed. - * - * Results: - *	0 if successful, the value of errno if failed. - * - * Side effects: - *	Closes the socket of the channel. - * - *---------------------------------------------------------------------- - */ - -	/* ARGSUSED */ -static int -TcpCloseProc( -    ClientData instanceData,	/* The socket to close. */ -    Tcl_Interp *interp)		/* For error reporting - unused. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; -    int errorCode = 0; - -    /* -     * Delete a file handler that may be active for this socket if this is a -     * server socket - the file handler was created automatically by Tcl as -     * part of the mechanism to accept new client connections. Channel -     * handlers are already deleted in the generic IO channel closing code -     * that called this function, so we do not have to delete them here. -     */ - -    Tcl_DeleteFileHandler(statePtr->fd); - -    if (close(statePtr->fd) < 0) { -	errorCode = errno; -    } -    ckfree((char *) statePtr); - -    return errorCode; -} - -/* - *---------------------------------------------------------------------- - * - * TcpGetOptionProc -- - * - *	Computes an option value for a TCP socket based channel, or a list of - *	all options and their values. - * - *	Note: This code is based on code contributed by John Haxby. - * - * Results: - *	A standard Tcl result. The value of the specified option or a list of - *	all options and their values is returned in the supplied DString. Sets - *	Error message if needed. - * - * Side effects: - *	None. - * - *---------------------------------------------------------------------- - */ - -static int -TcpGetOptionProc( -    ClientData instanceData,	/* Socket state. */ -    Tcl_Interp *interp,		/* For error reporting - can be NULL. */ -    const char *optionName,	/* Name of the option to retrieve the value -				 * for, or NULL to get all options and their -				 * values. */ -    Tcl_DString *dsPtr)		/* Where to store the computed value; -				 * initialized by caller. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; -    struct sockaddr_in sockname; -    struct sockaddr_in peername; -    struct hostent *hostEntPtr; -    socklen_t size = sizeof(struct sockaddr_in); -    size_t len = 0; -    char buf[TCL_INTEGER_SPACE]; - -    if (optionName != NULL) { -	len = strlen(optionName); -    } - -    if ((len > 1) && (optionName[1] == 'e') && -	    (strncmp(optionName, "-error", len) == 0)) { -	socklen_t optlen = sizeof(int); -	int err, ret; - -	ret = getsockopt(statePtr->fd, SOL_SOCKET, SO_ERROR, -		(char *)&err, &optlen); -	if (ret < 0) { -	    err = errno; -	} -	if (err != 0) { -	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1); -	} -	return TCL_OK; -    } - -    if ((len == 0) || -	    ((len > 1) && (optionName[1] == 'p') && -		    (strncmp(optionName, "-peername", len) == 0))) { -	if (getpeername(statePtr->fd, (struct sockaddr *) &peername, -		&size) >= 0) { -	    if (len == 0) { -		Tcl_DStringAppendElement(dsPtr, "-peername"); -		Tcl_DStringStartSublist(dsPtr); -	    } -	    Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); -	    hostEntPtr = TclpGetHostByAddr(			/* INTL: Native. */ -		    (char *) &peername.sin_addr, -		    sizeof(peername.sin_addr), AF_INET); -	    if (hostEntPtr != NULL) { -		Tcl_DString ds; - -		Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds); -		Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); -		Tcl_DStringFree(&ds); -	    } else { -		Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); -	    } -	    TclFormatInt(buf, ntohs(peername.sin_port)); -	    Tcl_DStringAppendElement(dsPtr, buf); -	    if (len == 0) { -		Tcl_DStringEndSublist(dsPtr); -	    } else { -		return TCL_OK; -	    } -	} else { -	    /* -	     * getpeername failed - but if we were asked for all the options -	     * (len==0), don't flag an error at that point because it could be -	     * an fconfigure request on a server socket (which have no peer). -	     * Same must be done on win&mac. -	     */ - -	    if (len) { -		if (interp) { -		    Tcl_AppendResult(interp, "can't get peername: ", -			    Tcl_PosixError(interp), NULL); -		} -		return TCL_ERROR; -	    } -	} -    } - -    if ((len == 0) || -	    ((len > 1) && (optionName[1] == 's') && -	    (strncmp(optionName, "-sockname", len) == 0))) { -	if (getsockname(statePtr->fd, (struct sockaddr *) &sockname, -		&size) >= 0) { -	    if (len == 0) { -		Tcl_DStringAppendElement(dsPtr, "-sockname"); -		Tcl_DStringStartSublist(dsPtr); -	    } -	    Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); -	    hostEntPtr = TclpGetHostByAddr(			/* INTL: Native. */ -		    (char *) &sockname.sin_addr, -		    sizeof(sockname.sin_addr), AF_INET); -	    if (hostEntPtr != NULL) { -		Tcl_DString ds; - -		Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds); -		Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); -		Tcl_DStringFree(&ds); -	    } else { -		Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); -	    } -	    TclFormatInt(buf, ntohs(sockname.sin_port)); -	    Tcl_DStringAppendElement(dsPtr, buf); -	    if (len == 0) { -		Tcl_DStringEndSublist(dsPtr); -	    } else { -		return TCL_OK; -	    } -	} else { -	    if (interp) { -		Tcl_AppendResult(interp, "can't get sockname: ", -			Tcl_PosixError(interp), NULL); -	    } -	    return TCL_ERROR; -	} -    } - -    if (len > 0) { -	return Tcl_BadChannelOption(interp, optionName, "peername sockname"); -    } - -    return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TcpWatchProc -- - * - *	Initialize the notifier to watch the fd from this channel. - * - * Results: - *	None. - * - * Side effects: - *	Sets up the notifier so that a future event on the channel will be - *	seen by Tcl. - * - *---------------------------------------------------------------------- - */ - -static void -TcpWatchProc( -    ClientData instanceData,	/* The socket state. */ -    int mask)			/* Events of interest; an OR-ed combination of -				 * TCL_READABLE, TCL_WRITABLE and -				 * TCL_EXCEPTION. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; - -    /* -     * Make sure we don't mess with server sockets since they will never be -     * readable or writable at the Tcl level. This keeps Tcl scripts from -     * interfering with the -accept behavior. -     */ - -    if (!statePtr->acceptProc) { -	if (mask) { -	    Tcl_CreateFileHandler(statePtr->fd, mask, -		    (Tcl_FileProc *) Tcl_NotifyChannel, -		    (ClientData) statePtr->channel); -	} else { -	    Tcl_DeleteFileHandler(statePtr->fd); -	} -    } -} - -/* - *---------------------------------------------------------------------- - * - * TcpGetHandleProc -- - * - *	Called from Tcl_GetChannelHandle to retrieve OS handles from inside a - *	TCP socket based channel. - * - * Results: - *	Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no - *	handle for the specified direction. - * - * Side effects: - *	None. - * - *---------------------------------------------------------------------- - */ - -	/* ARGSUSED */ -static int -TcpGetHandleProc( -    ClientData instanceData,	/* The socket state. */ -    int direction,		/* Not used. */ -    ClientData *handlePtr)	/* Where to store the handle. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; - -    *handlePtr = (ClientData) INT2PTR(statePtr->fd); -    return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * CreateSocket -- - * - *	This function opens a new socket in client or server mode and - *	initializes the TcpState structure. - * - * Results: - *	Returns a new TcpState, or NULL with an error in the interp's result, - *	if interp is not NULL. - * - * Side effects: - *	Opens a socket. - * - *---------------------------------------------------------------------- - */ - -static TcpState * -CreateSocket( -    Tcl_Interp *interp,		/* For error reporting; can be NULL. */ -    int port,			/* Port number to open. */ -    const char *host,		/* Name of host on which to open port. NULL -				 * implies INADDR_ANY */ -    int server,			/* 1 if socket should be a server socket, else -				 * 0 for a client socket. */ -    const char *myaddr,		/* Optional client-side address */ -    int myport,			/* Optional client-side port */ -    int async)			/* If nonzero and creating a client socket, -				 * attempt to do an async connect. Otherwise -				 * do a synchronous connect or bind. */ -{ -    int status, sock, asyncConnect, curState, origState; -    struct sockaddr_in sockaddr;	/* socket address */ -    struct sockaddr_in mysockaddr;	/* Socket address for client */ -    TcpState *statePtr; -    const char *errorMsg = NULL; - -    sock = -1; -    origState = 0; -    if (!CreateSocketAddress(&sockaddr, host, port, 0, &errorMsg)) { -	goto addressError; -    } -    if ((myaddr != NULL || myport != 0) && -	    !CreateSocketAddress(&mysockaddr, myaddr, myport, 1, &errorMsg)) { -	goto addressError; -    } - -    sock = socket(AF_INET, SOCK_STREAM, 0); -    if (sock < 0) { -	goto addressError; -    } - -    /* -     * Set the close-on-exec flag so that the socket will not get inherited by -     * child processes. -     */ - -    fcntl(sock, F_SETFD, FD_CLOEXEC); - -    /* -     * Set kernel space buffering -     */ - -    TclSockMinimumBuffers(sock, SOCKET_BUFSIZE); - -    asyncConnect = 0; -    status = 0; -    if (server) { -	/* -	 * Set up to reuse server addresses automatically and bind to the -	 * specified port. -	 */ - -	status = 1; -	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &status, -		sizeof(status)); -	status = bind(sock, (struct sockaddr *) &sockaddr, -		sizeof(struct sockaddr)); -	if (status != -1) { -	    status = listen(sock, SOMAXCONN); -	} -    } else { -	if (myaddr != NULL || myport != 0) { -	    curState = 1; -	    (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, -		    (char *) &curState, sizeof(curState)); -	    status = bind(sock, (struct sockaddr *) &mysockaddr, -		    sizeof(struct sockaddr)); -	    if (status < 0) { -		goto bindError; -	    } -	} - -	/* -	 * Attempt to connect. The connect may fail at present with an -	 * EINPROGRESS but at a later time it will complete. The caller will -	 * set up a file handler on the socket if she is interested in being -	 * informed when the connect completes. -	 */ - -	if (async) { -	    status = TclUnixSetBlockingMode(sock, TCL_MODE_NONBLOCKING); -	} else { -	    status = 0; -	} -	if (status > -1) { -	    status = connect(sock, (struct sockaddr *) &sockaddr, -		    sizeof(sockaddr)); -	    if (status < 0) { -		if (errno == EINPROGRESS) { -		    asyncConnect = 1; -		    status = 0; -		} -	    } else { -		/* -		 * Here we are if the connect succeeds. In case of an -		 * asynchronous connect we have to reset the channel to -		 * blocking mode. This appears to happen not very often, but -		 * e.g. on a HP 9000/800 under HP-UX B.11.00 we enter this -		 * stage. [Bug: 4388] -		 */ - -		if (async) { -		    status = TclUnixSetBlockingMode(sock, TCL_MODE_BLOCKING); -		} -	    } -	} -    } - -  bindError: -    if (status < 0) { -	if (interp != NULL) { -	    Tcl_AppendResult(interp, "couldn't open socket: ", -		    Tcl_PosixError(interp), NULL); -	} -	if (sock != -1) { -	    close(sock); -	} -	return NULL; -    } - -    /* -     * Allocate a new TcpState for this socket. -     */ - -    statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); -    statePtr->flags = 0; -    if (asyncConnect) { -	statePtr->flags = TCP_ASYNC_CONNECT; -    } -    statePtr->fd = sock; - -    return statePtr; - -  addressError: -    if (sock != -1) { -	close(sock); -    } -    if (interp != NULL) { -	Tcl_AppendResult(interp, "couldn't open socket: ", -		Tcl_PosixError(interp), NULL); -	if (errorMsg != NULL) { -	    Tcl_AppendResult(interp, " (", errorMsg, ")", NULL); -	} -    } -    return NULL; -} - -/* - *---------------------------------------------------------------------- - * - * CreateSocketAddress -- - * - *	This function initializes a sockaddr structure for a host and port. - * - * Results: - *	1 if the host was valid, 0 if the host could not be converted to an IP - *	address. - * - * Side effects: - *	Fills in the *sockaddrPtr structure. - * - *---------------------------------------------------------------------- - */ - -static int -CreateSocketAddress( -    struct sockaddr_in *sockaddrPtr,	/* Socket address */ -    const char *host,			/* Host. NULL implies INADDR_ANY */ -    int port,				/* Port number */ -    int willBind,			/* Is this an address to bind() to or -					 * to connect() to? */ -    const char **errorMsgPtr)		/* Place to store the error message -					 * detail, if available. */ -{ -#ifdef HAVE_GETADDRINFO -    struct addrinfo hints, *resPtr = NULL; -    char *native; -    Tcl_DString ds; -    int result; - -    if (host == NULL) { -	sockaddrPtr->sin_family = AF_INET; -	sockaddrPtr->sin_addr.s_addr = INADDR_ANY; -    addPort: -	sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); -	return 1; -    } - -    (void) memset(&hints, 0, sizeof(struct addrinfo)); -    hints.ai_family = AF_INET; -    hints.ai_socktype = SOCK_STREAM; -    if (willBind) { -	hints.ai_flags |= AI_PASSIVE; -    } - -    /* -     * Note that getaddrinfo() *is* thread-safe. If a platform doesn't get -     * that right, it shouldn't use this part of the code. -     */ - -    native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); -    result = getaddrinfo(native, NULL, &hints, &resPtr); -    Tcl_DStringFree(&ds); -    if (result == 0) { -	memcpy(sockaddrPtr, resPtr->ai_addr, sizeof(struct sockaddr_in)); -	freeaddrinfo(resPtr); -	goto addPort; -    } - -    /* -     * Ought to use gai_strerror() here... -     */ - -    switch (result) { -    case EAI_NONAME: -    case EAI_SERVICE: -#if defined(EAI_ADDRFAMILY) && EAI_ADDRFAMILY != EAI_NONAME -    case EAI_ADDRFAMILY: -#endif -#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME -    case EAI_NODATA: -#endif -	*errorMsgPtr = gai_strerror(result); -	errno = EHOSTUNREACH; -	return 0; -    case EAI_SYSTEM: -	return 0; -    default: -	*errorMsgPtr = gai_strerror(result); -	errno = ENXIO; -	return 0; -    } -#else /* !HAVE_GETADDRINFO */ -    struct in_addr addr;		/* For 64/32 bit madness */ - -    (void) memset(sockaddrPtr, '\0', sizeof(struct sockaddr_in)); -    sockaddrPtr->sin_family = AF_INET; -    sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); -    if (host == NULL) { -	addr.s_addr = INADDR_ANY; -    } else { -	struct hostent *hostent;	/* Host database entry */ -	Tcl_DString ds; -	const char *native; - -	if (host == NULL) { -	    native = NULL; -	} else { -	    native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); -	} -	addr.s_addr = inet_addr(native);		/* INTL: Native. */ - -	/* -	 * This is 0xFFFFFFFF to ensure that it compares as a 32bit -1 on -	 * either 32 or 64 bits systems. -	 */ - -	if (addr.s_addr == 0xFFFFFFFF) { -	    hostent = TclpGetHostByName(native);	/* INTL: Native. */ -	    if (hostent != NULL) { -		memcpy(&addr, hostent->h_addr_list[0], -			(size_t) hostent->h_length); -	    } else { -#ifdef	EHOSTUNREACH -		errno = EHOSTUNREACH; -#else /* !EHOSTUNREACH */ -#ifdef ENXIO -		errno = ENXIO; -#endif /* ENXIO */ -#endif /* EHOSTUNREACH */ -		if (native != NULL) { -		    Tcl_DStringFree(&ds); -		} -		return 0;	/* Error. */ -	    } -	} -	if (native != NULL) { -	    Tcl_DStringFree(&ds); -	} -    } - -    /* -     * NOTE: On 64 bit machines the assignment below is rumored to not do the -     * right thing. Please report errors related to this if you observe -     * incorrect behavior on 64 bit machines such as DEC Alphas. Should we -     * modify this code to do an explicit memcpy? -     */ - -    sockaddrPtr->sin_addr.s_addr = addr.s_addr; -    return 1;			/* Success. */ -#endif /* HAVE_GETADDRINFO */ -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_OpenTcpClient -- - * - *	Opens a TCP client socket and creates a channel around it. - * - * Results: - *	The channel or NULL if failed. An error message is returned in the - *	interpreter on failure. - * - * Side effects: - *	Opens a client socket and creates a new channel. - * - *---------------------------------------------------------------------- - */ - -Tcl_Channel -Tcl_OpenTcpClient( -    Tcl_Interp *interp,		/* For error reporting; can be NULL. */ -    int port,			/* Port number to open. */ -    const char *host,		/* Host on which to open port. */ -    const char *myaddr,		/* Client-side address */ -    int myport,			/* Client-side port */ -    int async)			/* If nonzero, attempt to do an asynchronous -				 * connect. Otherwise we do a blocking -				 * connect. */ -{ -    TcpState *statePtr; -    char channelName[16 + TCL_INTEGER_SPACE]; - -    /* -     * Create a new client socket and wrap it in a channel. -     */ - -    statePtr = CreateSocket(interp, port, host, 0, myaddr, myport, async); -    if (statePtr == NULL) { -	return NULL; -    } - -    statePtr->acceptProc = NULL; -    statePtr->acceptProcData = NULL; - -    sprintf(channelName, "sock%d", statePtr->fd); - -    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, -	    (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE)); -    if (Tcl_SetChannelOption(interp, statePtr->channel, "-translation", -	    "auto crlf") == TCL_ERROR) { -	Tcl_Close(NULL, statePtr->channel); -	return NULL; -    } -    return statePtr->channel; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_MakeTcpClientChannel -- - * - *	Creates a Tcl_Channel from an existing client TCP socket. - * - * Results: - *	The Tcl_Channel wrapped around the preexisting TCP socket. - * - * Side effects: - *	None. - * - *---------------------------------------------------------------------- - */ - -Tcl_Channel -Tcl_MakeTcpClientChannel( -    ClientData sock)		/* The socket to wrap up into a channel. */ -{ -    return MakeTcpClientChannelMode(sock, (TCL_READABLE | TCL_WRITABLE)); -} - -/* - *---------------------------------------------------------------------- - * - * MakeTcpClientChannelMode -- - * - *	Creates a Tcl_Channel from an existing client TCP socket - *	with given mode. - * - * Results: - *	The Tcl_Channel wrapped around the preexisting TCP socket. - * - * Side effects: - *	None. - * - *---------------------------------------------------------------------- - */ - -static Tcl_Channel -MakeTcpClientChannelMode( -    ClientData sock,		/* The socket to wrap up into a channel. */ -    int mode)			/* ORed combination of TCL_READABLE and -				 * TCL_WRITABLE to indicate file mode. */ -{ -    TcpState *statePtr; -    char channelName[16 + TCL_INTEGER_SPACE]; - -    statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); -    statePtr->fd = PTR2INT(sock); -    statePtr->flags = 0; -    statePtr->acceptProc = NULL; -    statePtr->acceptProcData = NULL; - -    sprintf(channelName, "sock%d", statePtr->fd); - -    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, -	    (ClientData) statePtr, mode); -    if (Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", -	    "auto crlf") == TCL_ERROR) { -	Tcl_Close(NULL, statePtr->channel); -	return NULL; -    } -    return statePtr->channel; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_OpenTcpServer -- - * - *	Opens a TCP server socket and creates a channel around it. - * - * Results: - *	The channel or NULL if failed. If an error occurred, an error message - *	is left in the interp's result if interp is not NULL. - * - * Side effects: - *	Opens a server socket and creates a new channel. - * - *---------------------------------------------------------------------- - */ - -Tcl_Channel -Tcl_OpenTcpServer( -    Tcl_Interp *interp,		/* For error reporting - may be NULL. */ -    int port,			/* Port number to open. */ -    const char *myHost,		/* Name of local host. */ -    Tcl_TcpAcceptProc *acceptProc, -				/* Callback for accepting connections from new -				 * clients. */ -    ClientData acceptProcData)	/* Data for the callback. */ -{ -    TcpState *statePtr; -    char channelName[16 + TCL_INTEGER_SPACE]; - -    /* -     * Create a new client socket and wrap it in a channel. -     */ - -    statePtr = CreateSocket(interp, port, myHost, 1, NULL, 0, 0); -    if (statePtr == NULL) { -	return NULL; -    } - -    statePtr->acceptProc = acceptProc; -    statePtr->acceptProcData = acceptProcData; - -    /* -     * Set up the callback mechanism for accepting connections from new -     * clients. -     */ - -    Tcl_CreateFileHandler(statePtr->fd, TCL_READABLE, TcpAccept, -	    (ClientData) statePtr); -    sprintf(channelName, "sock%d", statePtr->fd); -    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, -	    (ClientData) statePtr, 0); -    return statePtr->channel; -} - -/* - *---------------------------------------------------------------------- - * - * TcpAccept -- - *	Accept a TCP socket connection.	 This is called by the event loop. - * - * Results: - *	None. - * - * Side effects: - *	Creates a new connection socket. Calls the registered callback for the - *	connection acceptance mechanism. - * - *---------------------------------------------------------------------- - */ - -	/* ARGSUSED */ -static void -TcpAccept( -    ClientData data,		/* Callback token. */ -    int mask)			/* Not used. */ -{ -    TcpState *sockState;	/* Client data of server socket. */ -    int newsock;		/* The new client socket */ -    TcpState *newSockState;	/* State for new socket. */ -    struct sockaddr_in addr;	/* The remote address */ -    socklen_t len;		/* For accept interface */ -    char channelName[16 + TCL_INTEGER_SPACE]; - -    sockState = (TcpState *) data; - -    len = sizeof(struct sockaddr_in); -    newsock = accept(sockState->fd, (struct sockaddr *) &addr, &len); -    if (newsock < 0) { -	return; -    } - -    /* -     * Set close-on-exec flag to prevent the newly accepted socket from being -     * inherited by child processes. -     */ - -    (void) fcntl(newsock, F_SETFD, FD_CLOEXEC); - -    newSockState = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); - -    newSockState->flags = 0; -    newSockState->fd = newsock; -    newSockState->acceptProc = NULL; -    newSockState->acceptProcData = NULL; - -    sprintf(channelName, "sock%d", newsock); -    newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName, -	    (ClientData) newSockState, (TCL_READABLE | TCL_WRITABLE)); - -    Tcl_SetChannelOption(NULL, newSockState->channel, "-translation", -	    "auto crlf"); - -    if (sockState->acceptProc != NULL) { -	(*sockState->acceptProc)(sockState->acceptProcData, -		newSockState->channel, inet_ntoa(addr.sin_addr), -		ntohs(addr.sin_port)); -    } -} - -/* - *---------------------------------------------------------------------- - *   * TclpGetDefaultStdChannel --   *   *	Creates channels for standard input, standard output or standard error @@ -2828,7 +1523,7 @@ TclpGetDefaultStdChannel(      Tcl_Channel channel = NULL;      int fd = 0;			/* Initializations needed to prevent */      int mode = 0;		/* compiler warning (used before set). */ -    char *bufMode = NULL; +    const char *bufMode = NULL;      /*       * Some #def's to make the code a little clearer! @@ -2873,7 +1568,7 @@ TclpGetDefaultStdChannel(  #undef ZERO_OFFSET  #undef ERROR_OFFSET -    channel = Tcl_MakeFileChannel((ClientData) INT2PTR(fd), mode); +    channel = Tcl_MakeFileChannel(INT2PTR(fd), mode);      if (channel == NULL) {  	return NULL;      } @@ -2933,15 +1628,19 @@ Tcl_GetOpenFile(      FILE *f;      chan = Tcl_GetChannel(interp, chanID, &chanMode); -    if (chan == (Tcl_Channel) NULL) { +    if (chan == NULL) {  	return TCL_ERROR;      } -    if ((forWriting) && ((chanMode & TCL_WRITABLE) == 0)) { -	Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for writing", +    if (forWriting && !(chanMode & TCL_WRITABLE)) { +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		"\"%s\" wasn't opened for writing", chanID)); +	Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "NOT_WRITABLE",  		NULL);  	return TCL_ERROR; -    } else if ((!forWriting) && ((chanMode & TCL_READABLE) == 0)) { -	Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for reading", +    } else if (!forWriting && !(chanMode & TCL_READABLE)) { +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		"\"%s\" wasn't opened for reading", chanID)); +	Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "NOT_READABLE",  		NULL);  	return TCL_ERROR;      } @@ -2957,11 +1656,10 @@ Tcl_GetOpenFile(  #ifdef SUPPORTS_TTY  	    || (chanTypePtr == &ttyChannelType)  #endif /* SUPPORTS_TTY */ -	    || (chanTypePtr == &tcpChannelType) +	    || (strcmp(chanTypePtr->typeName, "tcp") == 0)  	    || (strcmp(chanTypePtr->typeName, "pipe") == 0)) {  	if (Tcl_GetChannelHandle(chan, -		(forWriting ? TCL_WRITABLE : TCL_READABLE), -		(ClientData*) &data) == TCL_OK) { +		(forWriting ? TCL_WRITABLE : TCL_READABLE), &data) == TCL_OK) {  	    fd = PTR2INT(data);  	    /* @@ -2972,20 +1670,26 @@ Tcl_GetOpenFile(  	    f = fdopen(fd, (forWriting ? "w" : "r"));  	    if (f == NULL) { -		Tcl_AppendResult(interp, "cannot get a FILE * for \"", chanID, -			"\"", NULL); +		Tcl_SetObjResult(interp, Tcl_ObjPrintf( +			"cannot get a FILE * for \"%s\"", chanID)); +		Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", +			"FILE_FAILURE", NULL);  		return TCL_ERROR;  	    } -	    *filePtr = (ClientData) f; +	    *filePtr = f;  	    return TCL_OK;  	}      } -    Tcl_AppendResult(interp, "\"", chanID, -	    "\" cannot be used to get a FILE *", NULL); +    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +	    "\"%s\" cannot be used to get a FILE *", chanID)); +    Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "NO_DESCRIPTOR", +	    NULL);      return TCL_ERROR;  } +#ifndef HAVE_COREFOUNDATION	/* Darwin/Mac OS X CoreFoundation notifier is +				 * in tclMacOSXNotify.c */  /*   *----------------------------------------------------------------------   * @@ -3023,12 +1727,21 @@ TclUnixWaitForFile(  {      Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */      struct timeval blockTime, *timeoutPtr; -    int index, numFound, result = 0; -    fd_mask bit; -    fd_mask readyMasks[3*MASK_SIZE]; -    fd_mask *maskp[3];		/* This array reflects the readable/writable -				 * conditions that were found to exist by the -				 * last call to select. */ +    int numFound, result = 0; +    fd_set readableMask; +    fd_set writableMask; +    fd_set exceptionMask; + +#ifndef _DARWIN_C_SOURCE +    /* +     * Sanity check fd. +     */ + +    if (fd >= FD_SETSIZE) { +	Tcl_Panic("TclUnixWaitForFile can't handle file id %d", fd); +	/* must never get here, or select masks overrun will occur below */ +    } +#endif      /*       * If there is a non-zero finite timeout, compute the time when we give @@ -3053,16 +1766,12 @@ TclUnixWaitForFile(      }      /* -     * Initialize the ready masks and compute the mask offsets. +     * Initialize the select masks.       */ -    if (fd >= FD_SETSIZE) { -	Tcl_Panic("TclWaitForFile can't handle file id %d", fd); -	/* must never get here, or readyMasks overrun will occur below */ -    } -    memset(readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask)); -    index = fd / (NBBY*sizeof(fd_mask)); -    bit = ((fd_mask)1) << (fd % (NBBY*sizeof(fd_mask))); +    FD_ZERO(&readableMask); +    FD_ZERO(&writableMask); +    FD_ZERO(&exceptionMask);      /*       * Loop in a mini-event loop of our own, waiting for either the file to @@ -3084,41 +1793,33 @@ TclUnixWaitForFile(  	}  	/* -	 * Set the appropriate bit in the ready masks for the fd. +	 * Setup the select masks for the fd.  	 */  	if (mask & TCL_READABLE) { -	    readyMasks[index] |= bit; +	    FD_SET(fd, &readableMask);  	}  	if (mask & TCL_WRITABLE) { -	    (readyMasks+MASK_SIZE)[index] |= bit; +	    FD_SET(fd, &writableMask);  	}  	if (mask & TCL_EXCEPTION) { -	    (readyMasks+2*(MASK_SIZE))[index] |= bit; +	    FD_SET(fd, &exceptionMask);  	}  	/*  	 * Wait for the event or a timeout.  	 */ -	/* -	 * This is needed to satisfy GCC 3.3's strict aliasing rules. -	 */ - -	maskp[0] = &readyMasks[0]; -	maskp[1] = &readyMasks[MASK_SIZE]; -	maskp[2] = &readyMasks[2*MASK_SIZE]; -	numFound = select(fd+1, (SELECT_MASK *) maskp[0], -		(SELECT_MASK *) maskp[1], -		(SELECT_MASK *) maskp[2], timeoutPtr); +	numFound = select(fd + 1, &readableMask, &writableMask, +		&exceptionMask, timeoutPtr);  	if (numFound == 1) { -	    if (readyMasks[index] & bit) { +	    if (FD_ISSET(fd, &readableMask)) {  		SET_BITS(result, TCL_READABLE);  	    } -	    if ((readyMasks+MASK_SIZE)[index] & bit) { +	    if (FD_ISSET(fd, &writableMask)) {  		SET_BITS(result, TCL_WRITABLE);  	    } -	    if ((readyMasks+2*(MASK_SIZE))[index] & bit) { +	    if (FD_ISSET(fd, &exceptionMask)) {   		SET_BITS(result, TCL_EXCEPTION);  	    }  	    result &= mask; @@ -3145,6 +1846,7 @@ TclUnixWaitForFile(      }      return result;  } +#endif /* HAVE_COREFOUNDATION */  /*   *---------------------------------------------------------------------- @@ -3170,7 +1872,7 @@ FileTruncateProc(      ClientData instanceData,      Tcl_WideInt length)  { -    FileState *fsPtr = (FileState *) instanceData; +    FileState *fsPtr = instanceData;      int result;  #ifdef HAVE_TYPE_OFF64_T | 
