diff options
author | stanton <stanton> | 1999-04-16 00:46:29 (GMT) |
---|---|---|
committer | stanton <stanton> | 1999-04-16 00:46:29 (GMT) |
commit | 97464e6cba8eb0008cf2727c15718671992b913f (patch) | |
tree | ce9959f2747257d98d52ec8d18bf3b0de99b9535 /unix/tclUnixChan.c | |
parent | a8c96ddb94d1483a9de5e340b740cb74ef6cafa7 (diff) | |
download | tcl-97464e6cba8eb0008cf2727c15718671992b913f.zip tcl-97464e6cba8eb0008cf2727c15718671992b913f.tar.gz tcl-97464e6cba8eb0008cf2727c15718671992b913f.tar.bz2 |
merged tcl 8.1 branch back into the main trunk
Diffstat (limited to 'unix/tclUnixChan.c')
-rw-r--r-- | unix/tclUnixChan.c | 558 |
1 files changed, 330 insertions, 228 deletions
diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index 2759a41..4da4f1f 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -5,11 +5,12 @@ * pipes and TCP sockets. * * 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.9 1999/02/03 00:51:20 stanton Exp $ + * RCS: @(#) $Id: tclUnixChan.c,v 1.10 1999/04/16 00:48:04 stanton Exp $ */ #include "tclInt.h" /* Internal definitions for Tcl. */ @@ -40,31 +41,32 @@ #undef FLUSHO #undef PENDIN +#define SUPPORTS_TTY + #ifdef USE_TERMIOS # include <termios.h> +# define IOSTATE struct termios +# define GETIOSTATE(fd, statePtr) tcgetattr((fd), (statePtr)) +# define SETIOSTATE(fd, statePtr) tcsetattr((fd), TCSADRAIN, (statePtr)) #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> -#endif /* USE_SGTTY */ +# 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 */ /* - * The following structure is used to set or get the serial port - * attributes in a platform-independant manner. - */ - -typedef struct TtyAttrs { - int baud; - int parity; - int data; - int stop; -} TtyAttrs; - -/* * This structure describes per-instance state of a file based channel. */ @@ -78,11 +80,44 @@ typedef struct FileState { * file channels. */ } FileState; +#ifdef SUPPORTS_TTY + /* - * List of all file channels currently open. + * The following structure describes per-instance state of a tty-based + * channel. */ -static FileState *firstFilePtr = NULL; +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. + */ + +typedef struct TtyAttrs { + int baud; + int parity; + int data; + int stop; +} TtyAttrs; + +#endif /* !SUPPORTS_TTY */ + +typedef struct ThreadSpecificData { + /* + * List of all file channels currently open. This is per thread and is + * used to match up fd's to channels, which rarely occurs. + */ + + FileState *firstFilePtr; +} ThreadSpecificData; + +static Tcl_ThreadDataKey dataKey; /* * This structure describes per-instance state of a tcp based channel. @@ -170,20 +205,24 @@ static int TcpOutputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toWrite, int *errorCode)); static void TcpWatchProc _ANSI_ARGS_((ClientData instanceData, int mask)); -static int TtyParseMode _ANSI_ARGS_((Tcl_Interp *interp, - CONST char *mode, int *speedPtr, int *parityPtr, - int *dataPtr, int *stopPtr)); +#ifdef SUPPORTS_TTY +static int TtyCloseProc _ANSI_ARGS_((ClientData instanceData, + Tcl_Interp *interp)); static void TtyGetAttributes _ANSI_ARGS_((int fd, TtyAttrs *ttyPtr)); static int TtyGetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, char *optionName, Tcl_DString *dsPtr)); -static void TtyInit _ANSI_ARGS_((int fd)); +static FileState * TtyInit _ANSI_ARGS_((int fd)); +static int TtyParseMode _ANSI_ARGS_((Tcl_Interp *interp, + CONST char *mode, int *speedPtr, int *parityPtr, + int *dataPtr, int *stopPtr)); static void TtySetAttributes _ANSI_ARGS_((int fd, TtyAttrs *ttyPtr)); static int TtySetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, char *optionName, char *value)); +#endif /* SUPPORTS_TTY */ static int WaitForConnect _ANSI_ARGS_((TcpState *statePtr, int *errorCodePtr)); @@ -204,6 +243,7 @@ static Tcl_ChannelType fileChannelType = { FileGetHandleProc, /* Get OS handles out of channel. */ }; +#ifdef SUPPORTS_TTY /* * This structure describes the channel type structure for serial IO. * Note that this type is a subclass of the "file" type. @@ -212,7 +252,7 @@ static Tcl_ChannelType fileChannelType = { static Tcl_ChannelType ttyChannelType = { "tty", /* Type name. */ FileBlockModeProc, /* Set blocking/nonblocking mode.*/ - FileCloseProc, /* Close proc. */ + TtyCloseProc, /* Close proc. */ FileInputProc, /* Input proc. */ FileOutputProc, /* Output proc. */ NULL, /* Seek proc. */ @@ -221,6 +261,7 @@ static Tcl_ChannelType ttyChannelType = { FileWatchProc, /* Initialize notifier. */ FileGetHandleProc, /* Get OS handles out of channel. */ }; +#endif /* SUPPORTS_TTY */ /* * This structure describes the channel type structure for TCP socket @@ -403,15 +444,21 @@ FileCloseProc(instanceData, interp) FileState *fsPtr = (FileState *) instanceData; FileState **nextPtrPtr; int errorCode = 0; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Tcl_DeleteFileHandler(fsPtr->fd); + + /* + * Do not close standard channels while in thread-exit. + */ + if (!TclInExit() || ((fsPtr->fd != 0) && (fsPtr->fd != 1) && (fsPtr->fd != 2))) { if (close(fsPtr->fd) < 0) { errorCode = errno; } } - for (nextPtrPtr = &firstFilePtr; (*nextPtrPtr) != NULL; + for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL; nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { if ((*nextPtrPtr) == fsPtr) { (*nextPtrPtr) = fsPtr->nextPtr; @@ -508,7 +555,7 @@ FileWatchProc(instanceData, mask) * * FileGetHandleProc -- * - * Called from Tcl_GetChannelFile to retrieve OS handles from + * Called from Tcl_GetChannelHandle to retrieve OS handles from * a file based channel. * * Results: @@ -536,6 +583,37 @@ FileGetHandleProc(instanceData, direction, handlePtr) return TCL_ERROR; } } + +#ifdef SUPPORTS_TTY + +/* + *---------------------------------------------------------------------- + * + * TtyCloseProc -- + * + * This procedure is called from the generic IO level to perform + * channel-type-specific cleanup when a tty based channel is closed. + * + * Results: + * 0 if successful, errno if failed. + * + * Side effects: + * Restores the settings and closes the device of the channel. + * + *---------------------------------------------------------------------- + */ + +static int +TtyCloseProc(instanceData, interp) + ClientData instanceData; /* Tty state. */ + Tcl_Interp *interp; /* For error reporting - unused. */ +{ + TtyState *ttyPtr; + + ttyPtr = (TtyState *) instanceData; + SETIOSTATE(ttyPtr->fs.fd, &ttyPtr->savedState); + return FileCloseProc(instanceData, interp); +} /* *---------------------------------------------------------------------- @@ -545,7 +623,7 @@ FileGetHandleProc(instanceData, direction, handlePtr) * Sets an option on a channel. * * Results: - * A standard Tcl result. Also sets interp->result on error if + * A standard Tcl result. Also sets the interp's result on error if * interp is not NULL. * * Side effects: @@ -614,7 +692,7 @@ TtyGetOptionProc(instanceData, interp, optionName, dsPtr) { FileState *fsPtr = (FileState *) instanceData; unsigned int len; - char buf[32]; + char buf[3 * TCL_INTEGER_SPACE + 16]; TtyAttrs tty; if (optionName == NULL) { @@ -820,65 +898,6 @@ TtyGetBaud(speed) /* *--------------------------------------------------------------------------- * - * TtyInit -- - * - * 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. - * - * Results: - * None. - * - * Side effects: - * Serial device initialized. - * - *--------------------------------------------------------------------------- - */ - -static void -TtyInit(fd) - int fd; /* Open file descriptor for serial port to - * be initialized. */ -{ -#ifdef USE_TERMIOS - struct termios termios; - - tcgetattr(fd, &termios); - termios.c_iflag = IGNBRK; - termios.c_oflag = 0; - termios.c_lflag = 0; - termios.c_cflag |= CREAD; - termios.c_cc[VMIN] = 60; - termios.c_cc[VTIME] = 2; - tcsetattr(fd, TCSANOW, &termios); -#else /* !USE_TERMIOS */ -#ifdef USE_TERMIO - struct termio termio; - - ioctl(fd, TCGETA, &termio); - termio.c_iflag = IGNBRK; - termio.c_oflag = 0; - termio.c_lflag = 0; - termio.c_cflag |= CREAD; - termio.c_cc[VMIN] = 60; - termio.c_cc[VTIME] = 2; - ioctl(fd, TCSETAW, &termio); -#else /* !USE_TERMIO */ -#ifdef USE_SGTTY - struct sgttyb sgttyb; - - ioctl(fd, TIOCGETP, &sgttyb); - sgttyb.sg_flags &= (EVENP | ODDP); - sgttyb.sg_flags |= RAW; - ioctl(fd, TIOCSETP, &sgttyb); -#endif /* USE_SGTTY */ -#endif /* !USE_TERMIO */ -#endif /* !USE_TERMIOS */ -} - -/* - *--------------------------------------------------------------------------- - * * TtyGetAttributes -- * * Get the current attributes of the specified serial device. @@ -899,79 +918,71 @@ TtyGetAttributes(fd, ttyPtr) TtyAttrs *ttyPtr; /* Buffer filled with serial port * attributes. */ { -#ifdef USE_TERMIOS - int parity, data; - struct termios termios; + IOSTATE iostate; + int baud, parity, data, stop; - tcgetattr(fd, &termios); - ttyPtr->baud = TtyGetBaud(cfgetospeed(&termios)); + GETIOSTATE(fd, &iostate); + +#ifdef USE_TERMIOS + baud = TtyGetBaud(cfgetospeed(&iostate)); parity = 'n'; #ifdef PAREXT - switch ((int) (termios.c_cflag & (PARENB | PARODD | PAREXT))) { + switch ((int) (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; } #else /* !PAREXT */ - switch ((int) (termios.c_cflag & (PARENB | PARODD))) { + switch ((int) (iostate.c_cflag & (PARENB | PARODD))) { case PARENB : parity = 'e'; break; case PARENB | PARODD : parity = 'o'; break; } #endif /* !PAREXT */ - ttyPtr->parity = parity; - data = termios.c_cflag & CSIZE; - ttyPtr->data = (data == CS5) ? 5 : (data == CS6) ? 6 : - (data == CS7) ? 7 : 8; + 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 */ - ttyPtr->stop = (termios.c_cflag & CSTOPB) ? 2 : 1; -#else /* !USE_TERMIOS */ #ifdef USE_TERMIO - int parity, data; - struct termio termio; + baud = TtyGetBaud(iostate.c_cflag & CBAUD); - ioctl(fd, TCGETA, &termio); - ttyPtr->baud = TtyGetBaud(termio.c_cflag & CBAUD); parity = 'n'; - switch (termio.c_cflag & (PARENB | PARODD | PAREXT)) { + 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; } - ttyPtr->parity = parity; - data = termio.c_cflag & CSIZE; - ttyPtr->data = (data == CS5) ? 5 : (data == CS6) ? 6 : - (data == CS7) ? 7 : 8; + 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 */ - ttyPtr->stop = (termio.c_cflag & CSTOPB) ? 2 : 1; -#else /* !USE_TERMIO */ #ifdef USE_SGTTY - int parity; - struct sgttyb sgttyb; + baud = TtyGetBaud(iostate.sg_ospeed); - ioctl(fd, TIOCGETP, &sgttyb); - ttyPtr->baud = TtyGetBaud(sgttyb.sg_ospeed); parity = 'n'; - if (sgttyb.sg_flags & EVENP) { + if (iostate.sg_flags & EVENP) { parity = 'e'; - } else if (sgttyb.sg_flags & ODDP) { + } else if (iostate.sg_flags & ODDP) { parity = 'o'; } - ttyPtr->parity = parity; - ttyPtr->data = (sgttyb.sg_flags & (EVENP | ODDP)) ? 7 : 8; - ttyPtr->stop = 1; -#else /* !USE_SGTTY */ - ttyPtr->baud = 0; - ttyPtr->parity = 'n'; - ttyPtr->data = 0; - ttyPtr->stop = 0; -#endif /* !USE_SGTTY */ -#endif /* !USE_TERMIO */ -#endif /* !USE_TERMIOS */ + + data = (iostate.sg_flags & (EVENP | ODDP)) ? 7 : 8; + + stop = 1; +#endif /* USE_SGTTY */ + + ttyPtr->baud = baud; + ttyPtr->parity = parity; + ttyPtr->data = data; + ttyPtr->stop = stop; } /* @@ -997,20 +1008,21 @@ TtySetAttributes(fd, ttyPtr) TtyAttrs *ttyPtr; /* Buffer containing new attributes for * serial port. */ { + IOSTATE iostate; + #ifdef USE_TERMIOS int parity, data, flag; - struct termios termios; - tcgetattr(fd, &termios); - cfsetospeed(&termios, TtyGetSpeed(ttyPtr->baud)); - cfsetispeed(&termios, TtyGetSpeed(ttyPtr->baud)); + GETIOSTATE(fd, &iostate); + cfsetospeed(&iostate, TtyGetSpeed(ttyPtr->baud)); + cfsetispeed(&iostate, TtyGetSpeed(ttyPtr->baud)); flag = 0; parity = ttyPtr->parity; if (parity != 'n') { flag |= PARENB; #ifdef PAREXT - termios.c_cflag &= ~PAREXT; + iostate.c_cflag &= ~PAREXT; if ((parity == 'm') || (parity == 's')) { flag |= PAREXT; } @@ -1025,18 +1037,17 @@ TtySetAttributes(fd, ttyPtr) flag |= CSTOPB; } - termios.c_cflag &= ~(PARENB | PARODD | CSIZE | CSTOPB); - termios.c_cflag |= flag; - tcsetattr(fd, TCSANOW, &termios); + iostate.c_cflag &= ~(PARENB | PARODD | CSIZE | CSTOPB); + iostate.c_cflag |= flag; + +#endif /* USE_TERMIOS */ -#else /* !USE_TERMIOS */ #ifdef USE_TERMIO int parity, data, flag; - struct termio termio; - ioctl(fd, TCGETA, &termio); - termio.c_cflag &= ~CBAUD; - termio.c_cflag |= TtyGetSpeed(ttyPtr->baud); + GETIOSTATE(fd, &iostate); + iostate.c_cflag &= ~CBAUD; + iostate.c_cflag |= TtyGetSpeed(ttyPtr->baud); flag = 0; parity = ttyPtr->parity; @@ -1055,31 +1066,29 @@ TtySetAttributes(fd, ttyPtr) flag |= CSTOPB; } - termio.c_cflag &= ~(PARENB | PARODD | PAREXT | CSIZE | CSTOPB); - termio.c_cflag |= flag; - ioctl(fd, TCSETAW, &termio); + iostate.c_cflag &= ~(PARENB | PARODD | PAREXT | CSIZE | CSTOPB); + iostate.c_cflag |= flag; + +#endif /* USE_TERMIO */ -#else /* !USE_TERMIO */ #ifdef USE_SGTTY int parity; - struct sgttyb sgttyb; - ioctl(fd, TIOCGETP, &sgttyb); - sgttyb.sg_ospeed = TtyGetSpeed(ttyPtr->baud); - sgttyb.sg_ispeed = TtyGetSpeed(ttyPtr->baud); + GETIOSTATE(fd, &iostate); + iostate.sg_ospeed = TtyGetSpeed(ttyPtr->baud); + iostate.sg_ispeed = TtyGetSpeed(ttyPtr->baud); parity = ttyPtr->parity; if (parity == 'e') { - sgttyb.sg_flags &= ~ODDP; - sgttyb.sg_flags |= EVENP; + iostate.sg_flags &= ~ODDP; + iostate.sg_flags |= EVENP; } else if (parity == 'o') { - sgttyb.sg_flags &= ~EVENP; - sgttyb.sg_flags |= ODDP; + iostate.sg_flags &= ~EVENP; + iostate.sg_flags |= ODDP; } - ioctl(fd, TIOCSETP, &sgttyb); #endif /* USE_SGTTY */ -#endif /* !USE_TERMIO */ -#endif /* !USE_TERMIOS */ + + SETIOSTATE(fd, &iostate); } /* @@ -1093,7 +1102,7 @@ TtySetAttributes(fd, ttyPtr) * Results: * The return value is TCL_OK if the argument was successfully * parsed, TCL_ERROR otherwise. If TCL_ERROR is returned, an - * error message is left in interp->result (if interp is non-NULL). + * error message is left in the interp's result (if interp is non-NULL). * * Side effects: * None. @@ -1148,6 +1157,67 @@ TtyParseMode(interp, mode, speedPtr, parityPtr, dataPtr, stopPtr) } /* + *--------------------------------------------------------------------------- + * + * TtyInit -- + * + * 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. + * + * Results: + * None. + * + * 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. + * + *--------------------------------------------------------------------------- + */ + +static FileState * +TtyInit(fd) + int fd; /* Open file descriptor for serial port to + * be initialized. */ +{ + IOSTATE iostate; + TtyState *ttyPtr; + + ttyPtr = (TtyState *) ckalloc((unsigned) sizeof(TtyState)); + GETIOSTATE(fd, &ttyPtr->savedState); + + 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; +#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; +#endif /* USE_TERMIO */ + +#ifdef USE_SGTTY + iostate.sg_flags &= (EVENP | ODDP); + iostate.sg_flags |= RAW; +#endif /* USE_SGTTY */ + + SETIOSTATE(fd, &iostate); + + return &ttyPtr->fs; +} +#endif /* SUPPORTS_TTY */ + +/* *---------------------------------------------------------------------- * * TclpOpenFileChannel -- @@ -1157,7 +1227,7 @@ TtyParseMode(interp, mode, speedPtr, parityPtr, dataPtr, stopPtr) * Results: * The new channel or NULL. If NULL, the output argument * errorCodePtr is set to a POSIX error and an error message is - * left in interp->result if interp is not NULL. + * left in the interp's result if interp is not NULL. * * Side effects: * May open the channel and may cause creation of a file on the @@ -1179,9 +1249,11 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) { int fd, seekFlag, mode, channelPermissions; FileState *fsPtr; - char *nativeName, channelName[20]; - Tcl_DString buffer; + char *native, *translation; + char channelName[16 + TCL_INTEGER_SPACE]; + Tcl_DString ds, buffer; Tcl_ChannelType *channelTypePtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); mode = TclGetOpenMode(interp, modeString, &seekFlag); if (mode == -1) { @@ -1205,17 +1277,13 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) return NULL; } - nativeName = Tcl_TranslateFileName(interp, fileName, &buffer); - if (nativeName == NULL) { + native = Tcl_TranslateFileName(interp, fileName, &buffer); + if (native == NULL) { return NULL; } - fd = open(nativeName, mode, permissions); - - /* - * If nativeName is not NULL, the buffer is valid and we must free - * the storage. - */ - + native = Tcl_UtfToExternalDString(NULL, native, -1, &ds); + fd = open(native, mode, permissions); /* INTL: Native. */ + Tcl_DStringFree(&ds); Tcl_DStringFree(&buffer); if (fd < 0) { @@ -1235,12 +1303,7 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) sprintf(channelName, "file%d", fd); - fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); - fsPtr->nextPtr = firstFilePtr; - firstFilePtr = fsPtr; - fsPtr->validMask = channelPermissions | TCL_EXCEPTION; - fsPtr->fd = fd; - +#ifdef SUPPORTS_TTY if (isatty(fd)) { /* * Initialize the serial port to a set of sane parameters. @@ -1250,12 +1313,22 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) * then the serial driver would echo it back to the device, etc. */ - TtyInit(fd); + translation = "auto crlf"; channelTypePtr = &ttyChannelType; - } else { + fsPtr = TtyInit(fd); + } else +#endif /* SUPPORTS_TTY */ + { + translation = NULL; channelTypePtr = &fileChannelType; + fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); } + fsPtr->nextPtr = tsdPtr->firstFilePtr; + tsdPtr->firstFilePtr = fsPtr; + fsPtr->validMask = channelPermissions | TCL_EXCEPTION; + fsPtr->fd = fd; + fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, (ClientData) fsPtr, channelPermissions); @@ -1270,7 +1343,7 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) } } - if (channelTypePtr == &ttyChannelType) { + 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 @@ -1280,7 +1353,7 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) */ if (Tcl_SetChannelOption(interp, fsPtr->channel, "-translation", - "auto crlf") != TCL_OK) { + translation) != TCL_OK) { Tcl_Close(NULL, fsPtr->channel); return NULL; } @@ -1312,8 +1385,9 @@ Tcl_MakeFileChannel(handle, mode) * TCL_WRITABLE to indicate file mode. */ { FileState *fsPtr; - char channelName[20]; + char channelName[16 + TCL_INTEGER_SPACE]; int fd = (int) handle; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (mode == 0) { return NULL; @@ -1326,15 +1400,17 @@ Tcl_MakeFileChannel(handle, mode) * If the fd is used, but the mode doesn't match, return NULL. */ - for (fsPtr = firstFilePtr; fsPtr != NULL; fsPtr = fsPtr->nextPtr) { + for (fsPtr = tsdPtr->firstFilePtr; fsPtr != NULL; fsPtr = fsPtr->nextPtr) { if (fsPtr->fd == fd) { - return (mode == fsPtr->validMask) ? fsPtr->channel : NULL; + return ((mode|TCL_EXCEPTION) == fsPtr->validMask) ? + fsPtr->channel : NULL; } } fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); - fsPtr->nextPtr = firstFilePtr; - firstFilePtr = fsPtr; + fsPtr->nextPtr = tsdPtr->firstFilePtr; + tsdPtr->firstFilePtr = fsPtr; + fsPtr->fd = fd; fsPtr->validMask = mode | TCL_EXCEPTION; fsPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName, @@ -1604,7 +1680,7 @@ TcpCloseProc(instanceData, interp) * closing code that called this function, so we do not have to * delete them here. */ - + Tcl_DeleteFileHandler(statePtr->fd); if (close(statePtr->fd) < 0) { @@ -1653,47 +1729,51 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) struct hostent *hostEntPtr; int size = sizeof(struct sockaddr_in); size_t len = 0; - char buf[128]; + char buf[TCL_INTEGER_SPACE]; if (optionName != (char *) NULL) { len = strlen(optionName); } if ((len > 1) && (optionName[1] == 'e') && - (strncmp(optionName, "-error", len) == 0)) { - int optlen; - int err, ret; + (strncmp(optionName, "-error", len) == 0)) { + int optlen; + int err, ret; - optlen = sizeof(int); - 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); - } + optlen = sizeof(int); + 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 (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 = gethostbyaddr((char *) &(peername.sin_addr), - sizeof(peername.sin_addr), AF_INET); - if (hostEntPtr != (struct hostent *) NULL) { - Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); + hostEntPtr = gethostbyaddr( /* 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)); } else { Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); } - sprintf(buf, "%d", ntohs(peername.sin_port)); + TclFormatInt(buf, ntohs(peername.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); @@ -1729,14 +1809,18 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) Tcl_DStringStartSublist(dsPtr); } Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); - hostEntPtr = gethostbyaddr((char *) &(sockname.sin_addr), + hostEntPtr = gethostbyaddr( /* INTL: Native. */ + (char *) &sockname.sin_addr, sizeof(sockname.sin_addr), AF_INET); if (hostEntPtr != (struct hostent *) NULL) { - Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); + Tcl_DString ds; + + Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds); + Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); } else { Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); } - sprintf(buf, "%d", ntohs(sockname.sin_port)); + TclFormatInt(buf, ntohs(sockname.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); @@ -1808,7 +1892,7 @@ TcpWatchProc(instanceData, mask) * * TcpGetHandleProc -- * - * Called from Tcl_GetChannelFile to retrieve OS handles from inside + * Called from Tcl_GetChannelHandle to retrieve OS handles from inside * a TCP socket based channel. * * Results: @@ -1843,8 +1927,8 @@ TcpGetHandleProc(instanceData, direction, handlePtr) * and initializes the TcpState structure. * * Results: - * Returns a new TcpState, or NULL with an error in interp->result, - * if interp is not NULL. + * Returns a new TcpState, or NULL with an error in the interp's + * result, if interp is not NULL. * * Side effects: * Opens a socket. @@ -1983,7 +2067,7 @@ bindError: statePtr->flags = TCP_ASYNC_CONNECT; } statePtr->fd = sock; - + return statePtr; addressError: @@ -2029,9 +2113,17 @@ CreateSocketAddress(sockaddrPtr, host, port) if (host == NULL) { addr.s_addr = INADDR_ANY; } else { - addr.s_addr = inet_addr(host); + 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. */ if (addr.s_addr == -1) { - hostent = gethostbyname(host); + hostent = gethostbyname(native); /* INTL: Native. */ if (hostent != NULL) { memcpy((VOID *) &addr, (VOID *) hostent->h_addr_list[0], @@ -2044,9 +2136,15 @@ CreateSocketAddress(sockaddrPtr, host, port) errno = ENXIO; #endif #endif + if (native != NULL) { + Tcl_DStringFree(&ds); + } return 0; /* error */ } } + if (native != NULL) { + Tcl_DStringFree(&ds); + } } /* @@ -2089,7 +2187,7 @@ Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async) * we do a blocking connect. */ { TcpState *statePtr; - char channelName[20]; + char channelName[16 + TCL_INTEGER_SPACE]; /* * Create a new client socket and wrap it in a channel. @@ -2136,7 +2234,7 @@ Tcl_MakeTcpClientChannel(sock) ClientData sock; /* The socket to wrap up into a channel. */ { TcpState *statePtr; - char channelName[20]; + char channelName[16 + TCL_INTEGER_SPACE]; statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); statePtr->fd = (int) sock; @@ -2164,7 +2262,7 @@ Tcl_MakeTcpClientChannel(sock) * * Results: * The channel or NULL if failed. If an error occurred, an - * error message is left in interp->result if interp is + * error message is left in the interp's result if interp is * not NULL. * * Side effects: @@ -2184,7 +2282,7 @@ Tcl_OpenTcpServer(interp, port, myHost, acceptProc, acceptProcData) ClientData acceptProcData; /* Data for the callback. */ { TcpState *statePtr; - char channelName[20]; + char channelName[16 + TCL_INTEGER_SPACE]; /* * Create a new client socket and wrap it in a channel. @@ -2238,12 +2336,12 @@ TcpAccept(data, mask) TcpState *newSockState; /* State for new socket. */ struct sockaddr_in addr; /* The remote address */ int len; /* For accept interface */ - char channelName[20]; + char channelName[16 + TCL_INTEGER_SPACE]; sockState = (TcpState *) data; len = sizeof(struct sockaddr_in); - newsock = accept(sockState->fd, (struct sockaddr *)&addr, &len); + newsock = accept(sockState->fd, (struct sockaddr *) &addr, &len); if (newsock < 0) { return; } @@ -2259,18 +2357,18 @@ TcpAccept(data, mask) newSockState->flags = 0; newSockState->fd = newsock; - newSockState->acceptProc = (Tcl_TcpAcceptProc *) NULL; - newSockState->acceptProcData = (ClientData) NULL; + 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((Tcl_Interp *) NULL, newSockState->channel, - "-translation", "auto crlf"); + Tcl_SetChannelOption(NULL, newSockState->channel, "-translation", + "auto crlf"); - if (sockState->acceptProc != (Tcl_TcpAcceptProc *) NULL) { - (sockState->acceptProc) (sockState->acceptProcData, + if (sockState->acceptProc != NULL) { + (*sockState->acceptProc)(sockState->acceptProcData, newSockState->channel, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); } @@ -2279,7 +2377,7 @@ TcpAccept(data, mask) /* *---------------------------------------------------------------------- * - * TclGetDefaultStdChannel -- + * TclpGetDefaultStdChannel -- * * Creates channels for standard input, standard output or standard * error output if they do not already exist. @@ -2295,7 +2393,7 @@ TcpAccept(data, mask) */ Tcl_Channel -TclGetDefaultStdChannel(type) +TclpGetDefaultStdChannel(type) int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ { Tcl_Channel channel = NULL; @@ -2364,7 +2462,7 @@ TclGetDefaultStdChannel(type) * it is open for the requested mode, then the output parameter * filePtr is set to a FILE * for the underlying file. On error, the * filePtr is not set, TCL_ERROR is returned and an error message is - * left in interp->result. + * left in the interp's result. * * Side effects: * May invoke fdopen to create the FILE * for the requested file. @@ -2413,7 +2511,11 @@ Tcl_GetOpenFile(interp, string, forWriting, checkUsage, filePtr) */ chanTypePtr = Tcl_GetChannelType(chan); - if ((chanTypePtr == &fileChannelType) || (chanTypePtr == &tcpChannelType) + if ((chanTypePtr == &fileChannelType) +#ifdef SUPPORTS_TTY + || (chanTypePtr == &ttyChannelType) +#endif /* SUPPORTS_TTY */ + || (chanTypePtr == &tcpChannelType) || (strcmp(chanTypePtr->typeName, "pipe") == 0)) { if (Tcl_GetChannelHandle(chan, (forWriting ? TCL_WRITABLE : TCL_READABLE), @@ -2481,7 +2583,7 @@ TclUnixWaitForFile(fd, mask, timeout) Tcl_Time abortTime, now; struct timeval blockTime, *timeoutPtr; int index, bit, numFound, result = 0; - static fd_mask readyMasks[3*MASK_SIZE]; + fd_mask readyMasks[3*MASK_SIZE]; /* This array reflects the readable/writable * conditions that were found to exist by the * last call to select. */ |