summaryrefslogtreecommitdiffstats
path: root/unix
diff options
context:
space:
mode:
Diffstat (limited to 'unix')
-rw-r--r--unix/Makefile.in20
-rwxr-xr-xunix/configure4
-rw-r--r--unix/configure.ac4
-rw-r--r--unix/dltest/Makefile.in2
-rw-r--r--unix/tclUnixChan.c396
-rw-r--r--unix/tclUnixFCmd.c20
-rw-r--r--unix/tclUnixFile.c2
-rw-r--r--unix/tclUnixSock.c2
-rw-r--r--unix/tclUnixTime.c71
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 */
/*