diff options
Diffstat (limited to 'unix/tclUnixChan.c')
-rw-r--r-- | unix/tclUnixChan.c | 663 |
1 files changed, 238 insertions, 425 deletions
diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index d8eaccc..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.101 2009/06/15 16:24:45 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) - -/* - * Can't use ?: operator below because that messes up types on either Linux or - * Solaris (the two are mutually exclusive!) - */ +# else +# define GETWRITEQUEUE(fd, int) int = 0 +# endif -# 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,9 +86,10 @@ 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); \ } /* @@ -168,15 +117,12 @@ 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, @@ -187,7 +133,7 @@ static int TtySetOptionProc(ClientData instanceData, * 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. */ @@ -204,7 +150,7 @@ static Tcl_ChannelType fileChannelType = { NULL, /* handler proc. */ FileWideSeekProc, /* wide seek proc. */ NULL, - FileTruncateProc, /* truncate proc. */ + FileTruncateProc /* truncate proc. */ }; #ifdef SUPPORTS_TTY @@ -213,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. */ @@ -230,10 +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 */ - /* *---------------------------------------------------------------------- @@ -256,11 +201,10 @@ static Tcl_ChannelType ttyChannelType = { 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; @@ -295,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? */ @@ -341,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; @@ -385,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); @@ -400,7 +344,7 @@ FileCloseProc( errorCode = errno; } } - ckfree((char *) fsPtr); + ckfree(fsPtr); return errorCode; } @@ -431,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; /* @@ -492,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); @@ -525,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 @@ -536,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); } @@ -567,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 /* *---------------------------------------------------------------------- * @@ -610,7 +552,6 @@ TtyModemStatusStr( Tcl_DStringAppendElement(dsPtr, (status & TIOCM_CD) ? "1" : "0"); #endif /* TIOCM_CD */ } -#endif /* USE_TERMIOS */ /* *---------------------------------------------------------------------- @@ -637,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); @@ -652,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; } @@ -666,7 +605,6 @@ TtySetOptionProc( return TCL_OK; } -#ifdef USE_TERMIOS /* * Option -handshake none|xonxoff|rtscts|dtrdsr @@ -677,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; } @@ -713,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; } @@ -748,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 */ } /* @@ -851,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). * *---------------------------------------------------------------------- */ @@ -868,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. */ @@ -890,7 +827,6 @@ TtyGetOptionProc( Tcl_DStringAppendElement(dsPtr, buf); } -#ifdef USE_TERMIOS /* * Get option -xchar */ @@ -900,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) { @@ -929,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); @@ -944,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 @@ -953,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 @@ -1069,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. */ { @@ -1115,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; @@ -1140,7 +1059,6 @@ TtyGetBaud( } return 0; } -#endif /* !DIRECT_BAUD */ /* *--------------------------------------------------------------------------- @@ -1165,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'; @@ -1186,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; @@ -1255,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)); @@ -1290,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); } /* @@ -1357,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. - * *--------------------------------------------------------------------------- */ @@ -1367,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; } @@ -1389,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; } @@ -1431,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 */ @@ -1532,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: @@ -1566,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; } @@ -1599,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) { /* @@ -1658,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); @@ -1670,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 TclpMakeTcpClientChannelMode((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; } @@ -1762,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; } @@ -1822,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; } @@ -1849,8 +1659,7 @@ Tcl_GetOpenFile( || (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); /* @@ -1861,17 +1670,21 @@ 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; } @@ -1917,7 +1730,7 @@ TclUnixWaitForFile( int numFound, result = 0; fd_set readableMask; fd_set writableMask; - fd_set exceptionalMask; + fd_set exceptionMask; #ifndef _DARWIN_C_SOURCE /* @@ -1958,7 +1771,7 @@ TclUnixWaitForFile( FD_ZERO(&readableMask); FD_ZERO(&writableMask); - FD_ZERO(&exceptionalMask); + FD_ZERO(&exceptionMask); /* * Loop in a mini-event loop of our own, waiting for either the file to @@ -1983,14 +1796,14 @@ TclUnixWaitForFile( * Setup the select masks for the fd. */ - if (mask & TCL_READABLE) { + if (mask & TCL_READABLE) { FD_SET(fd, &readableMask); } - if (mask & TCL_WRITABLE) { + if (mask & TCL_WRITABLE) { FD_SET(fd, &writableMask); } if (mask & TCL_EXCEPTION) { - FD_SET(fd, &exceptionalMask); + FD_SET(fd, &exceptionMask); } /* @@ -1998,15 +1811,15 @@ TclUnixWaitForFile( */ numFound = select(fd + 1, &readableMask, &writableMask, - &exceptionalMask, timeoutPtr); + &exceptionMask, timeoutPtr); if (numFound == 1) { - if (FD_ISSET(fd, &readableMask)) { + if (FD_ISSET(fd, &readableMask)) { SET_BITS(result, TCL_READABLE); } - if (FD_ISSET(fd, &writableMask)) { + if (FD_ISSET(fd, &writableMask)) { SET_BITS(result, TCL_WRITABLE); } - if (FD_ISSET(fd, &exceptionalMask)) { + if (FD_ISSET(fd, &exceptionMask)) { SET_BITS(result, TCL_EXCEPTION); } result &= mask; @@ -2059,7 +1872,7 @@ FileTruncateProc( ClientData instanceData, Tcl_WideInt length) { - FileState *fsPtr = (FileState *) instanceData; + FileState *fsPtr = instanceData; int result; #ifdef HAVE_TYPE_OFF64_T |