diff options
Diffstat (limited to 'unix')
| -rw-r--r-- | unix/Makefile.in | 20 | ||||
| -rwxr-xr-x | unix/configure | 4 | ||||
| -rw-r--r-- | unix/configure.ac | 4 | ||||
| -rw-r--r-- | unix/dltest/Makefile.in | 2 | ||||
| -rw-r--r-- | unix/tclUnixChan.c | 396 | ||||
| -rw-r--r-- | unix/tclUnixFCmd.c | 20 | ||||
| -rw-r--r-- | unix/tclUnixFile.c | 2 | ||||
| -rw-r--r-- | unix/tclUnixSock.c | 2 | ||||
| -rw-r--r-- | unix/tclUnixTime.c | 71 |
9 files changed, 432 insertions, 89 deletions
diff --git a/unix/Makefile.in b/unix/Makefile.in index d769f03..74bee41 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -319,14 +319,14 @@ GENERIC_OBJS = regcomp.o regexec.o regfree.o regerror.o tclAlloc.o \ OO_OBJS = tclOO.o tclOOBasic.o tclOOCall.o tclOODefineCmds.o tclOOInfo.o \ tclOOMethod.o tclOOStubInit.o -TOMMATH_OBJS = bncore.o bn_reverse.o bn_fast_s_mp_mul_digs.o \ +TOMMATH_OBJS = bn_reverse.o bn_fast_s_mp_mul_digs.o \ bn_fast_s_mp_sqr.o bn_mp_add.o bn_mp_and.o \ bn_mp_add_d.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o \ bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \ bn_mp_cnt_lsb.o bn_mp_copy.o \ bn_mp_count_bits.o bn_mp_div.o bn_mp_div_d.o bn_mp_div_2.o \ - bn_mp_div_2d.o bn_mp_div_3.o \ - bn_mp_exch.o bn_mp_expt_d.o bn_mp_expt_d_ex.o bn_mp_get_int.o \ + bn_mp_div_2d.o bn_mp_div_3.o bn_mp_exch.o \ + bn_mp_expt_d.o bn_mp_expt_d_ex.o bn_mp_get_bit.o bn_mp_get_int.o \ bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o bn_mp_init.o \ bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o \ bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_karatsuba_mul.o \ @@ -490,7 +490,6 @@ STUB_SRCS = \ $(GENERIC_DIR)/tclOOStubLib.c TOMMATH_SRCS = \ - $(TOMMATH_DIR)/bncore.c \ $(TOMMATH_DIR)/bn_reverse.c \ $(TOMMATH_DIR)/bn_fast_s_mp_mul_digs.c \ $(TOMMATH_DIR)/bn_fast_s_mp_sqr.c \ @@ -1460,9 +1459,6 @@ tclThreadTest.o: $(GENERIC_DIR)/tclThreadTest.c tclTomMathInterface.o: $(GENERIC_DIR)/tclTomMathInterface.c $(MATHHDRS) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclTomMathInterface.c -bncore.o: $(TOMMATH_DIR)/bncore.c $(MATHHDRS) - $(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bncore.c - bn_reverse.o: $(TOMMATH_DIR)/bn_reverse.c $(MATHHDRS) $(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_reverse.c @@ -1532,6 +1528,9 @@ bn_mp_expt_d.o: $(TOMMATH_DIR)/bn_mp_expt_d.c $(MATHHDRS) bn_mp_expt_d_ex.o: $(TOMMATH_DIR)/bn_mp_expt_d_ex.c $(MATHHDRS) $(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_expt_d_ex.c +bn_mp_get_bit.o: $(TOMMATH_DIR)/bn_mp_get_bit.c $(MATHHDRS) + $(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_get_bit.c + bn_mp_get_int.o: $(TOMMATH_DIR)/bn_mp_get_int.c $(MATHHDRS) $(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_get_int.c @@ -2292,13 +2291,10 @@ html-tk: ${NATIVE_TCLSH} $(BUILD_HTML) --tk @EXTRA_BUILD_HTML@ -# You'd better have these programs or you will have problems creating Makefile -# from Makefile.in in the first place... -HTML_VERSION = `basename $(TOP_DIR) | sed s/tcl//` BUILD_HTML = \ @${NATIVE_TCLSH} $(TOOL_DIR)/tcltk-man2html.tcl \ - --useversion=$(HTML_VERSION) --htmldir="$(HTML_INSTALL_DIR)" \ - --srcdir=$(TOP_DIR)/.. $(BUILD_HTML_FLAGS) + --tcl --useversion=$(MAJOR_VERSION).$(MINOR_VERSION) --htmldir="$(HTML_INSTALL_DIR)" \ + --srcdir=$(TOP_DIR) $(BUILD_HTML_FLAGS) #-------------------------------------------------------------------------- # The list of all the targets that do not correspond to real files. This stops diff --git a/unix/configure b/unix/configure index ea26c4f..2de5b54 100755 --- a/unix/configure +++ b/unix/configure @@ -9455,10 +9455,10 @@ $as_echo "$langinfo_ok" >&6; } #-------------------------------------------------------------------- -# Check for support of chflags and mkstemps functions +# Check for support of cfmakeraw, chflags and mkstemps functions #-------------------------------------------------------------------- -for ac_func in chflags mkstemps +for ac_func in cfmakeraw chflags mkstemps do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/unix/configure.ac b/unix/configure.ac index f34091f..74dbe08 100644 --- a/unix/configure.ac +++ b/unix/configure.ac @@ -553,10 +553,10 @@ fi SC_ENABLE_LANGINFO #-------------------------------------------------------------------- -# Check for support of chflags and mkstemps functions +# Check for support of cfmakeraw, chflags and mkstemps functions #-------------------------------------------------------------------- -AC_CHECK_FUNCS(chflags mkstemps) +AC_CHECK_FUNCS(cfmakeraw chflags mkstemps) #-------------------------------------------------------------------- # Check for support of isnan() function or macro diff --git a/unix/dltest/Makefile.in b/unix/dltest/Makefile.in index 25b9376..500bf97 100644 --- a/unix/dltest/Makefile.in +++ b/unix/dltest/Makefile.in @@ -17,7 +17,7 @@ TCL_VERSION= @TCL_VERSION@ CFLAGS_DEBUG = @CFLAGS_DEBUG@ CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@ -CFLAGS = @CFLAGS_DEFAULT@ @CFLAGS@ +CFLAGS = @CFLAGS_DEFAULT@ @CFLAGS@ -DTCL_NO_DEPRECATED=1 LDFLAGS_DEBUG = @LDFLAGS_DEBUG@ LDFLAGS_OPTIMIZE = @LDFLAGS_OPTIMIZE@ LDFLAGS = @LDFLAGS_DEFAULT@ @LDFLAGS@ diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index 435579a..be49c95 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -49,6 +49,16 @@ #endif /* HAVE_TERMIOS_H */ /* + * The bits supported for describing the closeMode field of TtyState. + */ + +enum CloseModeBits { + CLOSE_DEFAULT, + CLOSE_DRAIN, + CLOSE_DISCARD +}; + +/* * Helper macros to make parts of this file clearer. The macros do exactly * what they say on the tin. :-) They also only ever refer to their arguments * once, and so can be used without regard to side effects. @@ -58,7 +68,8 @@ #define CLEAR_BITS(var, bits) ((var) &= ~(bits)) /* - * This structure describes per-instance state of a file based channel. + * These structures describe per-instance state of file-based and serial-based + * channels. */ typedef struct { @@ -69,6 +80,18 @@ typedef struct { * which operations are valid on the file. */ } FileState; +typedef struct { + FileState fileState; +#ifdef SUPPORTS_TTY + int closeMode; /* One of CLOSE_DEFAULT, CLOSE_DRAIN or + * CLOSE_DISCARD. */ + int doReset; /* Whether we should do a terminal reset on + * close. */ + struct termios initState; /* The state of the terminal when it was + * opened. */ +#endif /* SUPPORTS_TTY */ +} TtyState; + #ifdef SUPPORTS_TTY /* @@ -83,7 +106,7 @@ typedef struct { int stop; } TtyAttrs; -#endif /* !SUPPORTS_TTY */ +#endif /* SUPPORTS_TTY */ #define UNSUPPORTED_OPTION(detail) \ if (interp) { \ @@ -113,6 +136,8 @@ static Tcl_WideInt FileWideSeekProc(ClientData instanceData, Tcl_WideInt offset, int mode, int *errorCode); static void FileWatchProc(ClientData instanceData, int mask); #ifdef SUPPORTS_TTY +static int TtyCloseProc(ClientData instanceData, + Tcl_Interp *interp); static void TtyGetAttributes(int fd, TtyAttrs *ttyPtr); static int TtyGetOptionProc(ClientData instanceData, Tcl_Interp *interp, const char *optionName, @@ -162,7 +187,7 @@ static const Tcl_ChannelType fileChannelType = { static const Tcl_ChannelType ttyChannelType = { "tty", /* Type name. */ TCL_CHANNEL_VERSION_5, /* v5 channel */ - FileCloseProc, /* Close proc. */ + TtyCloseProc, /* Close proc. */ FileInputProc, /* Input proc. */ FileOutputProc, /* Output proc. */ NULL, /* Seek proc. */ @@ -310,10 +335,11 @@ FileOutputProc( /* *---------------------------------------------------------------------- * - * FileCloseProc -- + * FileCloseProc, TtyCloseProc -- * - * This function is called from the generic IO level to perform - * channel-type-specific cleanup when a file based channel is closed. + * These functions are called from the generic IO level to perform + * channel-type-specific cleanup when a file- or tty-based channel is + * closed. * * Results: * 0 if successful, errno if failed. @@ -347,6 +373,46 @@ FileCloseProc( ckfree(fsPtr); return errorCode; } + +#ifdef SUPPORTS_TTY +static int +TtyCloseProc( + ClientData instanceData, + Tcl_Interp *interp) +{ + TtyState *ttyPtr = instanceData; + + /* + * If we've been asked by the user to drain or flush, do so now. + */ + + switch (ttyPtr->closeMode) { + case CLOSE_DRAIN: + tcdrain(ttyPtr->fileState.fd); + break; + case CLOSE_DISCARD: + tcflush(ttyPtr->fileState.fd, TCIOFLUSH); + break; + default: + /* Do nothing */ + break; + } + + /* + * If we've had our state changed from the default, reset now. + */ + + if (ttyPtr->doReset) { + tcsetattr(ttyPtr->fileState.fd, TCSANOW, &ttyPtr->initState); + } + + /* + * Delegate to close for files. + */ + + return FileCloseProc(instanceData, interp); +} +#endif /* SUPPORTS_TTY */ /* *---------------------------------------------------------------------- @@ -578,7 +644,7 @@ TtySetOptionProc( const char *optionName, /* Which option to set? */ const char *value) /* New value for option. */ { - FileState *fsPtr = instanceData; + TtyState *fsPtr = instanceData; unsigned int len, vlen; TtyAttrs tty; int argc; @@ -601,7 +667,7 @@ TtySetOptionProc( * system calls results should be checked there. - dl */ - TtySetAttributes(fsPtr->fd, &tty); + TtySetAttributes(fsPtr->fileState.fd, &tty); return TCL_OK; } @@ -614,7 +680,7 @@ TtySetOptionProc( * Reset all handshake options. DTR and RTS are ON by default. */ - tcgetattr(fsPtr->fd, &iostate); + tcgetattr(fsPtr->fileState.fd, &iostate); CLEAR_BITS(iostate.c_iflag, IXON | IXOFF | IXANY); #ifdef CRTSCTS CLEAR_BITS(iostate.c_cflag, CRTSCTS); @@ -645,7 +711,7 @@ TtySetOptionProc( } return TCL_ERROR; } - tcsetattr(fsPtr->fd, TCSADRAIN, &iostate); + tcsetattr(fsPtr->fileState.fd, TCSADRAIN, &iostate); return TCL_OK; } @@ -654,34 +720,42 @@ TtySetOptionProc( */ if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) { - Tcl_DString ds; - if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } else if (argc != 2) { + badXchar: if (interp) { 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); + " two elements with each a single 8-bit character", -1)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "XCHAR", NULL); } ckfree(argv); return TCL_ERROR; } - tcgetattr(fsPtr->fd, &iostate); + tcgetattr(fsPtr->fileState.fd, &iostate); - Tcl_UtfToExternalDString(NULL, argv[0], -1, &ds); - iostate.c_cc[VSTART] = *(const cc_t *) Tcl_DStringValue(&ds); - TclDStringClear(&ds); + iostate.c_cc[VSTART] = argv[0][0]; + iostate.c_cc[VSTOP] = argv[1][0]; + if (argv[0][0] & 0x80 || argv[1][0] & 0x80) { + Tcl_UniChar character = 0; + int charLen; - Tcl_UtfToExternalDString(NULL, argv[1], -1, &ds); - iostate.c_cc[VSTOP] = *(const cc_t *) Tcl_DStringValue(&ds); - Tcl_DStringFree(&ds); + charLen = Tcl_UtfToUniChar(argv[0], &character); + if ((character > 0xFF) || argv[0][charLen]) { + goto badXchar; + } + iostate.c_cc[VSTART] = character; + charLen = Tcl_UtfToUniChar(argv[1], &character); + if ((character > 0xFF) || argv[1][charLen]) { + goto badXchar; + } + iostate.c_cc[VSTOP] = character; + } ckfree(argv); - tcsetattr(fsPtr->fd, TCSADRAIN, &iostate); + tcsetattr(fsPtr->fileState.fd, TCSADRAIN, &iostate); return TCL_OK; } @@ -692,13 +766,13 @@ TtySetOptionProc( if ((len > 2) && (strncmp(optionName, "-timeout", len) == 0)) { int msec; - tcgetattr(fsPtr->fd, &iostate); + tcgetattr(fsPtr->fileState.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; - tcsetattr(fsPtr->fd, TCSADRAIN, &iostate); + tcsetattr(fsPtr->fileState.fd, TCSADRAIN, &iostate); return TCL_OK; } @@ -725,7 +799,7 @@ TtySetOptionProc( return TCL_ERROR; } - ioctl(fsPtr->fd, TIOCMGET, &control); + ioctl(fsPtr->fileState.fd, TIOCMGET, &control); for (i = 0; i < argc-1; i += 2) { if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) { ckfree(argv); @@ -746,9 +820,9 @@ TtySetOptionProc( } else if (Tcl_UtfNcasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) { #if defined(TIOCSBRK) && defined(TIOCCBRK) if (flag) { - ioctl(fsPtr->fd, TIOCSBRK, NULL); + ioctl(fsPtr->fileState.fd, TIOCSBRK, NULL); } else { - ioctl(fsPtr->fd, TIOCCBRK, NULL); + ioctl(fsPtr->fileState.fd, TIOCCBRK, NULL); } #else /* TIOCSBRK & TIOCCBRK */ UNSUPPORTED_OPTION("-ttycontrol BREAK"); @@ -768,7 +842,7 @@ TtySetOptionProc( } } /* -ttycontrol options loop */ - ioctl(fsPtr->fd, TIOCMSET, &control); + ioctl(fsPtr->fileState.fd, TIOCMSET, &control); ckfree(argv); return TCL_OK; #else /* TIOCMGET&TIOCMSET */ @@ -776,8 +850,112 @@ TtySetOptionProc( #endif /* TIOCMGET&TIOCMSET */ } + /* + * Option -closemode drain|discard + */ + + if ((len > 2) && (strncmp(optionName, "-closemode", len) == 0)) { + if (Tcl_UtfNcasecmp(value, "DEFAULT", vlen) == 0) { + fsPtr->closeMode = CLOSE_DEFAULT; + } else if (Tcl_UtfNcasecmp(value, "DRAIN", vlen) == 0) { + fsPtr->closeMode = CLOSE_DRAIN; + } else if (Tcl_UtfNcasecmp(value, "DISCARD", vlen) == 0) { + fsPtr->closeMode = CLOSE_DISCARD; + } else { + if (interp) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad mode \"%s\" for -closemode: must be" + " default, discard, or drain", value)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", + "VALUE", NULL); + } + return TCL_ERROR; + } + return TCL_OK; + } + + /* + * Option -inputmode normal|password|raw + */ + + if ((len > 2) && (strncmp(optionName, "-inputmode", len) == 0)) { + if (tcgetattr(fsPtr->fileState.fd, &iostate) < 0) { + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read serial terminal control state: %s", + Tcl_PosixError(interp))); + } + return TCL_ERROR; + } + if (Tcl_UtfNcasecmp(value, "NORMAL", vlen) == 0) { + SET_BITS(iostate.c_iflag, BRKINT | IGNPAR | ISTRIP | ICRNL | IXON); + SET_BITS(iostate.c_oflag, OPOST); + SET_BITS(iostate.c_lflag, ECHO | ECHONL | ICANON | ISIG); + } else if (Tcl_UtfNcasecmp(value, "PASSWORD", vlen) == 0) { + SET_BITS(iostate.c_iflag, BRKINT | IGNPAR | ISTRIP | ICRNL | IXON); + SET_BITS(iostate.c_oflag, OPOST); + CLEAR_BITS(iostate.c_lflag, ECHO); + /* + * Note: password input turns out to be best if you echo the + * newline that the user types. Theoretically we could get users + * to do the processing of this in their scripts, but it always + * feels highly unnatural to do so in practice. + */ + SET_BITS(iostate.c_lflag, ECHONL | ICANON | ISIG); + } else if (Tcl_UtfNcasecmp(value, "RAW", vlen) == 0) { +#ifdef HAVE_CFMAKERAW + cfmakeraw(&iostate); +#else /* !HAVE_CFMAKERAW */ + CLEAR_BITS(iostate.c_iflag, IGNBRK | BRKINT | PARMRK | ISTRIP + | INLCR | IGNCR | ICRNL | IXON); + CLEAR_BITS(iostate.c_oflag, OPOST); + CLEAR_BITS(iostate.c_lflag, ECHO | ECHONL | ICANON | ISIG | IEXTEN); + CLEAR_BITS(iostate.c_cflag, CSIZE | PARENB); + SET_BITS(iostate.c_cflag, CS8); +#endif /* HAVE_CFMAKERAW */ + } else if (Tcl_UtfNcasecmp(value, "RESET", vlen) == 0) { + /* + * Reset to the initial state, whatever that is. + */ + + memcpy(&iostate, &fsPtr->initState, sizeof(struct termios)); + } else { + if (interp) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad mode \"%s\" for -inputmode: must be" + " normal, password, raw, or reset", value)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", + "VALUE", NULL); + } + return TCL_ERROR; + } + if (tcsetattr(fsPtr->fileState.fd, TCSADRAIN, &iostate) < 0) { + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't update serial terminal control state: %s", + Tcl_PosixError(interp))); + } + return TCL_ERROR; + } + + /* + * If we've changed the state from default, schedule a reset later. + * Note that this specifically does not detect changes made by calling + * an external stty program; that is deliberate, as it maintains + * compatibility with existing code! + * + * This mechanism in Tcl is not intended to be a full replacement for + * what stty does; it just handles a few common cases and tries not to + * leave things in a broken state. + */ + + fsPtr->doReset = (memcmp(&iostate, &fsPtr->initState, + sizeof(struct termios)) != 0); + return TCL_OK; + } + return Tcl_BadChannelOption(interp, optionName, - "mode handshake timeout ttycontrol xchar"); + "closemode inputmode mode handshake timeout ttycontrol xchar"); } /* @@ -805,16 +983,74 @@ TtyGetOptionProc( const char *optionName, /* Option to get. */ Tcl_DString *dsPtr) /* Where to store value(s). */ { - FileState *fsPtr = instanceData; + TtyState *fsPtr = instanceData; unsigned int len; char buf[3*TCL_INTEGER_SPACE + 16]; int valid = 0; /* Flag if valid option parsed. */ + struct termios iostate; if (optionName == NULL) { len = 0; } else { len = strlen(optionName); } + + /* + * Get option -closemode + */ + + if (len == 0) { + Tcl_DStringAppendElement(dsPtr, "-closemode"); + } + if (len==0 || (len>1 && strncmp(optionName, "-closemode", len)==0)) { + switch (fsPtr->closeMode) { + case CLOSE_DRAIN: + Tcl_DStringAppendElement(dsPtr, "drain"); + break; + case CLOSE_DISCARD: + Tcl_DStringAppendElement(dsPtr, "discard"); + break; + default: + Tcl_DStringAppendElement(dsPtr, "default"); + break; + } + } + + /* + * Get option -inputmode + * + * This is a great simplification of the underlying reality, but actually + * represents what almost all scripts really want to know. + */ + + if (len == 0) { + Tcl_DStringAppendElement(dsPtr, "-inputmode"); + } + if (len==0 || (len>1 && strncmp(optionName, "-inputmode", len)==0)) { + valid = 1; + if (tcgetattr(fsPtr->fileState.fd, &iostate) < 0) { + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read serial terminal control state: %s", + Tcl_PosixError(interp))); + } + return TCL_ERROR; + } + if (iostate.c_lflag & ICANON) { + if (iostate.c_lflag & ECHO) { + Tcl_DStringAppendElement(dsPtr, "normal"); + } else { + Tcl_DStringAppendElement(dsPtr, "password"); + } + } else { + Tcl_DStringAppendElement(dsPtr, "raw"); + } + } + + /* + * Get option -mode + */ + if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-mode"); } @@ -822,7 +1058,7 @@ TtyGetOptionProc( TtyAttrs tty; valid = 1; - TtyGetAttributes(fsPtr->fd, &tty); + TtyGetAttributes(fsPtr->fileState.fd, &tty); sprintf(buf, "%d,%c,%d,%d", tty.baud, tty.parity, tty.data, tty.stop); Tcl_DStringAppendElement(dsPtr, buf); } @@ -836,11 +1072,10 @@ TtyGetOptionProc( Tcl_DStringStartSublist(dsPtr); } if (len==0 || (len>1 && strncmp(optionName, "-xchar", len)==0)) { - struct termios iostate; Tcl_DString ds; valid = 1; - tcgetattr(fsPtr->fd, &iostate); + tcgetattr(fsPtr->fileState.fd, &iostate); Tcl_DStringInit(&ds); Tcl_ExternalToUtfDString(NULL, (char *) &iostate.c_cc[VSTART], 1, &ds); @@ -865,10 +1100,10 @@ TtyGetOptionProc( int inQueue=0, outQueue=0, inBuffered, outBuffered; valid = 1; - GETREADQUEUE(fsPtr->fd, inQueue); - GETWRITEQUEUE(fsPtr->fd, outQueue); - inBuffered = Tcl_InputBuffered(fsPtr->channel); - outBuffered = Tcl_OutputBuffered(fsPtr->channel); + GETREADQUEUE(fsPtr->fileState.fd, inQueue); + GETWRITEQUEUE(fsPtr->fileState.fd, outQueue); + inBuffered = Tcl_InputBuffered(fsPtr->fileState.channel); + outBuffered = Tcl_OutputBuffered(fsPtr->fileState.channel); sprintf(buf, "%d", inBuffered+inQueue); Tcl_DStringAppendElement(dsPtr, buf); @@ -887,16 +1122,42 @@ TtyGetOptionProc( int status; valid = 1; - ioctl(fsPtr->fd, TIOCMGET, &status); + ioctl(fsPtr->fileState.fd, TIOCMGET, &status); TtyModemStatusStr(status, dsPtr); } #endif /* TIOCMGET */ +#if defined(TIOCGWINSZ) + /* + * Get option -winsize + * Option is readonly and returned by [fconfigure chan -winsize] but not + * returned by [fconfigure chan] without explicit option name. + */ + + if ((len > 1) && (strncmp(optionName, "-winsize", len) == 0)) { + struct winsize ws; + + valid = 1; + if (ioctl(fsPtr->fileState.fd, TIOCGWINSZ, &ws) < 0) { + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read terminal size: %s", + Tcl_PosixError(interp))); + } + return TCL_ERROR; + } + sprintf(buf, "%d", ws.ws_col); + Tcl_DStringAppendElement(dsPtr, buf); + sprintf(buf, "%d", ws.ws_row); + Tcl_DStringAppendElement(dsPtr, buf); + } +#endif /* TIOCGWINSZ */ + if (valid) { return TCL_OK; } return Tcl_BadChannelOption(interp, optionName, - "mode queue ttystatus xchar"); + "closemode inputmode mode queue ttystatus winsize xchar"); } static const struct {int baud; speed_t speed;} speeds[] = { @@ -1367,7 +1628,7 @@ TclpOpenFileChannel( * what modes to create it? */ { int fd, channelPermissions; - FileState *fsPtr; + TtyState *fsPtr; const char *native, *translation; char channelName[16 + TCL_INTEGER_SPACE]; const Tcl_ChannelType *channelTypePtr; @@ -1423,8 +1684,6 @@ TclpOpenFileChannel( fcntl(fd, F_SETFD, FD_CLOEXEC); - sprintf(channelName, "file%d", fd); - #ifdef SUPPORTS_TTY if (strcmp(native, "/dev/tty") != 0 && isatty(fd)) { /* @@ -1444,18 +1703,27 @@ TclpOpenFileChannel( translation = "auto crlf"; channelTypePtr = &ttyChannelType; TtyInit(fd); + sprintf(channelName, "serial%d", fd); } else #endif /* SUPPORTS_TTY */ { translation = NULL; channelTypePtr = &fileChannelType; + sprintf(channelName, "file%d", fd); } - fsPtr = ckalloc(sizeof(FileState)); - fsPtr->validMask = channelPermissions | TCL_EXCEPTION; - fsPtr->fd = fd; + fsPtr = ckalloc(sizeof(TtyState)); + fsPtr->fileState.validMask = channelPermissions | TCL_EXCEPTION; + fsPtr->fileState.fd = fd; +#ifdef SUPPORTS_TTY + if (channelTypePtr == &ttyChannelType) { + fsPtr->closeMode = CLOSE_DEFAULT; + fsPtr->doReset = 0; + tcgetattr(fsPtr->fileState.fd, &fsPtr->initState); + } +#endif /* SUPPORTS_TTY */ - fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, + fsPtr->fileState.channel = Tcl_CreateChannel(channelTypePtr, channelName, fsPtr, channelPermissions); if (translation != NULL) { @@ -1467,14 +1735,14 @@ TclpOpenFileChannel( * reports that the serial port isn't working. */ - if (Tcl_SetChannelOption(interp, fsPtr->channel, "-translation", - translation) != TCL_OK) { - Tcl_Close(NULL, fsPtr->channel); + if (Tcl_SetChannelOption(interp, fsPtr->fileState.channel, + "-translation", translation) != TCL_OK) { + Tcl_Close(NULL, fsPtr->fileState.channel); return NULL; } } - return fsPtr->channel; + return fsPtr->fileState.channel; } /* @@ -1499,7 +1767,7 @@ Tcl_MakeFileChannel( int mode) /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */ { - FileState *fsPtr; + TtyState *fsPtr; char channelName[16 + TCL_INTEGER_SPACE]; int fd = PTR2INT(handle); const Tcl_ChannelType *channelTypePtr; @@ -1518,22 +1786,30 @@ Tcl_MakeFileChannel( sprintf(channelName, "serial%d", fd); } else #endif /* SUPPORTS_TTY */ - if ((getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0) - && (sockaddrLen > 0) - && (sockaddr.sa_family == AF_INET || sockaddr.sa_family == AF_INET6)) { + 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; sprintf(channelName, "file%d", fd); } - fsPtr = ckalloc(sizeof(FileState)); - fsPtr->fd = fd; - fsPtr->validMask = mode | TCL_EXCEPTION; - fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, + fsPtr = ckalloc(sizeof(TtyState)); + fsPtr->fileState.fd = fd; + fsPtr->fileState.validMask = mode | TCL_EXCEPTION; + fsPtr->fileState.channel = Tcl_CreateChannel(channelTypePtr, channelName, fsPtr, mode); +#ifdef SUPPORTS_TTY + if (channelTypePtr == &ttyChannelType) { + fsPtr->closeMode = CLOSE_DEFAULT; + fsPtr->doReset = 0; + tcgetattr(fsPtr->fileState.fd, &fsPtr->initState); + } +#endif /* SUPPORTS_TTY */ - return fsPtr->channel; + return fsPtr->fileState.channel; } /* diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index 7205085..e963589 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -1499,11 +1499,11 @@ SetGroupAttribute( Tcl_Obj *fileName, /* The name of the file (UTF-8). */ Tcl_Obj *attributePtr) /* New group for file. */ { - long gid; + Tcl_WideInt gid; int result; const char *native; - if (Tcl_GetLongFromObj(NULL, attributePtr, &gid) != TCL_OK) { + if (Tcl_GetWideIntFromObj(NULL, attributePtr, &gid) != TCL_OK) { Tcl_DString ds; struct group *groupPtr = NULL; const char *string; @@ -1565,11 +1565,11 @@ SetOwnerAttribute( Tcl_Obj *fileName, /* The name of the file (UTF-8). */ Tcl_Obj *attributePtr) /* New owner for file. */ { - long uid; + Tcl_WideInt uid; int result; const char *native; - if (Tcl_GetLongFromObj(NULL, attributePtr, &uid) != TCL_OK) { + if (Tcl_GetWideIntFromObj(NULL, attributePtr, &uid) != TCL_OK) { Tcl_DString ds; struct passwd *pwPtr = NULL; const char *string; @@ -1631,7 +1631,7 @@ SetPermissionsAttribute( Tcl_Obj *fileName, /* The name of the file (UTF-8). */ Tcl_Obj *attributePtr) /* The attribute to set. */ { - long mode; + Tcl_WideInt mode; mode_t newMode; int result = TCL_ERROR; const char *native; @@ -1650,11 +1650,11 @@ SetPermissionsAttribute( TclNewLiteralStringObj(modeObj, "0o"); Tcl_AppendToObj(modeObj, modeStringPtr+scanned+1, -1); - result = Tcl_GetLongFromObj(NULL, modeObj, &mode); + result = Tcl_GetWideIntFromObj(NULL, modeObj, &mode); Tcl_DecrRefCount(modeObj); } if (result == TCL_OK - || Tcl_GetLongFromObj(NULL, attributePtr, &mode) == TCL_OK) { + || Tcl_GetWideIntFromObj(NULL, attributePtr, &mode) == TCL_OK) { newMode = (mode_t) (mode & 0x00007FFF); } else { Tcl_StatBuf buf; @@ -2340,8 +2340,8 @@ GetUnixFileAttributes( return TCL_ERROR; } - *attributePtrPtr = Tcl_NewBooleanObj( - fileAttributes & attributeArray[objIndex]); + *attributePtrPtr = Tcl_NewWideIntObj( + (fileAttributes & attributeArray[objIndex]) != 0); return TCL_OK; } @@ -2440,7 +2440,7 @@ GetUnixFileAttributes( return TCL_ERROR; } - *attributePtrPtr = Tcl_NewBooleanObj(statBuf.st_flags & UF_IMMUTABLE); + *attributePtrPtr = Tcl_NewWideIntObj((statBuf.st_flags & UF_IMMUTABLE) != 0); return TCL_OK; } diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c index 8cb93b4..bf033d2 100644 --- a/unix/tclUnixFile.c +++ b/unix/tclUnixFile.c @@ -1117,7 +1117,7 @@ TclNativeCreateNativeRep( } Tcl_DecrRefCount(validPathPtr); nativePathPtr = ckalloc(len); - memcpy(nativePathPtr, Tcl_DStringValue(&ds), (size_t) len); + memcpy(nativePathPtr, Tcl_DStringValue(&ds), len); Tcl_DStringFree(&ds); return nativePathPtr; diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c index bd54a2e..62e4756 100644 --- a/unix/tclUnixSock.c +++ b/unix/tclUnixSock.c @@ -241,7 +241,7 @@ InitializeHostName( if (dot != NULL) { char *node = ckalloc(dot - u.nodename + 1); - memcpy(node, u.nodename, (size_t) (dot - u.nodename)); + memcpy(node, u.nodename, dot - u.nodename); node[dot - u.nodename] = '\0'; hp = TclpGetHostByName(node); ckfree(node); diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c index 6a73ac2..1d8b351 100644 --- a/unix/tclUnixTime.c +++ b/unix/tclUnixTime.c @@ -87,6 +87,32 @@ TclpGetSeconds(void) /* *---------------------------------------------------------------------- * + * TclpGetMicroseconds -- + * + * This procedure returns the number of microseconds from the epoch. + * On most Unix systems the epoch is Midnight Jan 1, 1970 GMT. + * + * Results: + * Number of microseconds from the epoch. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_WideInt +TclpGetMicroseconds(void) +{ + Tcl_Time time; + + tclGetTimeProcPtr(&time, tclTimeClientData); + return ((Tcl_WideInt)time.sec)*1000000 + time.usec; +} + +/* + *---------------------------------------------------------------------- + * * TclpGetClicks -- * * This procedure returns a value that represents the highest resolution @@ -219,6 +245,51 @@ TclpWideClicksToNanoseconds( return nsec; } + +/* + *---------------------------------------------------------------------- + * + * TclpWideClickInMicrosec -- + * + * This procedure return scale to convert click values from the + * TclpGetWideClicks native resolution to microsecond resolution + * and back. + * + * Results: + * 1 click in microseconds as double. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +double +TclpWideClickInMicrosec(void) +{ + if (tclGetTimeProcPtr != NativeGetTime) { + return 1.0; + } else { +#ifdef MAC_OSX_TCL + static int initialized = 0; + static double scale = 0.0; + + if (initialized) { + return scale; + } else { + mach_timebase_info_data_t tb; + + mach_timebase_info(&tb); + /* value of tb.numer / tb.denom = 1 click in nanoseconds */ + scale = ((double)tb.numer) / tb.denom / 1000; + initialized = 1; + return scale; + } +#else +#error Wide high-resolution clicks not implemented on this platform +#endif + } +} #endif /* TCL_WIDE_CLICKS */ /* |
