summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
Diffstat (limited to 'win')
-rw-r--r--win/Makefile.in820
-rw-r--r--win/README37
-rw-r--r--[-rwxr-xr-x]win/buildall.vc.bat14
-rw-r--r--win/cat.c15
-rw-r--r--win/coffbase.txt42
-rwxr-xr-xwin/configure8524
-rw-r--r--win/configure.in (renamed from win/configure.ac)316
-rw-r--r--win/gitmanifest.in1
-rw-r--r--win/makefile.bc597
-rw-r--r--win/makefile.vc1179
-rw-r--r--win/nmakehlp.c238
-rw-r--r--win/rules-ext.vc123
-rw-r--r--win/rules.vc1941
-rw-r--r--win/stub16.c195
-rw-r--r--win/svnmanifest.in1
-rw-r--r--win/targets.vc98
-rw-r--r--win/tcl.dsp124
-rw-r--r--win/tcl.hpj.in19
-rw-r--r--win/tcl.m4573
-rw-r--r--win/tcl.rc11
-rw-r--r--win/tclAppInit.c201
-rw-r--r--win/tclConfig.sh.in32
-rw-r--r--win/tclUuid.h.in1
-rw-r--r--win/tclWin32Dll.c707
-rw-r--r--win/tclWinChan.c696
-rw-r--r--win/tclWinConsole.c2511
-rw-r--r--win/tclWinDde.c744
-rw-r--r--win/tclWinError.c72
-rw-r--r--win/tclWinFCmd.c681
-rwxr-xr-x[-rw-r--r--]win/tclWinFile.c1994
-rw-r--r--win/tclWinInit.c354
-rw-r--r--win/tclWinInt.h231
-rw-r--r--win/tclWinLoad.c335
-rw-r--r--win/tclWinNotify.c218
-rw-r--r--win/tclWinPanic.c88
-rw-r--r--win/tclWinPipe.c1607
-rw-r--r--win/tclWinPort.h381
-rw-r--r--win/tclWinReg.c775
-rw-r--r--win/tclWinSerial.c559
-rw-r--r--win/tclWinSock.c3677
-rw-r--r--win/tclWinTest.c531
-rw-r--r--win/tclWinThrd.c262
-rw-r--r--win/tclWinThrd.h19
-rw-r--r--win/tclWinTime.c922
-rw-r--r--win/tclooConfig.sh19
-rw-r--r--win/tclsh.exe.manifest.in6
-rw-r--r--win/tclsh.icobin57022 -> 3630 bytes
-rw-r--r--win/tclsh.rc11
-rw-r--r--win/tcltest.rc75
-rwxr-xr-xwin/x86_64-w64-mingw32-nmakehlp.exebin25088 -> 0 bytes
50 files changed, 13617 insertions, 18960 deletions
diff --git a/win/Makefile.in b/win/Makefile.in
index e103ef2..ada9448 100644
--- a/win/Makefile.in
+++ b/win/Makefile.in
@@ -23,7 +23,6 @@ bindir = @bindir@
libdir = @libdir@
includedir = @includedir@
datarootdir = @datarootdir@
-runstatedir = @runstatedir@
mandir = @mandir@
# The following definition can be set to non-null for special systems like AFS
@@ -49,9 +48,6 @@ LIB_INSTALL_DIR = $(INSTALL_ROOT)$(libdir)
# Path name to use when installing library scripts.
SCRIPT_INSTALL_DIR = $(INSTALL_ROOT)$(TCL_LIBRARY)
-# Path name to use when installing Tcl modules.
-MODULE_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)/../tcl8
-
# Directory in which to install the include file tcl.h:
INCLUDE_INSTALL_DIR = $(INSTALL_ROOT)$(includedir)
@@ -70,6 +66,9 @@ MAN3_INSTALL_DIR = $(MAN_INSTALL_DIR)/man3
# Directory in which to install manual entries for the built-in Tcl commands:
MANN_INSTALL_DIR = $(MAN_INSTALL_DIR)/mann
+# Libraries built with optimization switches have this additional extension
+TCL_DBGX = @TCL_DBGX@
+
# warning flags
CFLAGS_WARNING = @CFLAGS_WARNING@
@@ -82,12 +81,7 @@ CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@
#CFLAGS = $(CFLAGS_DEBUG)
#CFLAGS = $(CFLAGS_OPTIMIZE)
#CFLAGS = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE)
-CFLAGS = @CFLAGS@ @CFLAGS_DEFAULT@ -DMP_FIXED_CUTOFFS -D__USE_MINGW_ANSI_STDIO=0
-
-# To compile without backward compatibility and deprecated code uncomment the
-# following
-NO_DEPRECATED_FLAGS =
-#NO_DEPRECATED_FLAGS = -DTCL_NO_DEPRECATED
+CFLAGS = @CFLAGS@ @CFLAGS_DEFAULT@
# To enable compilation debugging reverse the comment characters on one of the
# following lines.
@@ -95,17 +89,15 @@ COMPILE_DEBUG_FLAGS =
#COMPILE_DEBUG_FLAGS = -DTCL_COMPILE_DEBUG
#COMPILE_DEBUG_FLAGS = -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS
+# Special compiler flags to use when building man2tcl on Windows.
+MAN2TCLFLAGS = @MAN2TCLFLAGS@
+
SRC_DIR = @srcdir@
ROOT_DIR = @srcdir@/..
-TOP_DIR = $(shell cd @srcdir@/..; pwd -W 2>/dev/null || pwd -P)
-BUILD_DIR = @builddir@
-GENERIC_DIR = $(TOP_DIR)/generic
-WIN_DIR = $(TOP_DIR)/win
-COMPAT_DIR = $(TOP_DIR)/compat
-PKGS_DIR = $(TOP_DIR)/pkgs
-ZLIB_DIR = $(COMPAT_DIR)/zlib
-MINIZIP_DIR = $(ZLIB_DIR)/contrib/minizip
-TOMMATH_DIR = $(TOP_DIR)/libtommath
+GENERIC_DIR = @srcdir@/../generic
+TOMMATH_DIR = @srcdir@/../libtommath
+WIN_DIR = @srcdir@
+COMPAT_DIR = @srcdir@/../compat
# Converts a POSIX path to a Windows native path.
CYGPATH = @CYGPATH@
@@ -116,16 +108,18 @@ includedir_native = $(shell $(CYGPATH) '$(includedir)')
mandir_native = $(shell $(CYGPATH) '$(mandir)')
TCL_LIBRARY_NATIVE = $(shell $(CYGPATH) '$(TCL_LIBRARY)')
GENERIC_DIR_NATIVE = $(shell $(CYGPATH) '$(GENERIC_DIR)')
+TOMMATH_DIR_NATIVE = $(shell $(CYGPATH) '$(TOMMATH_DIR)')
WIN_DIR_NATIVE = $(shell $(CYGPATH) '$(WIN_DIR)')
ROOT_DIR_NATIVE = $(shell $(CYGPATH) '$(ROOT_DIR)')
-SCRIPT_INSTALL_DIR_NATIVE = $(shell $(CYGPATH) '$(SCRIPT_INSTALL_DIR)')
-INCLUDE_INSTALL_DIR_NATIVE = $(shell $(CYGPATH) '$(INCLUDE_INSTALL_DIR)')
-MAN_INSTALL_DIR_NATIVE = $(shell $(CYGPATH) '$(MAN_INSTALL_DIR)')
-ROOT_DIR_WIN_NATIVE = $(shell cd '$(ROOT_DIR)' ; pwd -W 2>/dev/null || pwd -P)
-ZLIB_DIR_NATIVE = $(shell $(CYGPATH) '$(ZLIB_DIR)')
-MINIZIP_DIR_NATIVE = $(shell $(CYGPATH) '$(MINIZIP_DIR)')
-TOMMATH_DIR_NATIVE = $(shell $(CYGPATH) '$(TOMMATH_DIR)')
+#GENERIC_DIR_NATIVE = $(GENERIC_DIR)
+#TOMMATH_DIR_NATIVE = $(TOMMATH_DIR)
+#WIN_DIR_NATIVE = $(WIN_DIR)
+#ROOT_DIR_NATIVE = $(ROOT_DIR)
+# Fully qualify library path so that `make test`
+# does not depend on the current directory.
+LIBRARY_DIR1 = $(shell cd '$(ROOT_DIR_NATIVE)/library' ; pwd)
+LIBRARY_DIR = $(shell $(CYGPATH) '$(LIBRARY_DIR1)')
DLLSUFFIX = @DLLSUFFIX@
LIBSUFFIX = @LIBSUFFIX@
EXESUFFIX = @EXESUFFIX@
@@ -137,49 +131,41 @@ DDEDOTVER = @TCL_DDE_MAJOR_VERSION@.@TCL_DDE_MINOR_VERSION@
REGVER = @TCL_REG_MAJOR_VERSION@@TCL_REG_MINOR_VERSION@
REGDOTVER = @TCL_REG_MAJOR_VERSION@.@TCL_REG_MINOR_VERSION@
-TCL_ZIP_FILE = @TCL_ZIP_FILE@
-TCL_VFS_PATH = libtcl.vfs/tcl_library
-TCL_VFS_ROOT = libtcl.vfs
-
-
TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
TCL_DLL_FILE = @TCL_DLL_FILE@
TCL_LIB_FILE = @TCL_LIB_FILE@
DDE_DLL_FILE = tcldde$(DDEVER)${DLLSUFFIX}
-DDE_LIB_FILE = @LIBPREFIX@tcldde$(DDEVER)${DLLSUFFIX}${LIBSUFFIX}
-REG_DLL_FILE = tclregistry$(REGVER)${DLLSUFFIX}
-REG_LIB_FILE = @LIBPREFIX@tclregistry$(REGVER)${DLLSUFFIX}${LIBSUFFIX}
-TEST_DLL_FILE = tcltest$(VER)${DLLSUFFIX}
-TEST_EXE_FILE = tcltest${EXESUFFIX}
-TEST_LIB_FILE = @LIBPREFIX@tcltest$(VER)${DLLSUFFIX}${LIBSUFFIX}
-TEST_LOAD_PRMS = lappend ::auto_path {$(ROOT_DIR_WIN_NATIVE)/tests};\
- package ifneeded dde 1.4.5 [list load ${DDE_DLL_FILE}];\
- package ifneeded registry 1.3.7 [list load ${REG_DLL_FILE}]
-TEST_LOAD_FACILITIES = package ifneeded tcl::test ${VERSION}@TCL_PATCH_LEVEL@ [list load ${TEST_DLL_FILE} Tcltest];\
- $(TEST_LOAD_PRMS)
-ZLIB_DLL_FILE = zlib1.dll
-TOMMATH_DLL_FILE = libtommath.dll
-
-SHARED_LIBRARIES = $(TCL_DLL_FILE) @ZLIB_DLL_FILE@ @TOMMATH_DLL_FILE@
-STATIC_LIBRARIES = $(TCL_LIB_FILE)
+DDE_LIB_FILE = tcldde$(DDEVER)${LIBSUFFIX}
+REG_DLL_FILE = tclreg$(REGVER)${DLLSUFFIX}
+REG_LIB_FILE = tclreg$(REGVER)${LIBSUFFIX}
+PIPE_DLL_FILE = tclpip$(VER)${DLLSUFFIX}
+
+SHARED_LIBRARIES = $(TCL_DLL_FILE) $(TCL_STUB_LIB_FILE) \
+ $(DDE_DLL_FILE) $(REG_DLL_FILE) $(PIPE_DLL_FILE)
+STATIC_LIBRARIES = $(TCL_LIB_FILE) $(REG_LIB_FILE) $(DDE_LIB_FILE)
+
+# To compile without backward compatibility and deprecated code
+# uncomment the following
+NO_DEPRECATED_FLAGS =
+#NO_DEPRECATED_FLAGS = -DTCL_NO_DEPRECATED
+
+# TCL_EXE is the name of a tclsh executable that is available *BEFORE* running
+# make for the first time. Certain build targets (make genstubs) need it to be
+# available on the PATH. This executable should *NOT* be required just to do a
+# normal build although it can be required to run make dist.
+TCL_EXE = tclsh
TCLSH = tclsh$(VER)${EXESUFFIX}
-WINE = @WINE@
+TCLTEST = tcltest${EXEEXT}
CAT32 = cat32$(EXEEXT)
-
-# For cross-compiled builds, TCL_EXE is the name of a tclsh executable that is
-# available *BEFORE* running make for the first time. Certain build targets
-# (make genstubs, make install) need it to be available on the PATH. This
-# executable should *NOT* be required just to do a normal build although
-# it can be required to run make dist.
-TCL_EXE = @TCL_EXE@
+MAN2TCL = man2tcl$(EXEEXT)
@SET_MAKE@
# Setting the VPATH variable to a list of paths will cause the Makefile to
# look into these paths when resolving .c to .obj dependencies.
-VPATH = $(GENERIC_DIR):$(WIN_DIR):$(COMPAT_DIR):$(ZLIB_DIR):$(TOMMATH_DIR)
+VPATH = $(GENERIC_DIR):$(TOMMATH_DIR):$(WIN_DIR):$(COMPAT_DIR)
AR = @AR@
RANLIB = @RANLIB@
@@ -197,84 +183,37 @@ EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
STLIB_LD = @STLIB_LD@
SHLIB_LD = @SHLIB_LD@
-SHLIB_LD_LIBS = @SHLIB_LD_LIBS@
+SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ $(LIBS)
SHLIB_CFLAGS = @SHLIB_CFLAGS@
SHLIB_SUFFIX = @SHLIB_SUFFIX@
-LIBS = @LIBS@ $(shell $(CYGPATH) '@ZLIB_LIBS@') $(shell $(CYGPATH) '@TOMMATH_LIBS@')
+LIBS = @LIBS@
RMDIR = rm -rf
MKDIR = mkdir -p
SHELL = @SHELL@
RM = rm -f
COPY = cp
-LN = ln
-
-###
-# Tip 430 - ZipFS Modifications
-###
-
-TCL_ZIP_FILE = @TCL_ZIP_FILE@
-TCL_VFS_PATH = libtcl.vfs/tcl_library
-TCL_VFS_ROOT = libtcl.vfs
-
-HOST_CC = @CC_FOR_BUILD@
-HOST_EXEEXT = @EXEEXT_FOR_BUILD@
-HOST_OBJEXT = @OBJEXT_FOR_BUILD@
-ZIPFS_BUILD = @ZIPFS_BUILD@
-NATIVE_ZIP = @ZIP_PROG@
-ZIP_PROG_OPTIONS = @ZIP_PROG_OPTIONS@
-ZIP_PROG_VFSSEARCH = @ZIP_PROG_VFSSEARCH@
-SHARED_BUILD = @SHARED_BUILD@
-INSTALL_MSGS = @INSTALL_MSGS@
-INSTALL_LIBRARIES = @INSTALL_LIBRARIES@
-# Fully qualify library path so that `make test`
-# does not depend on the current directory.
-# Only define these if not embedding the library
-ifeq ($(ZIPFS_BUILD), 0)
-LIBRARY_DIR1 = $(shell cd '$(ROOT_DIR_NATIVE)/library' ; pwd -P)
-LIBRARY_DIR = $(shell $(CYGPATH) '$(LIBRARY_DIR1)')
-endif
-
-# Minizip
-MINIZIP_OBJS = \
- adler32.$(HOST_OBJEXT) \
- compress.$(HOST_OBJEXT) \
- crc32.$(HOST_OBJEXT) \
- deflate.$(HOST_OBJEXT) \
- infback.$(HOST_OBJEXT) \
- inffast.$(HOST_OBJEXT) \
- inflate.$(HOST_OBJEXT) \
- inftrees.$(HOST_OBJEXT) \
- ioapi.$(HOST_OBJEXT) \
- iowin32.$(HOST_OBJEXT) \
- trees.$(HOST_OBJEXT) \
- uncompr.$(HOST_OBJEXT) \
- zip.$(HOST_OBJEXT) \
- zutil.$(HOST_OBJEXT) \
- minizip.$(HOST_OBJEXT)
-
-ZIP_INSTALL_OBJS = @ZIP_INSTALL_OBJS@
-
-CC_SWITCHES = -I"${BUILD_DIR}" -I"${GENERIC_DIR_NATIVE}" -I"${TOMMATH_DIR_NATIVE}" \
--I"${ZLIB_DIR_NATIVE}" -I"${WIN_DIR_NATIVE}" \
-${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} -DMP_PREC=4 \
-${AC_FLAGS} ${COMPILE_DEBUG_FLAGS} ${NO_DEPRECATED_FLAGS}
+CC_SWITCHES = ${CFLAGS} ${CFLAGS_WARNING} ${TCL_SHLIB_CFLAGS} \
+-I"${GENERIC_DIR_NATIVE}" -DTCL_TOMMATH -DMP_PREC=4 -I"${TOMMATH_DIR_NATIVE}" \
+-I"${WIN_DIR_NATIVE}" ${AC_FLAGS} \
+${COMPILE_DEBUG_FLAGS} ${NO_DEPRECATED_FLAGS}
CC_OBJNAME = @CC_OBJNAME@
CC_EXENAME = @CC_EXENAME@
-STUB_CC_SWITCHES = -I"${GENERIC_DIR_NATIVE}" -I"${TOMMATH_DIR_NATIVE}" \
--I"${ZLIB_DIR_NATIVE}" -I"${WIN_DIR_NATIVE}" \
-${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} -DMP_PREC=4 \
-${AC_FLAGS} ${COMPILE_DEBUG_FLAGS}
+STUB_CC_SWITCHES = ${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} \
+-I"${GENERIC_DIR_NATIVE}" -DTCL_TOMMATH -DMP_PREC=4 -I"${TOMMATH_DIR_NATIVE}" \
+-I"${WIN_DIR_NATIVE}" ${AC_FLAGS} \
+${COMPILE_DEBUG_FLAGS}
TCLTEST_OBJS = \
tclTest.$(OBJEXT) \
tclTestObj.$(OBJEXT) \
tclTestProcBodyObj.$(OBJEXT) \
tclThreadTest.$(OBJEXT) \
- tclWinTest.$(OBJEXT)
+ tclWinTest.$(OBJEXT) \
+ testMain.$(OBJEXT)
GENERIC_OBJS = \
regcomp.$(OBJEXT) \
@@ -282,8 +221,6 @@ GENERIC_OBJS = \
regfree.$(OBJEXT) \
regerror.$(OBJEXT) \
tclAlloc.$(OBJEXT) \
- tclArithSeries.$(OBJEXT) \
- tclAssembly.$(OBJEXT) \
tclAsync.$(OBJEXT) \
tclBasic.$(OBJEXT) \
tclBinary.$(OBJEXT) \
@@ -293,16 +230,12 @@ GENERIC_OBJS = \
tclCmdIL.$(OBJEXT) \
tclCmdMZ.$(OBJEXT) \
tclCompCmds.$(OBJEXT) \
- tclCompCmdsGR.$(OBJEXT) \
- tclCompCmdsSZ.$(OBJEXT) \
tclCompExpr.$(OBJEXT) \
tclCompile.$(OBJEXT) \
tclConfig.$(OBJEXT) \
tclDate.$(OBJEXT) \
tclDictObj.$(OBJEXT) \
- tclDisassemble.$(OBJEXT) \
tclEncoding.$(OBJEXT) \
- tclEnsemble.$(OBJEXT) \
tclEnv.$(OBJEXT) \
tclEvent.$(OBJEXT) \
tclExecute.$(OBJEXT) \
@@ -317,26 +250,16 @@ GENERIC_OBJS = \
tclIOCmd.$(OBJEXT) \
tclIOGT.$(OBJEXT) \
tclIORChan.$(OBJEXT) \
- tclIORTrans.$(OBJEXT) \
tclIOSock.$(OBJEXT) \
tclIOUtil.$(OBJEXT) \
tclLink.$(OBJEXT) \
tclLiteral.$(OBJEXT) \
tclListObj.$(OBJEXT) \
tclLoad.$(OBJEXT) \
- tclMainW.$(OBJEXT) \
tclMain.$(OBJEXT) \
tclNamesp.$(OBJEXT) \
tclNotify.$(OBJEXT) \
- tclOO.$(OBJEXT) \
- tclOOBasic.$(OBJEXT) \
- tclOOCall.$(OBJEXT) \
- tclOODefineCmds.$(OBJEXT) \
- tclOOInfo.$(OBJEXT) \
- tclOOMethod.$(OBJEXT) \
- tclOOStubInit.$(OBJEXT) \
tclObj.$(OBJEXT) \
- tclOptimize.$(OBJEXT) \
tclPanic.$(OBJEXT) \
tclParse.$(OBJEXT) \
tclPathObj.$(OBJEXT) \
@@ -346,7 +269,6 @@ GENERIC_OBJS = \
tclPosixStr.$(OBJEXT) \
tclPreserve.$(OBJEXT) \
tclProc.$(OBJEXT) \
- tclProcess.$(OBJEXT) \
tclRegexp.$(OBJEXT) \
tclResolve.$(OBJEXT) \
tclResult.$(OBJEXT) \
@@ -354,6 +276,7 @@ GENERIC_OBJS = \
tclStringObj.$(OBJEXT) \
tclStrToD.$(OBJEXT) \
tclStubInit.$(OBJEXT) \
+ tclStubLib.$(OBJEXT) \
tclThread.$(OBJEXT) \
tclThreadAlloc.$(OBJEXT) \
tclThreadJoin.$(OBJEXT) \
@@ -363,11 +286,13 @@ GENERIC_OBJS = \
tclTrace.$(OBJEXT) \
tclUtf.$(OBJEXT) \
tclUtil.$(OBJEXT) \
- tclVar.$(OBJEXT) \
- tclZipfs.$(OBJEXT) \
- tclZlib.$(OBJEXT)
+ tclVar.$(OBJEXT)
TOMMATH_OBJS = \
+ bncore.${OBJEXT} \
+ bn_reverse.${OBJEXT} \
+ bn_fast_s_mp_mul_digs.${OBJEXT} \
+ bn_fast_s_mp_sqr.${OBJEXT} \
bn_mp_add.${OBJEXT} \
bn_mp_add_d.${OBJEXT} \
bn_mp_and.${OBJEXT} \
@@ -386,16 +311,16 @@ TOMMATH_OBJS = \
bn_mp_div_2d.${OBJEXT} \
bn_mp_div_3.${OBJEXT} \
bn_mp_exch.${OBJEXT} \
- bn_mp_expt_u32.${OBJEXT} \
- bn_mp_get_mag_u64.${OBJEXT} \
+ bn_mp_expt_d.${OBJEXT} \
bn_mp_grow.${OBJEXT} \
bn_mp_init.${OBJEXT} \
bn_mp_init_copy.${OBJEXT} \
- bn_mp_init_i64.${OBJEXT} \
bn_mp_init_multi.${OBJEXT} \
bn_mp_init_set.${OBJEXT} \
+ bn_mp_init_set_int.${OBJEXT} \
bn_mp_init_size.${OBJEXT} \
- bn_mp_init_u64.${OBJEXT} \
+ bn_mp_karatsuba_mul.${OBJEXT} \
+ bn_mp_karatsuba_sqr.$(OBJEXT) \
bn_mp_lshd.${OBJEXT} \
bn_mp_mod.${OBJEXT} \
bn_mp_mod_2d.${OBJEXT} \
@@ -405,38 +330,29 @@ TOMMATH_OBJS = \
bn_mp_mul_d.${OBJEXT} \
bn_mp_neg.${OBJEXT} \
bn_mp_or.${OBJEXT} \
- bn_mp_pack.${OBJEXT} \
- bn_mp_pack_count.${OBJEXT} \
bn_mp_radix_size.${OBJEXT} \
bn_mp_radix_smap.${OBJEXT} \
bn_mp_read_radix.${OBJEXT} \
bn_mp_rshd.${OBJEXT} \
- bn_mp_set_i64.${OBJEXT} \
- bn_mp_set_u64.${OBJEXT} \
+ bn_mp_set.${OBJEXT} \
+ bn_mp_set_int.${OBJEXT} \
bn_mp_shrink.${OBJEXT} \
bn_mp_sqr.${OBJEXT} \
bn_mp_sqrt.${OBJEXT} \
bn_mp_sub.${OBJEXT} \
bn_mp_sub_d.${OBJEXT} \
- bn_mp_signed_rsh.${OBJEXT} \
- bn_mp_to_ubin.${OBJEXT} \
- bn_mp_to_radix.${OBJEXT} \
- bn_mp_ubin_size.${OBJEXT} \
- bn_mp_unpack.${OBJEXT} \
+ bn_mp_to_unsigned_bin.${OBJEXT} \
+ bn_mp_to_unsigned_bin_n.${OBJEXT} \
+ bn_mp_toom_mul.${OBJEXT} \
+ bn_mp_toom_sqr.${OBJEXT} \
+ bn_mp_toradix_n.${OBJEXT} \
+ bn_mp_unsigned_bin_size.${OBJEXT} \
bn_mp_xor.${OBJEXT} \
bn_mp_zero.${OBJEXT} \
bn_s_mp_add.${OBJEXT} \
- bn_s_mp_balance_mul.$(OBJEXT) \
- bn_s_mp_karatsuba_mul.${OBJEXT} \
- bn_s_mp_karatsuba_sqr.$(OBJEXT) \
bn_s_mp_mul_digs.${OBJEXT} \
- bn_s_mp_mul_digs_fast.${OBJEXT} \
- bn_s_mp_reverse.${OBJEXT} \
- bn_s_mp_sqr_fast.${OBJEXT} \
bn_s_mp_sqr.${OBJEXT} \
- bn_s_mp_sub.${OBJEXT} \
- bn_s_mp_toom_mul.${OBJEXT} \
- bn_s_mp_toom_sqr.${OBJEXT}
+ bn_s_mp_sub.${OBJEXT}
WIN_OBJS = \
@@ -455,108 +371,52 @@ WIN_OBJS = \
tclWinThrd.$(OBJEXT) \
tclWinTime.$(OBJEXT)
+PIPE_OBJS = stub16.$(OBJEXT)
+
DDE_OBJS = tclWinDde.$(OBJEXT)
REG_OBJS = tclWinReg.$(OBJEXT)
-STUB_OBJS = \
- tclStubLib.$(OBJEXT) \
- tclTomMathStubLib.$(OBJEXT) \
- tclOOStubLib.$(OBJEXT) \
- tclWinPanic.$(OBJEXT)
+STUB_OBJS = tclStubLib.$(OBJEXT)
TCLSH_OBJS = tclAppInit.$(OBJEXT)
-ZLIB_OBJS = \
- adler32.$(OBJEXT) \
- compress.$(OBJEXT) \
- crc32.$(OBJEXT) \
- deflate.$(OBJEXT) \
- infback.$(OBJEXT) \
- inffast.$(OBJEXT) \
- inflate.$(OBJEXT) \
- inftrees.$(OBJEXT) \
- trees.$(OBJEXT) \
- uncompr.$(OBJEXT) \
- zutil.$(OBJEXT)
-
-TCL_OBJS = ${GENERIC_OBJS} ${WIN_OBJS} @ZLIB_OBJS@ @TOMMATH_OBJS@
+TCL_OBJS = ${GENERIC_OBJS} $(TOMMATH_OBJS) ${WIN_OBJS}
TCL_DOCS = "$(ROOT_DIR_NATIVE)"/doc/*.[13n]
-all: binaries libraries doc packages
-
-# Test-suite helper (can be used to test Tcl from build directory with all expected modules).
-# To start from windows shell use:
-# > tcltest.cmd -verbose bps -file fileName.test
-# or from mingw/msys shell:
-# $ ./tcltest -verbose bps -file fileName.test
-
-tcltest.cmd: Makefile
- @echo 'Create tcltest.cmd helpers';
- @(\
- echo '@echo off'; \
- echo 'rem set LANG=en_US'; \
- echo 'set BDP=%~dp0'; \
- echo 'set OWD=%CD%'; \
- echo 'cd /d %TEMP%'; \
- echo 'rem "%BDP%\$(TCLSH)" "$(ROOT_DIR_WIN_NATIVE)/tests/all.tcl" %TESTFLAGS% -load "$(TEST_LOAD_FACILITIES)" %*'; \
- echo '"%BDP%\$(TEST_EXE_FILE)" "$(ROOT_DIR_WIN_NATIVE)/tests/all.tcl" %TESTFLAGS% -load "$(TEST_LOAD_PRMS)" %*'; \
- echo 'cd /d %OWD%'; \
- ) > tcltest.cmd;
- @(\
- echo '#!/bin/sh'; \
- echo '#LANG=en_US'; \
- echo 'BDP=$$(dirname $$(readlink -f %0))'; \
- echo 'cd /tmp'; \
- echo '#"$$BDP/$(TCLSH)" "$(ROOT_DIR_WIN_NATIVE)/tests/all.tcl" $$TESTFLAGS -load "$(TEST_LOAD_FACILITIES)" "$$@"'; \
- echo '"$$BDP/$(TEST_EXE_FILE)" "$(ROOT_DIR_WIN_NATIVE)/tests/all.tcl" $$TESTFLAGS -load "$(TEST_LOAD_PRMS)" "$$@"'; \
- ) > tcltest.sh;
-
-tcltest.sh: tcltest.cmd
-
-tcltest: binaries $(TEST_EXE_FILE) $(TEST_DLL_FILE) $(CAT32) tcltest.cmd
-
-binaries: $(TCL_STUB_LIB_FILE) @LIBRARIES@ winextensions ${TCL_ZIP_FILE} $(TCLSH)
+all: binaries libraries doc
-winextensions: ${DDE_DLL_FILE} ${REG_DLL_FILE}
+tcltest: $(TCLTEST)
+
+binaries: @LIBRARIES@ $(TCLSH)
libraries:
doc:
-tclzipfile: ${TCL_ZIP_FILE}
-
-${TCL_ZIP_FILE}: ${ZIP_INSTALL_OBJS} ${DDE_DLL_FILE} ${REG_DLL_FILE}
- @rm -rf ${TCL_VFS_ROOT}
- @mkdir -p ${TCL_VFS_PATH}
- @echo "creating ${TCL_VFS_PATH} (prepare compression)"
- @( \
- $(COPY) -a $(TOP_DIR)/library/* ${TCL_VFS_PATH}; \
- $(COPY) -a ${TCL_VFS_PATH}/manifest.txt ${TCL_VFS_PATH}/pkgIndex.tcl; \
- $(COPY) ${DDE_DLL_FILE} ${TCL_VFS_PATH}/dde; \
- $(COPY) ${REG_DLL_FILE} ${TCL_VFS_PATH}/registry; \
- )
- (zip=`(realpath '${NATIVE_ZIP}' || readlink -m '${NATIVE_ZIP}') 2>/dev/null || \
- (echo '${NATIVE_ZIP}' | sed "s?^\./?$$(pwd)/?")`; \
- cd ${TCL_VFS_ROOT} && \
- $$zip ${ZIP_PROG_OPTIONS} ../${TCL_ZIP_FILE} ${ZIP_PROG_VFSSEARCH} >/dev/null && \
- echo "${TCL_ZIP_FILE} successful created with $$zip" && \
- cd ..)
-
-$(TCLSH): $(TCLSH_OBJS) @LIBRARIES@ $(TCL_STUB_LIB_FILE) tclsh.$(RES) ${TCL_ZIP_FILE}
- $(CC) $(CFLAGS) $(TCLSH_OBJS) $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE) $(LIBS) \
- tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE)
- $(COPY) tclsh.exe.manifest $(TCLSH).manifest
+winhelp: $(ROOT_DIR)/tools/man2help.tcl $(MAN2TCL)
+ TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \
+ ./$(TCLSH) "$(ROOT_DIR_NATIVE)"/tools/man2help.tcl tcl "$(VER)" $(TCL_DOCS)
+ hcw /c /e tcl.hpj
+
+winextensions: ${DDE_DLL_FILE} ${REG_DLL_FILE}
+
+$(MAN2TCL): $(ROOT_DIR)/tools/man2tcl.c
+ $(CC) $(CFLAGS_OPTIMIZE) $(MAN2TCLFLAGS) -o $(MAN2TCL) "$(ROOT_DIR_NATIVE)"/tools/man2tcl.c
+
+$(TCLSH): $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE) $(TCLSH_OBJS) tclsh.$(RES)
+ $(CC) $(CFLAGS) $(TCLSH_OBJS) $(TCL_LIB_FILE) $(LIBS) \
+ tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE)
+ @VC_MANIFEST_EMBED_EXE@
+
+$(TCLTEST): $(TCL_LIB_FILE) $(TCLTEST_OBJS) $(CAT32) tclsh.$(RES)
+ $(CC) $(CFLAGS) $(TCLTEST_OBJS) $(TCL_LIB_FILE) $(LIBS) \
+ tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE)
@VC_MANIFEST_EMBED_EXE@
- @if test "${ZIPFS_BUILD}" = "2" ; then \
- cat ${TCL_ZIP_FILE} >> ${TCLSH}; \
- ${NATIVE_ZIP} -A ${TCLSH} \
- || echo 'ignore zip-error by adjust sfx process (not executable?)'; \
- fi
cat32.$(OBJEXT): cat.c
- $(CC) -c $(CC_SWITCHES) -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
+ $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME)
$(CAT32): cat32.$(OBJEXT)
$(CC) $(CFLAGS) cat32.$(OBJEXT) $(CC_EXENAME) $(LIBS) $(LDFLAGS_CONSOLE)
@@ -564,69 +424,42 @@ $(CAT32): cat32.$(OBJEXT)
# The following targets are configured by autoconf to generate either a shared
# library or static library
-${TCL_STUB_LIB_FILE}: ${STUB_OBJS} ${DDE_OBJS} ${REG_OBJS}
+${TCL_STUB_LIB_FILE}: ${STUB_OBJS}
@$(RM) ${TCL_STUB_LIB_FILE}
- @MAKE_STUB_LIB@ ${STUB_OBJS} ${DDE_OBJS} ${REG_OBJS}
+ @MAKE_STUB_LIB@ ${STUB_OBJS}
@POST_MAKE_LIB@
-${TCL_DLL_FILE}: ${TCL_OBJS} tcl.$(RES) @ZLIB_DLL_FILE@ @TOMMATH_DLL_FILE@ ${TCL_ZIP_FILE}
- @$(RM) ${TCL_DLL_FILE} $(TCL_LIB_FILE)
+${TCL_DLL_FILE}: ${TCL_OBJS} tcl.$(RES)
+ @$(RM) ${TCL_DLL_FILE}
@MAKE_DLL@ ${TCL_OBJS} tcl.$(RES) $(SHLIB_LD_LIBS)
- $(COPY) tclsh.exe.manifest ${TCL_DLL_FILE}.manifest
@VC_MANIFEST_EMBED_DLL@
- @if test "${ZIPFS_BUILD}" = "1" ; then \
- cat ${TCL_ZIP_FILE} >> ${TCL_DLL_FILE}; \
- ${NATIVE_ZIP} -A ${TCL_DLL_FILE} \
- || echo 'ignore zip-error by adjust sfx process (not executable?)'; \
- fi
-${TCL_LIB_FILE}: ${TCL_OBJS} tclWinPanic.$(OBJEXT) ${DDE_OBJS} ${REG_OBJS}
+${TCL_LIB_FILE}: ${TCL_OBJS}
@$(RM) ${TCL_LIB_FILE}
- @MAKE_LIB@ ${TCL_OBJS} tclWinPanic.$(OBJEXT) ${DDE_OBJS} ${REG_OBJS}
+ @MAKE_LIB@ ${TCL_OBJS}
@POST_MAKE_LIB@
-${DDE_DLL_FILE}: ${TCL_STUB_LIB_FILE} ${DDE_OBJS}
+${DDE_DLL_FILE}: ${DDE_OBJS} ${TCL_STUB_LIB_FILE}
+ @$(RM) ${DDE_DLL_FILE}
@MAKE_DLL@ ${DDE_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
- $(COPY) tclsh.exe.manifest ${DDE_DLL_FILE}.manifest
-${REG_DLL_FILE}: ${TCL_STUB_LIB_FILE} ${REG_OBJS}
+${DDE_LIB_FILE}: ${DDE_OBJS} ${TCL_LIB_FILE}
+ @$(RM) ${DDE_LIB_FILE}
+ @MAKE_LIB@ ${DDE_OBJS} ${TCL_LIB_FILE}
+
+${REG_DLL_FILE}: ${REG_OBJS} ${TCL_STUB_LIB_FILE}
+ @$(RM) ${REG_DLL_FILE}
@MAKE_DLL@ ${REG_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
- $(COPY) tclsh.exe.manifest ${REG_DLL_FILE}.manifest
-${TEST_DLL_FILE}: ${TCL_STUB_LIB_FILE} ${TCLTEST_OBJS}
- @$(RM) ${TEST_DLL_FILE} ${TEST_LIB_FILE}
- @MAKE_DLL@ ${TCLTEST_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
- $(COPY) tclsh.exe.manifest ${TEST_DLL_FILE}.manifest
+${REG_LIB_FILE}: ${REG_OBJS} ${TCL_LIB_FILE}
+ @$(RM) ${REG_LIB_FILE}
+ @MAKE_LIB@ ${REG_OBJS} ${TCL_LIB_FILE}
-${TEST_EXE_FILE}: ${TCL_STUB_LIB_FILE} ${TCLTEST_OBJS} tclTestMain.${OBJEXT}
- @$(RM) ${TEST_EXE_FILE}
- $(CC) $(CFLAGS) $(TCLTEST_OBJS) tclTestMain.$(OBJEXT) $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE) $(LIBS) \
- tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE)
- $(COPY) tclsh.exe.manifest ${TEST_EXE_FILE}.manifest
-
-# use prebuilt zlib1.dll
-${ZLIB_DLL_FILE}: ${TCL_STUB_LIB_FILE}
- @if test "@ZLIB_LIBS@set" = "${ZLIB_DIR_NATIVE}/win64-arm/zdll.libset" ; then \
- $(COPY) $(ZLIB_DIR)/win64-arm/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \
- elif test "@ZLIB_LIBS@set" = "${ZLIB_DIR_NATIVE}/win64-arm/libz.dll.aset" ; then \
- $(COPY) $(ZLIB_DIR)/win64-arm/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \
- elif test "@ZLIB_LIBS@set" = "${ZLIB_DIR_NATIVE}/win32/zdll.libset" ; then \
- $(COPY) $(ZLIB_DIR)/win32/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \
- else \
- $(COPY) $(ZLIB_DIR)/win64/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \
- fi;
-
-# use pre-built libtommath.dll
-${TOMMATH_DLL_FILE}: ${TCL_STUB_LIB_FILE}
- @if test "@TOMMATH_LIBS@set" = "${TOMMATH_DIR_NATIVE}/win64-arm/tommath.libset" ; then \
- $(COPY) $(TOMMATH_DIR)/win64-arm/${TOMMATH_DLL_FILE} ${TOMMATH_DLL_FILE}; \
- elif test "@TOMMATH_LIBS@set" = "${TOMMATH_DIR_NATIVE}/win64-arm/libtommath.dll.aset" ; then \
- $(COPY) $(TOMMATH_DIR)/win64-arm/${TOMMATH_DLL_FILE} ${TOMMATH_DLL_FILE}; \
- elif test "@TOMMATH_LIBS@set" = "${TOMMATH_DIR_NATIVE}/win32/tommath.libset" ; then \
- $(COPY) $(TOMMATH_DIR)/win32/${TOMMATH_DLL_FILE} ${TOMMATH_DLL_FILE}; \
- else \
- $(COPY) $(TOMMATH_DIR)/win64/${TOMMATH_DLL_FILE} ${TOMMATH_DLL_FILE}; \
- fi;
+# PIPE_DLL_FILE is actually an executable, don't build it like a DLL.
+
+${PIPE_DLL_FILE}: ${PIPE_OBJS}
+ @$(RM) ${PIPE_DLL_FILE}
+ @MAKE_EXE@ $(CFLAGS) ${PIPE_OBJS} $(LIBS) $(LDFLAGS_CONSOLE)
# Add the object extension to the implicit rules. By default .obj is not
# automatically added.
@@ -637,32 +470,35 @@ ${TOMMATH_DLL_FILE}: ${TCL_STUB_LIB_FILE}
# Special case object targets
-tclTestMain.${OBJEXT}: tclAppInit.c
- $(CC) -c $(CC_SWITCHES) -DTCL_TEST -DUNICODE -D_UNICODE $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
-
tclWinInit.${OBJEXT}: tclWinInit.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclWinPipe.${OBJEXT}: tclWinPipe.c
- $(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
+ $(CC) -c $(CC_SWITCHES) -DBUILD_tcl -DTCL_PIPE_DLL=\"$(PIPE_DLL_FILE)\" \
+ $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
-tclWinReg.${OBJEXT}: tclWinReg.c
- $(CC) -c $(CC_SWITCHES) $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
+testMain.${OBJEXT}: tclAppInit.c
+ $(CC) -c $(CC_SWITCHES) -DTCL_TEST @DEPARG@ $(CC_OBJNAME)
-tclWinDde.${OBJEXT}: tclWinDde.c
- $(CC) -c $(CC_SWITCHES) $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
+tclTest.${OBJEXT}: tclTest.c
+ $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME)
-tclAppInit.${OBJEXT}: tclAppInit.c
- $(CC) -c $(CC_SWITCHES) $(EXTFLAGS) -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
+tclTestObj.${OBJEXT}: tclTestObj.c
+ $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME)
-tclMainW.${OBJEXT}: tclMain.c
- $(CC) -c $(CC_SWITCHES) -DBUILD_tcl -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
+tclWinTest.${OBJEXT}: tclWinTest.c
+ $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME)
-# TIP #430, ZipFS Support
-tclZipfs.${OBJEXT}: $(GENERIC_DIR)/tclZipfs.c
- $(CC) -c $(CC_SWITCHES) -DBUILD_tcl \
- $(ZLIB_INCLUDE) -I$(MINIZIP_DIR_NATIVE) @DEPARG@ $(CC_OBJNAME)
+tclAppInit.${OBJEXT} : tclAppInit.c
+ $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME)
+# The following objects should be built using the stub interfaces
+
+tclWinReg.${OBJEXT} : tclWinReg.c
+ $(CC) -c $(CC_SWITCHES) -DUSE_TCL_STUBS @DEPARG@ $(CC_OBJNAME)
+
+tclWinDde.${OBJEXT} : tclWinDde.c
+ $(CC) -c $(CC_SWITCHES) -DUSE_TCL_STUBS @DEPARG@ $(CC_OBJNAME)
# TIP #59, embedding of configuration information into the binary library.
#
@@ -674,52 +510,27 @@ tclZipfs.${OBJEXT}: $(GENERIC_DIR)/tclZipfs.c
tclPkgConfig.${OBJEXT}: tclPkgConfig.c
$(CC) -c $(CC_SWITCHES) \
- -DCFG_INSTALL_LIBDIR="\"$(LIB_INSTALL_DIR_NATIVE)\"" \
- -DCFG_INSTALL_BINDIR="\"$(BIN_INSTALL_DIR_NATIVE)\"" \
- -DCFG_INSTALL_SCRDIR="\"$(SCRIPT_INSTALL_DIR_NATIVE)\"" \
- -DCFG_INSTALL_INCDIR="\"$(INCLUDE_INSTALL_DIR_NATIVE)\"" \
- -DCFG_INSTALL_DOCDIR="\"$(MAN_INSTALL_DIR_NATIVE)\"" \
+ -DCFG_INSTALL_LIBDIR=\"$(LIB_INSTALL_DIR_NATIVE)\" \
+ -DCFG_INSTALL_BINDIR=\"$(BIN_INSTALL_DIR_NATIVE)\" \
+ -DCFG_INSTALL_SCRDIR=\"$(SCRIPT_INSTALL_DIR_NATIVE)\" \
+ -DCFG_INSTALL_INCDIR=\"$(INCLUDE_INSTALL_DIR_NATIVE)\" \
+ -DCFG_INSTALL_DOCDIR=\"$(MAN_INSTALL_DIR)\" \
\
- -DCFG_RUNTIME_LIBDIR="\"$(libdir_native)\"" \
- -DCFG_RUNTIME_BINDIR="\"$(bindir_native)\"" \
- -DCFG_RUNTIME_SCRDIR="\"$(TCL_LIBRARY_NATIVE)\"" \
- -DCFG_RUNTIME_INCDIR="\"$(includedir_native)\"" \
- -DCFG_RUNTIME_DOCDIR="\"$(mandir_native)\"" \
- -DCFG_RUNTIME_DLLFILE="\"$(TCL_DLL_FILE)\"" \
+ -DCFG_RUNTIME_LIBDIR=\"$(libdir_native)\" \
+ -DCFG_RUNTIME_BINDIR=\"$(bindir_native)\" \
+ -DCFG_RUNTIME_SCRDIR=\"$(TCL_LIBRARY_NATIVE)\" \
+ -DCFG_RUNTIME_INCDIR=\"$(includedir_native)\" \
+ -DCFG_RUNTIME_DOCDIR=\"$(mandir_native)\" \
-DBUILD_tcl \
@DEPARG@ $(CC_OBJNAME)
-tclEvent.${OBJEXT}: tclEvent.c tclUuid.h
-
-tclTest.${OBJEXT}: tclTest.c tclUuid.h
-
-$(TOP_DIR)/manifest.uuid:
- printf "git-" >$(TOP_DIR)/manifest.uuid
- (cd $(TOP_DIR); git rev-parse HEAD >>$(TOP_DIR)/manifest.uuid || \
- (printf "svn-r" >$(TOP_DIR)/manifest.uuid ; \
- svn info --show-item last-changed-revision >>$(TOP_DIR)/manifest.uuid) || \
- printf "unknown" >$(TOP_DIR)/manifest.uuid)
-
-tclUuid.h: $(TOP_DIR)/manifest.uuid
- echo "#define TCL_VERSION_UUID \\" >$@
- cat $(TOP_DIR)/manifest.uuid >>$@
- echo "" >>$@
-
# The following objects are part of the stub library and should not be built
# as DLL objects but none of the symbols should be exported
tclStubLib.${OBJEXT}: tclStubLib.c
- $(CC) -c $(CC_SWITCHES) -DSTATIC_BUILD @CFLAGS_NOLTO@ @DEPARG@ $(CC_OBJNAME)
-
-tclTomMathStubLib.${OBJEXT}: tclTomMathStubLib.c
- $(CC) -c $(CC_SWITCHES) @CFLAGS_NOLTO@ @DEPARG@ $(CC_OBJNAME)
-
-tclOOStubLib.${OBJEXT}: tclOOStubLib.c
- $(CC) -c $(CC_SWITCHES) @CFLAGS_NOLTO@ @DEPARG@ $(CC_OBJNAME)
-
-tclWinPanic.${OBJEXT}: tclWinPanic.c
$(CC) -c $(CC_SWITCHES) -DSTATIC_BUILD @DEPARG@ $(CC_OBJNAME)
+
# Implicit rule for all object files that will end up in the Tcl library
%.${OBJEXT}: %.c
@@ -728,59 +539,6 @@ tclWinPanic.${OBJEXT}: tclWinPanic.c
.rc.$(RES):
$(RC) @RC_OUT@ $@ @RC_TYPE@ @RC_DEFINES@ @RC_INCLUDE@ "$(GENERIC_DIR_NATIVE)" @RC_INCLUDE@ "$(WIN_DIR_NATIVE)" @DEPARG@
-
-
-#--------------------------------------------------------------------------
-# Minizip implementation
-#--------------------------------------------------------------------------
-adler32.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/adler32.c
-
-compress.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/compress.c
-
-crc32.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/crc32.c
-
-deflate.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/deflate.c
-
-ioapi.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -I$(ZLIB_DIR)/contrib/minizip -c $(ZLIB_DIR)/contrib/minizip/ioapi.c
-
-iowin32.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -I$(ZLIB_DIR)/contrib/minizip -c $(ZLIB_DIR)/contrib/minizip/iowin32.c
-
-infback.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/infback.c
-
-inffast.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/inffast.c
-
-inflate.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/inflate.c
-
-inftrees.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/inftrees.c
-
-trees.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/trees.c
-
-uncompr.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/uncompr.c
-
-zip.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -I$(ZLIB_DIR)/contrib/minizip -c $(ZLIB_DIR)/contrib/minizip/zip.c
-
-zutil.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -c $(ZLIB_DIR)/zutil.c
-
-minizip.$(HOST_OBJEXT):
- $(HOST_CC) -o $@ -I$(ZLIB_DIR) -I$(ZLIB_DIR)/contrib/minizip -c $(ZLIB_DIR)/contrib/minizip/minizip.c
-
-minizip${HOST_EXEEXT}: $(MINIZIP_OBJS)
- $(HOST_CC) -o $@ $(MINIZIP_OBJS)
-
# The following target generates the file generic/tclDate.c from the yacc
# grammar found in generic/tclGetDate.y. This is only run by hand as yacc is
# not available in all environments. The name of the .c file is different than
@@ -793,42 +551,42 @@ gendate:
--no-lines \
$(GENERIC_DIR)/tclGetDate.y
-INSTALL_BASE_TARGETS = install-binaries $(INSTALL_LIBRARIES) $(INSTALL_MSGS) $(INSTALL_TZDATA)
-INSTALL_DOC_TARGETS = install-doc
-INSTALL_PACKAGE_TARGETS = install-packages
-INSTALL_DEV_TARGETS = install-headers
-INSTALL_EXTRA_TARGETS =
-INSTALL_TARGETS = $(INSTALL_BASE_TARGETS) $(INSTALL_DOC_TARGETS) $(INSTALL_DEV_TARGETS) \
- $(INSTALL_PACKAGE_TARGETS) $(INSTALL_EXTRA_TARGETS)
+# The following target generates the file generic/tclTomMath.h. It needs to be
+# run (and the results checked) after updating to a new release of libtommath.
+
+gentommath_h:
+ $(TCL_EXE) "$(ROOT_DIR_NATIVE)\tools\fix_tommath_h.tcl" \
+ "$(TOMMATH_DIR_NATIVE)\tommath.h" \
+ > "$(GENERIC_DIR_NATIVE)\tclTomMath.h"
-install: $(INSTALL_TARGETS)
+install: all install-binaries install-libraries install-doc
install-binaries: binaries
- @for i in "$(LIB_INSTALL_DIR)" "$(BIN_INSTALL_DIR)"; \
+ @for i in "$(LIB_INSTALL_DIR)" "$(BIN_INSTALL_DIR)" ; \
do \
- if [ ! -d "$$i" ] ; then \
+ if [ ! -d $$i ] ; then \
echo "Making directory $$i"; \
- $(MKDIR) "$$i"; \
- chmod 755 "$$i"; \
+ $(MKDIR) $$i; \
+ chmod 755 $$i; \
else true; \
fi; \
done;
- @for i in dde${DDEDOTVER} registry${REGDOTVER}; \
+ @for i in dde$(DDEDOTVER) reg$(REGDOTVER); \
do \
- if [ ! -d "$(LIB_INSTALL_DIR)/$$i" ] ; then \
+ if [ ! -d $(LIB_INSTALL_DIR)/$$i ] ; then \
echo "Making directory $(LIB_INSTALL_DIR)/$$i"; \
- $(MKDIR) "$(LIB_INSTALL_DIR)/$$i"; \
+ $(MKDIR) $(LIB_INSTALL_DIR)/$$i; \
else true; \
fi; \
done;
- @for i in $(TCL_DLL_FILE) $(ZLIB_DLL_FILE) $(TOMMATH_DLL_FILE) $(TCLSH); \
+ @for i in $(TCL_DLL_FILE) $(TCLSH) $(PIPE_DLL_FILE); \
do \
if [ -f $$i ]; then \
echo "Installing $$i to $(BIN_INSTALL_DIR)/"; \
$(COPY) $$i "$(BIN_INSTALL_DIR)"; \
fi; \
done
- @for i in tclConfig.sh tclooConfig.sh $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE) @ZLIB_LIBS@ @TOMMATH_LIBS@; \
+ @for i in tclConfig.sh $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE); \
do \
if [ -f $$i ]; then \
echo "Installing $$i to $(LIB_INSTALL_DIR)/"; \
@@ -837,74 +595,76 @@ install-binaries: binaries
done
@if [ -f $(DDE_DLL_FILE) ]; then \
echo Installing $(DDE_DLL_FILE); \
- $(COPY) $(DDE_DLL_FILE) "$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
+ $(COPY) $(DDE_DLL_FILE) $(LIB_INSTALL_DIR)/dde$(DDEDOTVER); \
$(COPY) $(ROOT_DIR)/library/dde/pkgIndex.tcl \
- "$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
+ $(LIB_INSTALL_DIR)/dde$(DDEDOTVER); \
fi
@if [ -f $(DDE_LIB_FILE) ]; then \
echo Installing $(DDE_LIB_FILE); \
- $(COPY) $(DDE_LIB_FILE) "$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
+ $(COPY) $(DDE_LIB_FILE) $(LIB_INSTALL_DIR)/dde$(DDEDOTVER); \
fi
@if [ -f $(REG_DLL_FILE) ]; then \
echo Installing $(REG_DLL_FILE); \
- $(COPY) $(REG_DLL_FILE) "$(LIB_INSTALL_DIR)/registry${REGDOTVER}"; \
- $(COPY) $(ROOT_DIR)/library/registry/pkgIndex.tcl \
- "$(LIB_INSTALL_DIR)/registry${REGDOTVER}"; \
+ $(COPY) $(REG_DLL_FILE) $(LIB_INSTALL_DIR)/reg$(REGDOTVER); \
+ $(COPY) $(ROOT_DIR)/library/reg/pkgIndex.tcl \
+ $(LIB_INSTALL_DIR)/reg$(REGDOTVER); \
fi
@if [ -f $(REG_LIB_FILE) ]; then \
echo Installing $(REG_LIB_FILE); \
- $(COPY) $(REG_LIB_FILE) "$(LIB_INSTALL_DIR)/registry${REGDOTVER}"; \
+ $(COPY) $(REG_LIB_FILE) $(LIB_INSTALL_DIR)/reg$(REGDOTVER); \
fi
install-libraries: libraries install-tzdata install-msgs
- @for i in "$(prefix)/lib" "$(INCLUDE_INSTALL_DIR)" \
- "$(SCRIPT_INSTALL_DIR)" "$(MODULE_INSTALL_DIR)"; \
+ @for i in $(prefix)/lib $(INCLUDE_INSTALL_DIR) \
+ $(SCRIPT_INSTALL_DIR); \
do \
- if [ ! -d "$$i" ] ; then \
+ if [ ! -d $$i ] ; then \
echo "Making directory $$i"; \
- $(MKDIR) "$$i"; \
+ $(MKDIR) $$i; \
else true; \
fi; \
done;
- @for i in opt0.4 cookiejar0.2 encoding; \
+ @for i in http1.0 opt0.4 encoding ../tcl8 ../tcl8/8.4 ../tcl8/8.4/platform ../tcl8/8.5; \
do \
- if [ ! -d "$(SCRIPT_INSTALL_DIR)/$$i" ] ; then \
+ if [ ! -d $(SCRIPT_INSTALL_DIR)/$$i ] ; then \
echo "Making directory $(SCRIPT_INSTALL_DIR)/$$i"; \
- $(MKDIR) "$(SCRIPT_INSTALL_DIR)/$$i"; \
+ $(MKDIR) $(SCRIPT_INSTALL_DIR)/$$i; \
else true; \
fi; \
done;
- @for i in 8.4 8.4/platform 8.5 8.6 8.7; \
+ @echo "Installing header files";
+ @for i in "$(GENERIC_DIR)/tcl.h" "$(GENERIC_DIR)/tclDecls.h" \
+ "$(GENERIC_DIR)/tclPlatDecls.h" \
+ "$(GENERIC_DIR)/tclTomMath.h" \
+ "$(GENERIC_DIR)/tclTomMathDecls.h"; \
do \
- if [ ! -d "$(MODULE_INSTALL_DIR)/$$i" ] ; then \
- echo "Making directory $(MODULE_INSTALL_DIR)/$$i"; \
- $(MKDIR) "$(MODULE_INSTALL_DIR)/$$i"; \
- else true; \
- fi; \
+ $(COPY) "$$i" "$(INCLUDE_INSTALL_DIR)"; \
done;
@echo "Installing library files to $(SCRIPT_INSTALL_DIR)";
- @for i in $(ROOT_DIR)/library/*.tcl $(ROOT_DIR)/library/tclIndex; do \
+ @for i in $(ROOT_DIR)/library/*.tcl $(ROOT_DIR)/library/tclIndex; \
+ do \
$(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)"; \
done;
- @echo "Installing package cookiejar 0.2"
- @for j in $(ROOT_DIR)/library/cookiejar/*.tcl \
- $(ROOT_DIR)/library/cookiejar/*.gz; do \
- $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/cookiejar0.2"; \
+ @echo "Installing library http1.0 directory";
+ @for j in $(ROOT_DIR)/library/http1.0/*.tcl; \
+ do \
+ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http1.0"; \
done;
- @echo "Installing package http 2.10b2 as a Tcl Module";
- @$(COPY) $(ROOT_DIR)/library/http/http.tcl "$(MODULE_INSTALL_DIR)/8.6/http-2.10b2.tm";
- @echo "Installing package opt 0.4.7";
- @for j in $(ROOT_DIR)/library/opt/*.tcl; do \
+ @echo "Installing package http 2.7.13 as a Tcl Module";
+ @$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/http-2.7.13.tm;
+ @echo "Installing library opt0.4 directory";
+ @for j in $(ROOT_DIR)/library/opt/*.tcl; \
+ do \
$(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/opt0.4"; \
done;
- @echo "Installing package msgcat 1.7.1 as a Tcl Module";
- @$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl "$(MODULE_INSTALL_DIR)/8.7/msgcat-1.7.1.tm";
- @echo "Installing package tcltest 2.5.8 as a Tcl Module";
- @$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl "$(MODULE_INSTALL_DIR)/8.5/tcltest-2.5.8.tm";
- @echo "Installing package platform 1.0.19 as a Tcl Module";
- @$(COPY) $(ROOT_DIR)/library/platform/platform.tcl "$(MODULE_INSTALL_DIR)/8.4/platform-1.0.19.tm";
+ @echo "Installing package msgcat 1.5.2 as a Tcl Module";
+ @$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.5.2.tm;
+ @echo "Installing package tcltest 2.3.8 as a Tcl Module";
+ @$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/tcltest-2.3.8.tm;
+ @echo "Installing package platform 1.0.14 as a Tcl Module";
+ @$(COPY) $(ROOT_DIR)/library/platform/platform.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/platform-1.0.14.tm;
@echo "Installing package platform::shell 1.1.4 as a Tcl Module";
- @$(COPY) $(ROOT_DIR)/library/platform/shell.tcl "$(MODULE_INSTALL_DIR)/8.4/platform/shell-1.1.4.tm";
+ @$(COPY) $(ROOT_DIR)/library/platform/shell.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/platform/shell-1.1.4.tm;
@echo "Installing encodings";
@for i in $(ROOT_DIR)/library/encoding/*.enc ; do \
$(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)/encoding"; \
@@ -912,37 +672,18 @@ install-libraries: libraries install-tzdata install-msgs
install-tzdata:
@echo "Installing time zone data"
- @$(TCL_EXE) "$(ROOT_DIR)/tools/installData.tcl" \
- "$(ROOT_DIR)/library/tzdata" "$(SCRIPT_INSTALL_DIR_NATIVE)/tzdata"
+ @TCL_LIBRARY="${LIBRARY_DIR}"; export TCL_LIBRARY; \
+ ./$(TCLSH) "$(ROOT_DIR)/tools/installData.tcl" \
+ "$(ROOT_DIR)/library/tzdata" "$(SCRIPT_INSTALL_DIR)/tzdata"
install-msgs:
@echo "Installing message catalogs"
- $(TCL_EXE) "$(ROOT_DIR)/tools/installData.tcl" \
- "$(ROOT_DIR)/library/msgs" "$(SCRIPT_INSTALL_DIR_NATIVE)/msgs"
+ @TCL_LIBRARY="${LIBRARY_DIR}"; export TCL_LIBRARY; \
+ ./$(TCLSH) "$(ROOT_DIR)/tools/installData.tcl" \
+ "$(ROOT_DIR)/library/msgs" "$(SCRIPT_INSTALL_DIR)/msgs"
install-doc: doc
-install-headers:
- @for i in "$(INCLUDE_INSTALL_DIR)"; \
- do \
- if [ ! -d "$$i" ] ; then \
- echo "Making directory $$i"; \
- $(MKDIR) "$$i"; \
- chmod 755 "$$i"; \
- else true; \
- fi; \
- done;
- @echo "Installing header files to $(INCLUDE_INSTALL_DIR)/";
- @for i in $(GENERIC_DIR)/tcl.h $(GENERIC_DIR)/tclDecls.h \
- $(GENERIC_DIR)/tclOO.h $(GENERIC_DIR)/tclOODecls.h \
- $(GENERIC_DIR)/tclPlatDecls.h \
- $(GENERIC_DIR)/tclTomMath.h \
- $(GENERIC_DIR)/tclTomMathDecls.h \
- $(TOMMATH_DIR)/tommath.h ; \
- do \
- $(COPY) $$i "$(INCLUDE_INSTALL_DIR)"; \
- done;
-
# Optional target to install private headers
install-private-headers: libraries
@for i in $(PRIVATE_INCLUDE_INSTALL_DIR); \
@@ -956,7 +697,6 @@ install-private-headers: libraries
@echo "Installing private header files";
@for i in "$(GENERIC_DIR)/tclInt.h" "$(GENERIC_DIR)/tclIntDecls.h" \
"$(GENERIC_DIR)/tclIntPlatDecls.h" "$(GENERIC_DIR)/tclPort.h" \
- "$(GENERIC_DIR)/tclOOInt.h" "$(GENERIC_DIR)/tclOOIntDecls.h" \
"$(WIN_DIR)/tclWinPort.h" ; \
do \
$(COPY) "$$i" "$(PRIVATE_INCLUDE_INSTALL_DIR)"; \
@@ -966,23 +706,23 @@ install-private-headers: libraries
# tcltest, i.e.:
# % make test TESTFLAGS="-verbose bps -file fileName.test"
-test: test-tcl test-packages
-
-test-tcl: tcltest
+test: binaries $(TCLTEST)
TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \
- $(WINE) ./$(TCLSH) "$(ROOT_DIR_NATIVE)/tests/all.tcl" $(TESTFLAGS) \
- -load "$(TEST_LOAD_FACILITIES)"
+ ./$(TCLTEST) "$(ROOT_DIR_NATIVE)/tests/all.tcl" $(TESTFLAGS) \
+ -load "package ifneeded dde 1.3.3 [list load [file normalize ${DDE_DLL_FILE}] dde]; \
+ package ifneeded registry 1.2.2 [list load [file normalize ${REG_DLL_FILE}] registry]" | ./$(CAT32)
-# Useful target to launch a built tclsh with the proper path,...
-runtest: tcltest
+# Useful target to launch a built tcltest with the proper path,...
+runtest: binaries $(TCLTEST)
@TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \
- $(WINE) ./$(TCLSH) $(TESTFLAGS) -load "$(TEST_LOAD_FACILITIES)" $(SCRIPT)
+ ./$(TCLTEST) $(TESTFLAGS) -load "package ifneeded dde 1.3.3 [list load [file normalize ${DDE_DLL_FILE}] dde]; \
+ package ifneeded registry 1.2.2 [list load [file normalize ${REG_DLL_FILE}] registry]" $(SCRIPT)
# This target can be used to run tclsh from the build directory via
# `make shell SCRIPT=foo.tcl`
shell: binaries
@TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \
- $(WINE) ./$(TCLSH) -encoding utf-8 $(SCRIPT)
+ ./$(TCLSH) $(SCRIPT)
# This target can be used to run tclsh inside either gdb or insight
gdb: binaries
@@ -996,96 +736,16 @@ Makefile: $(SRC_DIR)/Makefile.in
./config.status
cleanhelp:
- $(RM) *.hlp *.cnt *.GID
+ $(RM) *.hlp *.cnt *.GID *.rtf man2tcl.exe
-clean: cleanhelp clean-packages
+clean: cleanhelp
$(RM) *.lib *.a *.exp *.dll *.$(RES) *.${OBJEXT} *~ \#* TAGS a.out
- $(RM) $(TCLSH) $(CAT32) $(TEST_EXE_FILE) $(TEST_DLL_FILE) tcltest.cmd tcltest.sh
- $(RM) *.pch *.ilk *.pdb *.zip
- $(RM) minizip${HOST_EXEEXT} *.${HOST_OBJEXT}
- $(RMDIR) *.vfs
+ $(RM) $(TCLSH) $(TCLTEST) $(CAT32)
+ $(RM) *.pch *.ilk *.pdb
-distclean: distclean-packages clean
+distclean: clean
$(RM) Makefile config.status config.cache config.log tclConfig.sh \
- config.status.lineno tclsh.exe.manifest tclUuid.h
-
-#
-# Bundled package targets
-#
-
-PKG_CFG_ARGS = @PKG_CFG_ARGS@
-PKG_DIR = ./pkgs
-
-packages:
- @builddir=`$(CYGPATH) $$(pwd -P)`; \
- for i in $(PKGS_DIR)/*; do \
- if [ -d $$i ] ; then \
- if [ -x $$i/configure ] ; then \
- pkg=`basename $$i`; \
- mkdir -p $(PKG_DIR)/$$pkg; \
- if [ ! -f $(PKG_DIR)/$$pkg/Makefile ]; then \
- ( cd $(PKG_DIR)/$$pkg; \
- echo "Configuring package '$$i' wd = `$(CYGPATH) $$(pwd -P)`"; \
- $$i/configure --with-tcl=$$builddir --with-tclinclude=$(GENERIC_DIR_NATIVE) $(PKG_CFG_ARGS) --enable-shared; ) \
- fi ; \
- echo "Building package '$$pkg'"; \
- ( cd $(PKG_DIR)/$$pkg; $(MAKE); ) \
- fi; \
- fi; \
- done; \
- cd $$builddir
-
-install-packages: packages
- @builddir=`pwd -P`; \
- for i in $(PKGS_DIR)/*; do \
- if [ -d $$i ]; then \
- pkg=`basename $$i`; \
- if [ -f $(PKG_DIR)/$$pkg/Makefile ]; then \
- echo "Installing package '$$pkg'"; \
- ( cd $(PKG_DIR)/$$pkg; $(MAKE) install "DESTDIR=$(INSTALL_ROOT)"; ) \
- fi; \
- fi; \
- done; \
- cd $$builddir
-
-test-packages: tcltest packages
- @builddir=`pwd -P`; \
- for i in $(PKGS_DIR)/*; do \
- if [ -d $$i ]; then \
- pkg=`basename $$i`; \
- if [ -f $(PKG_DIR)/$$pkg/Makefile ]; then \
- echo "Testing package '$$pkg'"; \
- ( cd $(PKG_DIR)/$$pkg; $(MAKE) "LD_LIBRARY_PATH=$$builddir:${LD_LIBRARY_PATH}" "TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" "TCLLIBPATH=$$builddir/pkgs" test "TCLSH_PROG=$$builddir/${TCLSH}"; ) \
- fi; \
- fi; \
- done; \
- cd $$builddir
-
-clean-packages:
- @builddir=`pwd -P`; \
- for i in $(PKGS_DIR)/*; do \
- if [ -d $$i ]; then \
- pkg=`basename $$i`; \
- if [ -f $(PKG_DIR)/$$pkg/Makefile ]; then \
- ( cd $(PKG_DIR)/$$pkg; $(MAKE) clean; ) \
- fi; \
- fi; \
- done; \
- cd $$builddir
-
-distclean-packages:
- @builddir=`pwd -P`; \
- for i in $(PKGS_DIR)/*; do \
- if [ -d $$i ]; then \
- pkg=`basename $$i`; \
- if [ -f $(PKG_DIR)/$$pkg/Makefile ]; then \
- ( cd $(PKG_DIR)/$$pkg; $(MAKE) distclean; ) \
- fi; \
- cd $$builddir; \
- rm -rf $(PKG_DIR)/$$pkg; \
- fi; \
- done; \
- rm -rf $(PKG_DIR)
+ tcl.hpj config.status.lineno
#
# Regenerate the stubs files.
@@ -1101,29 +761,8 @@ genstubs:
$(TCL_EXE) "$(ROOT_DIR_NATIVE)/tools/genStubs.tcl" \
"$(GENERIC_DIR_NATIVE)" \
"$(GENERIC_DIR_NATIVE)/tcl.decls" \
- "$(GENERIC_DIR_NATIVE)/tclInt.decls" \
+ "$(GENERIC_DIR_NATIVE)/tclInt.decls" \
"$(GENERIC_DIR_NATIVE)/tclTomMath.decls"
- $(TCL_EXE) "$(ROOT_DIR_NATIVE)/tools/genStubs.tcl" \
- "$(GENERIC_DIR_NATIVE)" \
- "$(GENERIC_DIR_NATIVE)/tclOO.decls"
-
-#
-# This target creates the HTML folder for Tcl & Tk and places it in
-# DISTDIR/html. It uses the tcltk-man2html.tcl tool from the Tcl group's tool
-# workspace. It depends on the Tcl & Tk being in directories called tcl8.* &
-# tk8.* up two directories from the TOOL_DIR.
-#
-
-TOOL_DIR=$(ROOT_DIR)/tools
-HTML_INSTALL_DIR=$(ROOT_DIR)/html
-html:
- $(MAKE) shell SCRIPT="$(TOOL_DIR)/tcltk-man2html.tcl --htmldir=$(HTML_INSTALL_DIR) --srcdir=$(ROOT_DIR)/.. $(BUILD_HTML_FLAGS)"
-
-html-tcl: $(TCLSH)
- $(MAKE) shell SCRIPT="$(TOOL_DIR)/tcltk-man2html.tcl --htmldir=$(HTML_INSTALL_DIR) --srcdir=$(ROOT_DIR)/.. $(BUILD_HTML_FLAGS) --tcl"
-
-html-tk: $(TCLSH)
- $(MAKE) shell SCRIPT="$(TOOL_DIR)/tcltk-man2html.tcl --htmldir=$(HTML_INSTALL_DIR) --srcdir=$(ROOT_DIR)/.. $(BUILD_HTML_FLAGS) --tk"
#
# The list of all the targets that do not correspond to real files. This stops
@@ -1136,6 +775,5 @@ html-tk: $(TCLSH)
.PHONY: gdb depend cleanhelp clean distclean packages install-packages
.PHONY: test-packages clean-packages distclean-packages genstubs html
.PHONY: html-tcl html-tk
-.PHONY: tclzipfile
# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/win/README b/win/README
index 3cfcc15..8288e3d 100644
--- a/win/README
+++ b/win/README
@@ -1,4 +1,4 @@
-Tcl 8.7 for Windows
+Tcl 8.5 for Windows
1. Introduction
---------------
@@ -9,43 +9,43 @@ that are specific to Microsoft Windows.
The information in this file is maintained on the web at:
- https://www.tcl-lang.org/doc/howto/compile.html#win
+ http://www.tcl.tk/doc/howto/compile.html#win
2. Compiling Tcl
----------------
In order to compile Tcl for Windows, you need the following:
- Tcl 8.7 Source Distribution (plus any patches)
+ Tcl 8.5 Source Distribution (plus any patches)
and
- Visual Studio 2015 or newer
+ Visual C++ 6 or newer
or
- Linux + MinGW-w64 [https://www.mingw-w64.org/]
+ Linux + MinGW-w64 [http://mingw-w64.sourceforge.net/]
(win32 or win64)
or
- Cygwin + MinGW-w64 [https://cygwin.com/install.html]
+ Cygwin + MinGW-w64 [http://cygwin.com/install.html]
(win32 or win64)
or
- Darwin + MinGW-w64 [https://www.mingw-w64.org/]
+ Darwin + MinGW-w64 [http://mingw-w64.sourceforge.net/]
(win32 or win64)
or
- Msys + MinGW-w64 [https://www.mingw-w64.org/]
+ Msys + MinGW-w64 [http://mingw-w64.sourceforge.net/]
(win32 or win64)
or
- LLVM MinGW [https://github.com/mstorsjo/llvm-mingw/]
- (win32 or win64, IX86, AMD64 or ARM64)
+ Msys + MinGW [http://www.mingw.org/download.shtml]
+ (win32 only)
In practice, this release is built with Visual C++ 6.0 and the TEA
@@ -67,9 +67,8 @@ configure/build process works just like the UNIX one, so you will want
to refer to ../unix/README for available configure options.
If you want 64-bit executables (x86_64), you need to configure using
-the --enable-64bit (or --enable-64bit=arm64) option. Make sure that
-the x86_64-w64-mingw32 (or aarch64-w64-mingw32) compiler is present.
-For Cygwin the x86_64 compiler can be found in the
+the --enable-64bit option. Make sure that the x86_64-w64-mingw32
+compiler is present. For Cygwin this compiler can be found in the
"mingw64-x86_64-gcc-core" package, which can be installed through
the normal Cygwin install process. If you only want 32-bit executables,
the "mingw64-i686-gcc-core" package is what you need. For Linux, Darwin
@@ -80,13 +79,11 @@ Use the Makefile "install" target to install Tcl. It will install it
according to the prefix options you provided in the correct directory
structure.
-Note that in order to run tclsh87.exe, you must ensure that tcl87.dll,
-libtommath.dll and zlib1.dll are on your path, in the system
-directory, or in the directory containing tclsh87.exe.
+Note that in order to run tclsh85.exe, you must ensure that tcl85.dll is
+on your path, in the system directory, or in the directory containing
+tclsh85.exe.
-Note: Tcl no longer provides support for systems earlier than Windows 7.
-You will also need the Windows Universal C runtime (UCRT):
- [https://support.microsoft.com/en-us/topic/update-for-universal-c-runtime-in-windows-c0514201-7fe6-95a3-b0a5-287930f3560c]
+Note: Tcl no longer provides support for Win32s.
3. Test suite
-------------
@@ -96,7 +93,7 @@ tests are timing dependent and will fail from time to time. If a test is
failing consistently, please send us a bug report with as much detail as
you can manage to our tracker:
- https://core.tcl-lang.org/tcl/reportlist
+ http://core.tcl.tk/tcl/reportlist
In order to run the test suite, you build the "test" target using the
appropriate makefile for your compiler.
diff --git a/win/buildall.vc.bat b/win/buildall.vc.bat
index 941f27e..1a0f36d 100755..100644
--- a/win/buildall.vc.bat
+++ b/win/buildall.vc.bat
@@ -38,9 +38,7 @@ if defined WINDOWSSDKDIR (goto :startBuilding)
:: might not be correct. You should call it yourself prior to running
:: this batchfile.
::
-REM call "C:\Program Files\Microsoft Developer Studio\vc98\bin\vcvars32.bat"
-set "VSCMD_START_DIR=%CD%"
-call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"
+call "C:\Program Files\Microsoft Developer Studio\vc98\bin\vcvars32.bat"
if errorlevel 1 (goto no_vcvars)
:startBuilding
@@ -61,15 +59,15 @@ if "%INSTALLDIR%" == "" set INSTALLDIR=C:\Program Files\Tcl
:: Build the normal stuff along with the help file.
::
-set OPTS=none
-if not %SYMBOLS%.==. set OPTS=symbols
-nmake -nologo -f makefile.vc release htmlhelp OPTS=%OPTS% %1
+set OPTS=threads
+if not %SYMBOLS%.==. set OPTS=symbols,threads
+nmake -nologo -f makefile.vc release winhelp OPTS=%OPTS% %1
if errorlevel 1 goto error
:: Build the static core and shell.
::
-set OPTS=static
-if not %SYMBOLS%.==. set OPTS=symbols,static
+set OPTS=static,msvcrt,threads
+if not %SYMBOLS%.==. set OPTS=symbols,static,msvcrt,threads
nmake -nologo -f makefile.vc shell OPTS=%OPTS% %1
if errorlevel 1 goto error
diff --git a/win/cat.c b/win/cat.c
index bd84dd4..d413923 100644
--- a/win/cat.c
+++ b/win/cat.c
@@ -9,33 +9,26 @@
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#ifdef TCL_BROKEN_MAINARGS
-/* On mingw32 and cygwin this doesn't work */
-# undef UNICODE
-# undef _UNICODE
-#endif
-
#include <stdio.h>
#include <io.h>
#include <string.h>
-#include <tchar.h>
int
-_tmain(void)
+main(void)
{
char buf[1024];
int n;
const char *err;
while (1) {
- n = _read(0, buf, sizeof(buf));
+ n = read(0, buf, sizeof(buf));
if (n <= 0) {
break;
}
- _write(1, buf, n);
+ write(1, buf, n);
}
err = (sizeof(int) == 2) ? "stderr16" : "stderr32";
- _write(2, err, (unsigned int)strlen(err));
+ write(2, err, strlen(err));
return 0;
}
diff --git a/win/coffbase.txt b/win/coffbase.txt
new file mode 100644
index 0000000..0ebe18a
--- /dev/null
+++ b/win/coffbase.txt
@@ -0,0 +1,42 @@
+;
+; This file defines the virtual base addresses for the Dynamic Link Libraries
+; that are part of the Tcl system. The first token on a line is the key (or name
+; of the DLL) and the second token is the virtual base address, in hexidecimal.
+; The third token is the maximum size of the DLL image file, including symbols.
+;
+; Using a specified "prefered load address" should speed loading time by avoiding
+; relocations (NT supported only). It is assumed extension authors will contribute
+; their modules to this grand-master list. You can use the dumpbin utility with
+; the /headers option to get the "size of image" data (already in hex). If the
+; maximum size is too small a linker warning will occur. Modules can overlap when
+; they're mutually exclusive. This info is placed in the DLL's PE header by the
+; linker with the `-base:@$(TCLDIR)\win\coffbase.txt,<key>` option.
+
+tcl 0x10000000 0x00200000
+tcldde 0x10200000 0x00010000
+tclreg 0x10210000 0x00010000
+tk 0x10220000 0x00200000
+expect 0x10480000 0x00080000
+itcl 0x10500000 0x00080000
+itk 0x10580000 0x00080000
+bltlite 0x10600000 0x00080000
+blt 0x10680000 0x00080000
+iocpsock 0x10700000 0x00080000
+tls 0x10780000 0x00100000
+winico 0x10880000 0x00010000
+sample 0x108B0000 0x00010000
+tile 0x10900000 0x00080000
+memchan 0x109D0000 0x00010000
+tdom 0x109E0000 0x00080000
+tclvfs 0x10A70000 0x00010000
+tkvideo 0x10B00000 0x00010000
+tclsdl 0x10B20000 0x00080000
+vqtcl 0x10C00000 0x00010000
+tdbc 0x10C40000 0x00010000
+thread 0x10C80000 0x00020000
+;
+; insert new packages here
+;
+snack 0x1E000000 0x00400000
+sound 0x1E400000 0x00400000
+snackogg 0x1E800000 0x00200000
diff --git a/win/configure b/win/configure
index 94e04f5..090feaa 100755
--- a/win/configure
+++ b/win/configure
@@ -1,469 +1,81 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.72 for tcl 8.7.
-#
-#
-# Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation,
-# Inc.
-#
+# Generated by GNU Autoconf 2.59.
#
+# Copyright (C) 2003 Free Software Foundation, Inc.
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else case e in #(
- e) case `(set -o) 2>/dev/null` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac ;;
-esac
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
fi
+DUALCASE=1; export DUALCASE # for MKS sh
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
-as_nl='
-'
-export as_nl
-IFS=" "" $as_nl"
-
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
PS1='$ '
PS2='> '
PS4='+ '
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
-if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
-
-# The user is always right.
-if ${PATH_SEPARATOR+false} :; then
- PATH_SEPARATOR=:
- (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
- (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
- PATH_SEPARATOR=';'
- }
-fi
-
-
-# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-# We did not find ourselves, most probably we were run as 'sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
- as_myself=$0
-fi
-if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
- exit 1
-fi
-
-
-# Use a proper internal environment variable to ensure we don't fall
- # into an infinite loop, continuously re-executing ourselves.
- if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
- _as_can_reexec=no; export _as_can_reexec;
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed 'exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
- fi
- # We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
-if test "x$CONFIG_SHELL" = x; then
- as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '\${1+\"\$@\"}'='\"\$@\"'
- setopt NO_GLOB_SUBST
-else case e in #(
- e) case \`(set -o) 2>/dev/null\` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac ;;
-esac
-fi
-"
- as_required="as_fn_return () { (exit \$1); }
-as_fn_success () { as_fn_return 0; }
-as_fn_failure () { as_fn_return 1; }
-as_fn_ret_success () { return 0; }
-as_fn_ret_failure () { return 1; }
-
-exitcode=0
-as_fn_success || { exitcode=1; echo as_fn_success failed.; }
-as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
-as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
-as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" )
-then :
-
-else case e in #(
- e) exitcode=1; echo positional parameters were not saved. ;;
-esac
-fi
-test x\$exitcode = x0 || exit 1
-blah=\$(echo \$(echo blah))
-test x\"\$blah\" = xblah || exit 1
-test -x / || exit 1"
- as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
- as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
- eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
- test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
-test \$(( 1 + 1 )) = 2 || exit 1"
- if (eval "$as_required") 2>/dev/null
-then :
- as_have_required=yes
-else case e in #(
- e) as_have_required=no ;;
-esac
-fi
- if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
-then :
-
-else case e in #(
- e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- as_found=:
- case $as_dir in #(
- /*)
- for as_base in sh bash ksh sh5; do
- # Try only shells that exist, to save several forks.
- as_shell=$as_dir$as_base
- if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
- as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
- CONFIG_SHELL=$as_shell as_have_required=yes
- if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
-then :
- break 2
-fi
-fi
- done;;
- esac
- as_found=false
-done
-IFS=$as_save_IFS
-if $as_found
-then :
-
-else case e in #(
- e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
- as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
- CONFIG_SHELL=$SHELL as_have_required=yes
-fi ;;
-esac
-fi
-
-
- if test "x$CONFIG_SHELL" != x
-then :
- export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed 'exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
-fi
-
- if test x$as_have_required = xno
-then :
- printf "%s\n" "$0: This script requires a shell more modern than all"
- printf "%s\n" "$0: the shells that I found on your system."
- if test ${ZSH_VERSION+y} ; then
- printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
- printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
else
- printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system,
-$0: including any error possibly output before this
-$0: message. Then install a modern shell, or manually run
-$0: the script under such a shell if you do have one."
- fi
- exit 1
-fi ;;
-esac
-fi
-fi
-SHELL=${CONFIG_SHELL-/bin/sh}
-export SHELL
-# Unset more variables known to interfere with behavior of common tools.
-CLICOLOR_FORCE= GREP_OPTIONS=
-unset CLICOLOR_FORCE GREP_OPTIONS
-
-## --------------------- ##
-## M4sh Shell Functions. ##
-## --------------------- ##
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
- { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
- return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
- set +e
- as_fn_set_status $1
- exit $1
-} # as_fn_exit
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
- case $as_dir in #(
- -*) as_dir=./$as_dir;;
- esac
- test -d "$as_dir" || eval $as_mkdir_p || {
- as_dirs=
- while :; do
- case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
- *) as_qdir=$as_dir;;
- esac
- as_dirs="'$as_qdir' $as_dirs"
- as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_dir" : 'X\(//\)[^/]' \| \
- X"$as_dir" : 'X\(//\)$' \| \
- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- test -d "$as_dir" && break
- done
- test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
-then :
- eval 'as_fn_append ()
- {
- eval $1+=\$2
- }'
-else case e in #(
- e) as_fn_append ()
- {
- eval $1=\$$1\$2
- } ;;
-esac
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
-then :
- eval 'as_fn_arith ()
- {
- as_val=$(( $* ))
- }'
-else case e in #(
- e) as_fn_arith ()
- {
- as_val=`expr "$@" || test $? -eq 1`
- } ;;
-esac
-fi # as_fn_arith
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ $as_unset $as_var
fi
- printf "%s\n" "$as_me: error: $2" >&2
- as_fn_exit $as_status
-} # as_fn_error
+done
-if expr a : '\(a\)' >/dev/null 2>&1 &&
- test "X`expr 00001 : '.*\(...\)'`" = X001; then
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
as_expr=expr
else
as_expr=false
fi
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
as_basename=basename
else
as_basename=false
fi
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
- as_dirname=dirname
-else
- as_dirname=false
-fi
-as_me=`$as_basename -- "$0" ||
+# Name of the executable.
+as_me=`$as_basename "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{
- s//\1/
- q
- }
- /^X\/\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\/\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+# PATH needs CR, and LINENO needs CR and PATH.
# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
@@ -471,356 +83,238 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
- as_lineno_1=$LINENO as_lineno_1a=$LINENO
- as_lineno_2=$LINENO as_lineno_2a=$LINENO
- eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
- test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
- # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
- sed -n '
- p
- /[$]LINENO/=
- ' <$as_myself |
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
sed '
- t clear
- :clear
- s/[$]LINENO.*/&-/
- t lineno
- b
- :lineno
N
- :loop
- s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
t loop
- s/-\n.*//
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
' >$as_me.lineno &&
- chmod +x "$as_me.lineno" ||
- { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
- # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
- # already done that, so ensure we don't try to do so again and fall
- # in an infinite loop. This has already happened in practice.
- _as_can_reexec=no; export _as_can_reexec
# Don't try to exec as it changes $[0], causing all sort of problems
# (the dirname of $[0] is not the place where we might find the
- # original and so on. Autoconf is especially sensitive to this).
- . "./$as_me.lineno"
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
# Exit status is that of the last command.
exit
}
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
- case `echo 'xy\c'` in
- *c*) ECHO_T=' ';; # ECHO_T is single tab character.
- xy) ECHO_C='\c';;
- *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
- ECHO_T=' ';;
- esac;;
-*)
- ECHO_N='-n';;
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
esac
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
- rm -f conf$$.dir/conf$$.file
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
else
- rm -f conf$$.dir
- mkdir conf$$.dir 2>/dev/null
+ as_expr=false
fi
-if (echo >conf$$.file) 2>/dev/null; then
- if ln -s conf$$.file conf$$ 2>/dev/null; then
- as_ln_s='ln -s'
- # ... but there are two gotchas:
- # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail.
- # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable.
- # In both cases, we have to default to 'cp -pR'.
- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
- elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
else
- as_ln_s='cp -pR'
+ as_ln_s='ln -s'
fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
+rm -f conf$$ conf$$.exe conf$$.file
if mkdir -p . 2>/dev/null; then
- as_mkdir_p='mkdir -p "$as_dir"'
+ as_mkdir_p=:
else
test -d ./-p && rmdir ./-p
as_mkdir_p=false
fi
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+as_executable_p="test -f"
# Sed expression to map a string onto a valid CPP name.
-as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
-as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
# Sed expression to map a string onto a valid variable name.
-as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
-as_tr_sh="eval sed '$as_sed_sh'" # deprecated
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-test -n "$DJDIR" || exec 7<&0 </dev/null
-exec 6>&1
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
# Name of the host.
-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
# so uname gets run too.
ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+exec 6>&1
+
#
# Initializations.
#
ac_default_prefix=/usr/local
-ac_clean_files=
ac_config_libobj_dir=.
-LIBOBJS=
cross_compiling=no
subdirs=
MFLAGS=
MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
# Identity of this package.
-PACKAGE_NAME='tcl'
-PACKAGE_TARNAME='tcl'
-PACKAGE_VERSION='8.7'
-PACKAGE_STRING='tcl 8.7'
-PACKAGE_BUGREPORT=''
-PACKAGE_URL=''
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
ac_unique_file="../generic/tcl.h"
# Factoring default headers for most tests.
ac_includes_default="\
-#include <stddef.h>
-#ifdef HAVE_STDIO_H
-# include <stdio.h>
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
#endif
-#ifdef HAVE_STDLIB_H
+#if STDC_HEADERS
# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
#endif
-#ifdef HAVE_STRING_H
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
# include <string.h>
#endif
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#ifdef HAVE_STRINGS_H
+#if HAVE_STRINGS_H
# include <strings.h>
#endif
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
#endif
-#ifdef HAVE_UNISTD_H
+#if HAVE_UNISTD_H
# include <unistd.h>
#endif"
-ac_header_c_list=
-ac_subst_vars='LTLIBOBJS
-LIBOBJS
-RES
-RC_DEFINES
-RC_DEFINE
-RC_INCLUDE
-RC_TYPE
-RC_OUT
-TCL_REG_MINOR_VERSION
-TCL_REG_MAJOR_VERSION
-TCL_REG_VERSION
-TCL_DDE_MINOR_VERSION
-TCL_DDE_MAJOR_VERSION
-TCL_DDE_VERSION
-TCL_PACKAGE_PATH
-TCL_EXP_FILE
-TCL_BUILD_EXP_FILE
-TCL_LD_SEARCH_FLAGS
-TCL_CC_SEARCH_FLAGS
-TCL_BUILD_LIB_SPEC
-MAKE_EXE
-MAKE_DLL
-POST_MAKE_LIB
-MAKE_STUB_LIB
-MAKE_LIB
-LIBRARIES
-EXESUFFIX
-LIBSUFFIX
-LIBPREFIX
-DLLSUFFIX
-LIBS_GUI
-TCL_SHARED_BUILD
-SHLIB_SUFFIX
-SHLIB_CFLAGS
-SHLIB_LD_LIBS
-SHLIB_LD
-STLIB_LD
-LDFLAGS_WINDOW
-LDFLAGS_CONSOLE
-LDFLAGS_OPTIMIZE
-LDFLAGS_DEBUG
-CC_EXENAME
-CC_OBJNAME
-DEPARG
-EXTRA_CFLAGS
-CFG_TCL_UNSHARED_LIB_SUFFIX
-CFG_TCL_SHARED_LIB_SUFFIX
-TCL_BIN_DIR
-TCL_SRC_DIR
-TCL_DLL_FILE
-TCL_BUILD_STUB_LIB_PATH
-TCL_BUILD_STUB_LIB_SPEC
-TCL_INCLUDE_SPEC
-TCL_STUB_LIB_PATH
-TCL_STUB_LIB_SPEC
-TCL_STUB_LIB_FLAG
-TCL_STUB_LIB_FILE
-TCL_LIB_SPEC
-TCL_IMPORT_LIB_FLAG
-TCL_IMPORT_LIB_FILE
-TCL_STATIC_LIB_FLAG
-TCL_STATIC_LIB_FILE
-TCL_LIB_FLAG
-TCL_LIB_FILE
-TCL_EXE
-PKG_CFG_ARGS
-TCL_PATCH_LEVEL
-TCL_MINOR_VERSION
-TCL_MAJOR_VERSION
-TCL_VERSION
-MACHINE
-TCL_WIN_VERSION
-VC_MANIFEST_EMBED_EXE
-VC_MANIFEST_EMBED_DLL
-CPP
-LDFLAGS_DEFAULT
-CFLAGS_DEFAULT
-INSTALL_MSGS
-INSTALL_LIBRARIES
-TCL_ZIP_FILE
-ZIPFS_BUILD
-ZIP_INSTALL_OBJS
-ZIP_PROG_VFSSEARCH
-ZIP_PROG_OPTIONS
-ZIP_PROG
-TCLSH_PROG
-EXEEXT_FOR_BUILD
-CC_FOR_BUILD
-TCL_TOMMATH_LIB_NAME
-TCL_ZLIB_LIB_NAME
-TOMMATH_OBJS
-ZLIB_OBJS
-TOMMATH_LIBS
-ZLIB_LIBS
-TOMMATH_DLL_FILE
-ZLIB_DLL_FILE
-CFLAGS_NOLTO
-CFLAGS_WARNING
-CFLAGS_OPTIMIZE
-CFLAGS_DEBUG
-DL_LIBS
-WINE
-CYGPATH
-SHARED_BUILD
-SET_MAKE
-RC
-RANLIB
-AR
-OBJEXT
-EXEEXT
-ac_ct_CC
-CPPFLAGS
-LDFLAGS
-CFLAGS
-CC
-target_alias
-host_alias
-build_alias
-LIBS
-ECHO_T
-ECHO_N
-ECHO_C
-DEFS
-mandir
-localedir
-libdir
-psdir
-pdfdir
-dvidir
-htmldir
-infodir
-docdir
-oldincludedir
-includedir
-runstatedir
-localstatedir
-sharedstatedir
-sysconfdir
-datadir
-datarootdir
-libexecdir
-sbindir
-bindir
-program_transform_name
-prefix
-exec_prefix
-PACKAGE_URL
-PACKAGE_BUGREPORT
-PACKAGE_STRING
-PACKAGE_VERSION
-PACKAGE_TARNAME
-PACKAGE_NAME
-PATH_SEPARATOR
-SHELL
-OBJEXT_FOR_BUILD'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP AR ac_ct_AR RANLIB ac_ct_RANLIB RC ac_ct_RC SET_MAKE TCL_THREADS CYGPATH CELIB_DIR DL_LIBS CFLAGS_DEBUG CFLAGS_OPTIMIZE CFLAGS_WARNING CFLAGS_DEFAULT LDFLAGS_DEFAULT VC_MANIFEST_EMBED_DLL VC_MANIFEST_EMBED_EXE TCL_WIN_VERSION MACHINE TCL_VERSION TCL_MAJOR_VERSION TCL_MINOR_VERSION TCL_PATCH_LEVEL TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_STUB_LIB_PATH TCL_INCLUDE_SPEC TCL_BUILD_STUB_LIB_SPEC TCL_BUILD_STUB_LIB_PATH TCL_DLL_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_DBGX CFG_TCL_SHARED_LIB_SUFFIX CFG_TCL_UNSHARED_LIB_SUFFIX CFG_TCL_EXPORT_FILE_SUFFIX EXTRA_CFLAGS DEPARG CC_OBJNAME CC_EXENAME LDFLAGS_DEBUG LDFLAGS_OPTIMIZE LDFLAGS_CONSOLE LDFLAGS_WINDOW STLIB_LD SHLIB_LD SHLIB_LD_LIBS SHLIB_CFLAGS SHLIB_SUFFIX TCL_SHARED_BUILD LIBS_GUI DLLSUFFIX LIBPREFIX LIBSUFFIX EXESUFFIX LIBRARIES MAKE_LIB MAKE_STUB_LIB POST_MAKE_LIB MAKE_DLL MAKE_EXE TCL_BUILD_LIB_SPEC TCL_LD_SEARCH_FLAGS TCL_NEEDS_EXP_FILE TCL_BUILD_EXP_FILE TCL_EXP_FILE TCL_LIB_VERSIONS_OK TCL_PACKAGE_PATH TCL_DDE_VERSION TCL_DDE_MAJOR_VERSION TCL_DDE_MINOR_VERSION TCL_REG_VERSION TCL_REG_MAJOR_VERSION TCL_REG_MINOR_VERSION RC_OUT RC_TYPE RC_INCLUDE RC_DEFINE RC_DEFINES RES LIBOBJS LTLIBOBJS'
ac_subst_files=''
-ac_user_opts='
-enable_option_checking
-with_encoding
-enable_shared
-enable_time64bit
-enable_64bit
-enable_zipfs
-enable_symbols
-enable_embedded_manifest
-'
- ac_precious_vars='build_alias
-host_alias
-target_alias
-CC
-CFLAGS
-LDFLAGS
-LIBS
-CPPFLAGS
-CPP'
-
# Initialize some variables set by options.
ac_init_help=
ac_init_version=false
-ac_unrecognized_opts=
-ac_unrecognized_sep=
# The variables have the same names as the options, with
# dashes changed to underlines.
cache_file=/dev/null
@@ -843,48 +337,34 @@ x_libraries=NONE
# and all the variables that are supposed to be based on exec_prefix
# by default will actually change.
# Use braces instead of parens because sh, perl, etc. also accept them.
-# (The list follows the same order as the GNU Coding Standards.)
bindir='${exec_prefix}/bin'
sbindir='${exec_prefix}/sbin'
libexecdir='${exec_prefix}/libexec'
-datarootdir='${prefix}/share'
-datadir='${datarootdir}'
+datadir='${prefix}/share'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
-runstatedir='${localstatedir}/run'
+libdir='${exec_prefix}/lib'
includedir='${prefix}/include'
oldincludedir='/usr/include'
-docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
-infodir='${datarootdir}/info'
-htmldir='${docdir}'
-dvidir='${docdir}'
-pdfdir='${docdir}'
-psdir='${docdir}'
-libdir='${exec_prefix}/lib'
-localedir='${datarootdir}/locale'
-mandir='${datarootdir}/man'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
ac_prev=
-ac_dashdash=
for ac_option
do
# If the previous option needs an argument, assign it.
if test -n "$ac_prev"; then
- eval $ac_prev=\$ac_option
+ eval "$ac_prev=\$ac_option"
ac_prev=
continue
fi
- case $ac_option in
- *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
- *=) ac_optarg= ;;
- *) ac_optarg=yes ;;
- esac
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
- case $ac_dashdash$ac_option in
- --)
- ac_dashdash=yes ;;
+ case $ac_option in
-bindir | --bindir | --bindi | --bind | --bin | --bi)
ac_prev=bindir ;;
@@ -906,59 +386,33 @@ do
--config-cache | -C)
cache_file=config.cache ;;
- -datadir | --datadir | --datadi | --datad)
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
ac_prev=datadir ;;
- -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
datadir=$ac_optarg ;;
- -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
- | --dataroo | --dataro | --datar)
- ac_prev=datarootdir ;;
- -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
- | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
- datarootdir=$ac_optarg ;;
-
-disable-* | --disable-*)
- ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
# Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: '$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"enable_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval enable_$ac_useropt=no ;;
-
- -docdir | --docdir | --docdi | --doc | --do)
- ac_prev=docdir ;;
- -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
- docdir=$ac_optarg ;;
-
- -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
- ac_prev=dvidir ;;
- -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
- dvidir=$ac_optarg ;;
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
-enable-* | --enable-*)
- ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
# Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: '$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"enable_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
esac
- eval enable_$ac_useropt=\$ac_optarg ;;
+ eval "enable_$ac_feature='$ac_optarg'" ;;
-exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
| --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
@@ -985,12 +439,6 @@ do
-host=* | --host=* | --hos=* | --ho=*)
host_alias=$ac_optarg ;;
- -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
- ac_prev=htmldir ;;
- -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
- | --ht=*)
- htmldir=$ac_optarg ;;
-
-includedir | --includedir | --includedi | --included | --include \
| --includ | --inclu | --incl | --inc)
ac_prev=includedir ;;
@@ -1015,16 +463,13 @@ do
| --libexe=* | --libex=* | --libe=*)
libexecdir=$ac_optarg ;;
- -localedir | --localedir | --localedi | --localed | --locale)
- ac_prev=localedir ;;
- -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
- localedir=$ac_optarg ;;
-
-localstatedir | --localstatedir | --localstatedi | --localstated \
- | --localstate | --localstat | --localsta | --localst | --locals)
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
ac_prev=localstatedir ;;
-localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
- | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
localstatedir=$ac_optarg ;;
-mandir | --mandir | --mandi | --mand | --man | --ma | --m)
@@ -1089,29 +534,10 @@ do
| --progr-tra=* | --program-tr=* | --program-t=*)
program_transform_name=$ac_optarg ;;
- -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
- ac_prev=pdfdir ;;
- -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
- pdfdir=$ac_optarg ;;
-
- -psdir | --psdir | --psdi | --psd | --ps)
- ac_prev=psdir ;;
- -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
- psdir=$ac_optarg ;;
-
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
- -runstatedir | --runstatedir | --runstatedi | --runstated \
- | --runstate | --runstat | --runsta | --runst | --runs \
- | --run | --ru | --r)
- ac_prev=runstatedir ;;
- -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
- | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
- | --run=* | --ru=* | --r=*)
- runstatedir=$ac_optarg ;;
-
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1158,36 +584,26 @@ do
ac_init_version=: ;;
-with-* | --with-*)
- ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
# Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: '$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"with_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
esac
- eval with_$ac_useropt=\$ac_optarg ;;
+ eval "with_$ac_package='$ac_optarg'" ;;
-without-* | --without-*)
- ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
# Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: '$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"with_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval with_$ac_useropt=no ;;
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
--x)
# Obsolete; use --with-x.
@@ -1207,26 +623,27 @@ do
| --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
x_libraries=$ac_optarg ;;
- -*) as_fn_error $? "unrecognized option: '$ac_option'
-Try '$0 --help' for more information"
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
;;
*=*)
ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
# Reject names that are not valid shell variable names.
- case $ac_envvar in #(
- '' | [0-9]* | *[!_$as_cr_alnum]* )
- as_fn_error $? "invalid variable name: '$ac_envvar'" ;;
- esac
- eval $ac_envvar=\$ac_optarg
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
export $ac_envvar ;;
*)
# FIXME: should be removed in autoconf 3.0.
- printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
- printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2
- : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
;;
esac
@@ -1234,39 +651,34 @@ done
if test -n "$ac_prev"; then
ac_option=--`echo $ac_prev | sed 's/_/-/g'`
- as_fn_error $? "missing argument to $ac_option"
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
fi
-if test -n "$ac_unrecognized_opts"; then
- case $enable_option_checking in
- no) ;;
- fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
- *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
- esac
-fi
-
-# Check all directory arguments for consistency.
-for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
- datadir sysconfdir sharedstatedir localstatedir includedir \
- oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir runstatedir
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
do
- eval ac_val=\$$ac_var
- # Remove trailing slashes.
+ eval ac_val=$`echo $ac_var`
case $ac_val in
- */ )
- ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
- eval $ac_var=\$ac_val;;
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
esac
- # Be sure to have absolute directory names.
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
case $ac_val in
- [\\/$]* | ?:[\\/]* ) continue;;
- NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
esac
- as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
done
-# There might be people who depend on the old broken behavior: '$host'
+# There might be people who depend on the old broken behavior: `$host'
# used to hold the argument of --host etc.
# FIXME: To remove some day.
build=$build_alias
@@ -1277,6 +689,8 @@ target=$target_alias
if test "x$host_alias" != x; then
if test "x$build_alias" = x; then
cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
elif test "x$build_alias" != "x$host_alias"; then
cross_compiling=yes
fi
@@ -1288,72 +702,74 @@ test -n "$host_alias" && ac_tool_prefix=$host_alias-
test "$silent" = yes && exec 6>/dev/null
-ac_pwd=`pwd` && test -n "$ac_pwd" &&
-ac_ls_di=`ls -di .` &&
-ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
- as_fn_error $? "working directory cannot be determined"
-test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
- as_fn_error $? "pwd does not report name of working directory"
-
-
# Find the source files, if location was not specified.
if test -z "$srcdir"; then
ac_srcdir_defaulted=yes
- # Try the directory containing this script, then the parent directory.
- ac_confdir=`$as_dirname -- "$as_myself" ||
-$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_myself" : 'X\(//\)[^/]' \| \
- X"$as_myself" : 'X\(//\)$' \| \
- X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_myself" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
srcdir=$ac_confdir
- if test ! -r "$srcdir/$ac_unique_file"; then
+ if test ! -r $srcdir/$ac_unique_file; then
srcdir=..
fi
else
ac_srcdir_defaulted=no
fi
-if test ! -r "$srcdir/$ac_unique_file"; then
- test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
- as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
-fi
-ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work"
-ac_abs_confdir=`(
- cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
- pwd)`
-# When building in place, set srcdir=.
-if test "$ac_abs_confdir" = "$ac_pwd"; then
- srcdir=.
-fi
-# Remove unnecessary trailing slashes from srcdir.
-# Double slashes in file names in object file debugging info
-# mess up M-x gdb in Emacs.
-case $srcdir in
-*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
-esac
-for ac_var in $ac_precious_vars; do
- eval ac_env_${ac_var}_set=\${${ac_var}+set}
- eval ac_env_${ac_var}_value=\$${ac_var}
- eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
- eval ac_cv_env_${ac_var}_value=\$${ac_var}
-done
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
#
# Report the --help message.
@@ -1362,7 +778,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-'configure' configures tcl 8.7 to adapt to many kinds of systems.
+\`configure' configures this package to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1376,46 +792,41 @@ Configuration:
--help=short display options specific to this package
--help=recursive display the short help of all the included packages
-V, --version display version information and exit
- -q, --quiet, --silent do not print 'checking ...' messages
+ -q, --quiet, --silent do not print \`checking...' messages
--cache-file=FILE cache test results in FILE [disabled]
- -C, --config-cache alias for '--cache-file=config.cache'
+ -C, --config-cache alias for \`--cache-file=config.cache'
-n, --no-create do not create output files
- --srcdir=DIR find the sources in DIR [configure dir or '..']
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+ cat <<_ACEOF
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
-By default, 'make install' will install all the files in
-'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify
-an installation prefix other than '$ac_default_prefix' using '--prefix',
-for instance '--prefix=\$HOME'.
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
For better control, use the options below.
Fine tuning of the installation directories:
- --bindir=DIR user executables [EPREFIX/bin]
- --sbindir=DIR system admin executables [EPREFIX/sbin]
- --libexecdir=DIR program executables [EPREFIX/libexec]
- --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
- --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
- --localstatedir=DIR modifiable single-machine data [PREFIX/var]
- --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
- --libdir=DIR object code libraries [EPREFIX/lib]
- --includedir=DIR C header files [PREFIX/include]
- --oldincludedir=DIR C header files for non-gcc [/usr/include]
- --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
- --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
- --infodir=DIR info documentation [DATAROOTDIR/info]
- --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
- --mandir=DIR man documentation [DATAROOTDIR/man]
- --docdir=DIR documentation root [DATAROOTDIR/doc/tcl]
- --htmldir=DIR html documentation [DOCDIR]
- --dvidir=DIR dvi documentation [DOCDIR]
- --pdfdir=DIR pdf documentation [DOCDIR]
- --psdir=DIR ps documentation [DOCDIR]
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
_ACEOF
cat <<\_ACEOF
@@ -1423,19 +834,16 @@ _ACEOF
fi
if test -n "$ac_init_help"; then
- case $ac_init_help in
- short | recursive ) echo "Configuration of tcl 8.7:";;
- esac
+
cat <<\_ACEOF
Optional Features:
- --disable-option-checking ignore unrecognized --enable/--with options
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-threads build with threads (default: off)
--enable-shared build and link with shared libraries (default: on)
- --enable-time64bit force 64-bit time_t for 32-bit build (default: off)
--enable-64bit enable 64bit support (where applicable)
- --enable-zipfs build with Zipfs support (default: on)
+ --enable-wince enable Win/CE support (where applicable)
--enable-symbols build with debugging symbols (default: off)
--enable-embedded-manifest
embed manifest if possible (default: yes)
@@ -1444,301 +852,133 @@ Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-encoding encoding for configuration values
+ --with-celib=DIR use Windows/CE support library from DIR
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir>
- LIBS libraries to pass to the linker, e.g. -l<library>
- CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
CPP C preprocessor
-Use these variables to override the choices made by 'configure' or to help
+Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
-Report bugs to the package provider.
_ACEOF
-ac_status=$?
fi
if test "$ac_init_help" = "recursive"; then
# If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
- test -d "$ac_dir" ||
- { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
- continue
+ test -d $ac_dir || continue
ac_builddir=.
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
- # A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
- case $ac_top_builddir_sub in
- "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
- esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
case $srcdir in
- .) # We are building in place.
+ .) # No --srcdir option. We are building in place.
ac_srcdir=.
- ac_top_srcdir=$ac_top_builddir_sub
- ac_abs_top_srcdir=$ac_pwd ;;
- [\\/]* | ?:[\\/]* ) # Absolute name.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir
- ac_abs_top_srcdir=$srcdir ;;
- *) # Relative name.
- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_build_prefix$srcdir
- ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
- cd "$ac_dir" || { ac_status=$?; continue; }
- # Check for configure.gnu first; this name is used for a wrapper for
- # Metaconfig's "Configure" on case-insensitive file systems.
- if test -f "$ac_srcdir/configure.gnu"; then
- echo &&
- $SHELL "$ac_srcdir/configure.gnu" --help=recursive
- elif test -f "$ac_srcdir/configure"; then
- echo &&
- $SHELL "$ac_srcdir/configure" --help=recursive
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
else
- printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2
- fi || ac_status=$?
- cd "$ac_pwd" || { ac_status=$?; break; }
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
done
fi
-test -n "$ac_init_help" && exit $ac_status
+test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-tcl configure 8.7
-generated by GNU Autoconf 2.72
-Copyright (C) 2023 Free Software Foundation, Inc.
+Copyright (C) 2003 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
- exit
-fi
-
-## ------------------------ ##
-## Autoconf initialization. ##
-## ------------------------ ##
-
-# ac_fn_c_try_compile LINENO
-# --------------------------
-# Try to compile conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_compile ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest.beam
- if { { ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compile") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest.$ac_objext
-then :
- ac_retval=0
-else case e in #(
- e) printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1 ;;
-esac
+ exit 0
fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_compile
-
-# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists and can be compiled using the include files in
-# INCLUDES, setting the cache variable VAR accordingly.
-ac_fn_c_check_header_compile ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- eval "$3=yes"
-else case e in #(
- e) eval "$3=no" ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
-esac
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_compile
-
-# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
-# -------------------------------------------
-# Tests whether TYPE exists after having included INCLUDES, setting cache
-# variable VAR accordingly.
-ac_fn_c_check_type ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) eval "$3=no"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main (void)
-{
-if (sizeof ($2))
- return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main (void)
-{
-if (sizeof (($2)))
- return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else case e in #(
- e) eval "$3=yes" ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
-esac
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_type
-
-# ac_fn_c_try_cpp LINENO
-# ----------------------
-# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_cpp ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if { { ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } > conftest.i && {
- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
- test ! -s conftest.err
- }
-then :
- ac_retval=0
-else case e in #(
- e) printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1 ;;
-esac
-fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_cpp
-ac_configure_args_raw=
-for ac_arg
-do
- case $ac_arg in
- *\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- as_fn_append ac_configure_args_raw " '$ac_arg'"
-done
-
-case $ac_configure_args_raw in
- *$as_nl*)
- ac_safe_unquote= ;;
- *)
- ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab.
- ac_unsafe_a="$ac_unsafe_z#~"
- ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g"
- ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
-esac
-
-cat >config.log <<_ACEOF
+exec 5>config.log
+cat >&5 <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by tcl $as_me 8.7, which was
-generated by GNU Autoconf 2.72. Invocation command line was
+It was created by $as_me, which was
+generated by GNU Autoconf 2.59. Invocation command line was
- $ $0$ac_configure_args_raw
+ $ $0 $@
_ACEOF
-exec 5>>config.log
{
cat <<_ASUNAME
## --------- ##
@@ -1757,7 +997,7 @@ uname -v = `(uname -v) 2>/dev/null || echo unknown`
/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
@@ -1768,14 +1008,9 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- printf "%s\n" "PATH: $as_dir"
- done
-IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
} >&5
@@ -1797,6 +1032,7 @@ _ACEOF
ac_configure_args=
ac_configure_args0=
ac_configure_args1=
+ac_sep=
ac_must_keep_next=false
for ac_pass in 1 2
do
@@ -1807,13 +1043,13 @@ do
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil)
continue ;;
- *\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
case $ac_pass in
- 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
2)
- as_fn_append ac_configure_args1 " '$ac_arg'"
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
if test $ac_must_keep_next = true; then
ac_must_keep_next=false # Got value, back to normal.
else
@@ -1829,575 +1065,217 @@ do
-* ) ac_must_keep_next=true ;;
esac
fi
- as_fn_append ac_configure_args " '$ac_arg'"
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
;;
esac
done
done
-{ ac_configure_args0=; unset ac_configure_args0;}
-{ ac_configure_args1=; unset ac_configure_args1;}
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
# When interrupted or exit'd, cleanup temporary files, and complete
# config.log. We remove comments because anyway the quotes in there
# would cause problems or look ugly.
-# WARNING: Use '\'' to represent an apostrophe within the trap.
-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
trap 'exit_status=$?
- # Sanitize IFS.
- IFS=" "" $as_nl"
# Save into config.log some information that might help in debugging.
{
echo
- printf "%s\n" "## ---------------- ##
+ cat <<\_ASBOX
+## ---------------- ##
## Cache variables. ##
-## ---------------- ##"
+## ---------------- ##
+_ASBOX
echo
# The following way of writing the cache mishandles newlines in values,
-(
- for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
- eval ac_val=\$$ac_var
- case $ac_val in #(
- *${as_nl}*)
- case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
- esac
- case $ac_var in #(
- _ | IFS | as_nl) ;; #(
- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
- *) { eval $ac_var=; unset $ac_var;} ;;
- esac ;;
- esac
- done
+{
(set) 2>&1 |
- case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
- *${as_nl}ac_space=\ *)
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
sed -n \
- "s/'\''/'\''\\\\'\'''\''/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
- ;; #(
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
*)
- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
;;
- esac |
- sort
-)
+ esac;
+}
echo
- printf "%s\n" "## ----------------- ##
+ cat <<\_ASBOX
+## ----------------- ##
## Output variables. ##
-## ----------------- ##"
+## ----------------- ##
+_ASBOX
echo
for ac_var in $ac_subst_vars
do
- eval ac_val=\$$ac_var
- case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
- esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
done | sort
echo
if test -n "$ac_subst_files"; then
- printf "%s\n" "## ------------------- ##
-## File substitutions. ##
-## ------------------- ##"
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
echo
for ac_var in $ac_subst_files
do
- eval ac_val=\$$ac_var
- case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
- esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
done | sort
echo
fi
if test -s confdefs.h; then
- printf "%s\n" "## ----------- ##
+ cat <<\_ASBOX
+## ----------- ##
## confdefs.h. ##
-## ----------- ##"
+## ----------- ##
+_ASBOX
echo
- cat confdefs.h
+ sed "/^$/d" confdefs.h | sort
echo
fi
test "$ac_signal" != 0 &&
- printf "%s\n" "$as_me: caught signal $ac_signal"
- printf "%s\n" "$as_me: exit $exit_status"
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
} >&5
- rm -f core *.core core.conftest.* &&
- rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ rm -f core *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
exit $exit_status
-' 0
+ ' 0
for ac_signal in 1 2 13 15; do
- trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
done
ac_signal=0
# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -f -r conftest* confdefs.h
-
-printf "%s\n" "/* confdefs.h */" > confdefs.h
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
# Predefined preprocessor variables.
-printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
-printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
-printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h
-printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
-printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h
-printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
# Let the site file select an alternate cache file if it wants to.
-# Prefer an explicitly selected file to automatically selected ones.
-if test -n "$CONFIG_SITE"; then
- ac_site_files="$CONFIG_SITE"
-elif test "x$prefix" != xNONE; then
- ac_site_files="$prefix/share/config.site $prefix/etc/config.site"
-else
- ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
fi
-
-for ac_site_file in $ac_site_files
-do
- case $ac_site_file in #(
- */*) :
- ;; #(
- *) :
- ac_site_file=./$ac_site_file ;;
-esac
- if test -f "$ac_site_file" && test -r "$ac_site_file"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;}
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
sed 's/^/| /' "$ac_site_file" >&5
- . "$ac_site_file" \
- || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
-as_fn_error $? "failed to load site script $ac_site_file
-See 'config.log' for more details" "$LINENO" 5; }
+ . "$ac_site_file"
fi
done
if test -r "$cache_file"; then
- # Some versions of bash will fail to source /dev/null (special files
- # actually), so we avoid doing that. DJGPP emulates it as a regular file.
- if test /dev/null != "$cache_file" && test -f "$cache_file"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-printf "%s\n" "$as_me: loading cache $cache_file" >&6;}
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
case $cache_file in
- [\\/]* | ?:[\\/]* ) . "$cache_file";;
- *) . "./$cache_file";;
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
esac
fi
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-printf "%s\n" "$as_me: creating cache $cache_file" >&6;}
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
>$cache_file
fi
-# Test code for whether the C compiler supports C89 (global declarations)
-ac_c_conftest_c89_globals='
-/* Does the compiler advertise C89 conformance?
- Do not test the value of __STDC__, because some compilers set it to 0
- while being otherwise adequately conformant. */
-#if !defined __STDC__
-# error "Compiler does not advertise C89 conformance"
-#endif
-
-#include <stddef.h>
-#include <stdarg.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */
-struct buf { int x; };
-struct buf * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (char **p, int i)
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
-
-/* C89 style stringification. */
-#define noexpand_stringify(a) #a
-const char *stringified = noexpand_stringify(arbitrary+token=sequence);
-
-/* C89 style token pasting. Exercises some of the corner cases that
- e.g. old MSVC gets wrong, but not very hard. */
-#define noexpand_concat(a,b) a##b
-#define expand_concat(a,b) noexpand_concat(a,b)
-extern int vA;
-extern int vbee;
-#define aye A
-#define bee B
-int *pvA = &expand_concat(v,aye);
-int *pvbee = &noexpand_concat(v,bee);
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not \xHH hex character constants.
- These do not provoke an error unfortunately, instead are silently treated
- as an "x". The following induces an error, until -std is added to get
- proper ANSI mode. Curiously \x00 != x always comes out true, for an
- array size at least. It is necessary to write \x00 == 0 to get something
- that is true only with -std. */
-int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1];
-
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) '\''x'\''
-int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int),
- int, int);'
-
-# Test code for whether the C compiler supports C89 (body of main).
-ac_c_conftest_c89_main='
-ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]);
-'
-
-# Test code for whether the C compiler supports C99 (global declarations)
-ac_c_conftest_c99_globals='
-/* Does the compiler advertise C99 conformance? */
-#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
-# error "Compiler does not advertise C99 conformance"
-#endif
-
-// See if C++-style comments work.
-
-#include <stdbool.h>
-extern int puts (const char *);
-extern int printf (const char *, ...);
-extern int dprintf (int, const char *, ...);
-extern void *malloc (size_t);
-extern void free (void *);
-
-// Check varargs macros. These examples are taken from C99 6.10.3.5.
-// dprintf is used instead of fprintf to avoid needing to declare
-// FILE and stderr.
-#define debug(...) dprintf (2, __VA_ARGS__)
-#define showlist(...) puts (#__VA_ARGS__)
-#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
-static void
-test_varargs_macros (void)
-{
- int x = 1234;
- int y = 5678;
- debug ("Flag");
- debug ("X = %d\n", x);
- showlist (The first, second, and third items.);
- report (x>y, "x is %d but y is %d", x, y);
-}
-
-// Check long long types.
-#define BIG64 18446744073709551615ull
-#define BIG32 4294967295ul
-#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
-#if !BIG_OK
- #error "your preprocessor is broken"
-#endif
-#if BIG_OK
-#else
- #error "your preprocessor is broken"
-#endif
-static long long int bignum = -9223372036854775807LL;
-static unsigned long long int ubignum = BIG64;
-
-struct incomplete_array
-{
- int datasize;
- double data[];
-};
-
-struct named_init {
- int number;
- const wchar_t *name;
- double average;
-};
-
-typedef const char *ccp;
-
-static inline int
-test_restrict (ccp restrict text)
-{
- // Iterate through items via the restricted pointer.
- // Also check for declarations in for loops.
- for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i)
- continue;
- return 0;
-}
-
-// Check varargs and va_copy.
-static bool
-test_varargs (const char *format, ...)
-{
- va_list args;
- va_start (args, format);
- va_list args_copy;
- va_copy (args_copy, args);
-
- const char *str = "";
- int number = 0;
- float fnumber = 0;
-
- while (*format)
- {
- switch (*format++)
- {
- case '\''s'\'': // string
- str = va_arg (args_copy, const char *);
- break;
- case '\''d'\'': // int
- number = va_arg (args_copy, int);
- break;
- case '\''f'\'': // float
- fnumber = va_arg (args_copy, double);
- break;
- default:
- break;
- }
- }
- va_end (args_copy);
- va_end (args);
-
- return *str && number && fnumber;
-}
-'
-
-# Test code for whether the C compiler supports C99 (body of main).
-ac_c_conftest_c99_main='
- // Check bool.
- _Bool success = false;
- success |= (argc != 0);
-
- // Check restrict.
- if (test_restrict ("String literal") == 0)
- success = true;
- char *restrict newvar = "Another string";
-
- // Check varargs.
- success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234);
- test_varargs_macros ();
-
- // Check flexible array members.
- struct incomplete_array *ia =
- malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
- ia->datasize = 10;
- for (int i = 0; i < ia->datasize; ++i)
- ia->data[i] = i * 1.234;
- // Work around memory leak warnings.
- free (ia);
-
- // Check named initializers.
- struct named_init ni = {
- .number = 34,
- .name = L"Test wide string",
- .average = 543.34343,
- };
-
- ni.number = 58;
-
- int dynamic_array[ni.number];
- dynamic_array[0] = argv[0][0];
- dynamic_array[ni.number - 1] = 543;
-
- // work around unused variable warnings
- ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\''
- || dynamic_array[ni.number - 1] != 543);
-'
-
-# Test code for whether the C compiler supports C11 (global declarations)
-ac_c_conftest_c11_globals='
-/* Does the compiler advertise C11 conformance? */
-#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
-# error "Compiler does not advertise C11 conformance"
-#endif
-
-// Check _Alignas.
-char _Alignas (double) aligned_as_double;
-char _Alignas (0) no_special_alignment;
-extern char aligned_as_int;
-char _Alignas (0) _Alignas (int) aligned_as_int;
-
-// Check _Alignof.
-enum
-{
- int_alignment = _Alignof (int),
- int_array_alignment = _Alignof (int[100]),
- char_alignment = _Alignof (char)
-};
-_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
-
-// Check _Noreturn.
-int _Noreturn does_not_return (void) { for (;;) continue; }
-
-// Check _Static_assert.
-struct test_static_assert
-{
- int x;
- _Static_assert (sizeof (int) <= sizeof (long int),
- "_Static_assert does not work in struct");
- long int y;
-};
-
-// Check UTF-8 literals.
-#define u8 syntax error!
-char const utf8_literal[] = u8"happens to be ASCII" "another string";
-
-// Check duplicate typedefs.
-typedef long *long_ptr;
-typedef long int *long_ptr;
-typedef long_ptr long_ptr;
-
-// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
-struct anonymous
-{
- union {
- struct { int i; int j; };
- struct { int k; long int l; } w;
- };
- int m;
-} v1;
-'
-
-# Test code for whether the C compiler supports C11 (body of main).
-ac_c_conftest_c11_main='
- _Static_assert ((offsetof (struct anonymous, i)
- == offsetof (struct anonymous, w.k)),
- "Anonymous union alignment botch");
- v1.i = 2;
- v1.w.k = 5;
- ok |= v1.i != 5;
-'
-
-# Test code for whether the C compiler supports C11 (complete).
-ac_c_conftest_c11_program="${ac_c_conftest_c89_globals}
-${ac_c_conftest_c99_globals}
-${ac_c_conftest_c11_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- ${ac_c_conftest_c99_main}
- ${ac_c_conftest_c11_main}
- return ok;
-}
-"
-
-# Test code for whether the C compiler supports C99 (complete).
-ac_c_conftest_c99_program="${ac_c_conftest_c89_globals}
-${ac_c_conftest_c99_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- ${ac_c_conftest_c99_main}
- return ok;
-}
-"
-
-# Test code for whether the C compiler supports C89 (complete).
-ac_c_conftest_c89_program="${ac_c_conftest_c89_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- return ok;
-}
-"
-
-as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H"
-as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H"
-as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H"
-as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
-as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
-as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
-as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
-as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
-as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
-for ac_var in $ac_precious_vars; do
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
eval ac_old_set=\$ac_cv_env_${ac_var}_set
eval ac_new_set=\$ac_env_${ac_var}_set
- eval ac_old_val=\$ac_cv_env_${ac_var}_value
- eval ac_new_val=\$ac_env_${ac_var}_value
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
case $ac_old_set,$ac_new_set in
set,)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5
-printf "%s\n" "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;}
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
ac_cache_corrupted=: ;;
,set)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5
-printf "%s\n" "$as_me: error: '$ac_var' was not set in the previous run" >&2;}
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
ac_cache_corrupted=: ;;
,);;
*)
if test "x$ac_old_val" != "x$ac_new_val"; then
- # differences in whitespace do not lead to failure.
- ac_old_val_w=`echo x $ac_old_val`
- ac_new_val_w=`echo x $ac_new_val`
- if test "$ac_old_val_w" != "$ac_new_val_w"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5
-printf "%s\n" "$as_me: error: '$ac_var' has changed since the previous run:" >&2;}
- ac_cache_corrupted=:
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5
-printf "%s\n" "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;}
- eval $ac_var=\$ac_old_val
- fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5
-printf "%s\n" "$as_me: former value: '$ac_old_val'" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5
-printf "%s\n" "$as_me: current value: '$ac_new_val'" >&2;}
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
fi;;
esac
# Pass precious variables to config.status.
if test "$ac_new_set" = set; then
case $ac_new_val in
- *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
*) ac_arg=$ac_var=$ac_new_val ;;
esac
case " $ac_configure_args " in
*" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
- *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
esac
fi
done
if $ac_cache_corrupted; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file'
- and start over" "$LINENO" 5
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
fi
-## -------------------- ##
-## Main body of script. ##
-## -------------------- ##
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
@@ -2409,34 +1287,43 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
# The following define is needed when building with Cygwin since newer
# versions of autoconf incorrectly set SHELL to /bin/bash instead of
# /bin/sh. The bash shell seems to suffer from some strange failures.
SHELL=/bin/sh
-TCL_VERSION=8.7
+TCL_VERSION=8.5
TCL_MAJOR_VERSION=8
-TCL_MINOR_VERSION=7
-TCL_PATCH_LEVEL="b1"
+TCL_MINOR_VERSION=5
+TCL_PATCH_LEVEL=".18"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION
-TCL_DDE_VERSION=1.4
+TCL_DDE_VERSION=1.3
TCL_DDE_MAJOR_VERSION=1
-TCL_DDE_MINOR_VERSION=4
+TCL_DDE_MINOR_VERSION=3
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION
-TCL_REG_VERSION=1.3
+TCL_REG_VERSION=1.2
TCL_REG_MAJOR_VERSION=1
-TCL_REG_MINOR_VERSION=3
+TCL_REG_MINOR_VERSION=2
REGVER=$TCL_REG_MAJOR_VERSION$TCL_REG_MINOR_VERSION
-PKG_CFG_ARGS=$@
-
-#------------------------------------------------------------------------
-# Empty slate for bundled packages, to avoid stale configuration
-#------------------------------------------------------------------------
-rm -Rf pkgs
-
#------------------------------------------------------------------------
# Handle the --prefix=... option
#------------------------------------------------------------------------
@@ -2460,15 +1347,6 @@ if test "${CFLAGS+set}" != "set" ; then
CFLAGS=""
fi
-
-
-
-
-
-
-
-
-
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -2477,164 +1355,172 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$CC"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
fi
if test -z "$ac_cv_prog_CC"; then
ac_ct_CC=$CC
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$ac_ct_CC"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="gcc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
+ CC=$ac_ct_CC
else
CC="$ac_cv_prog_CC"
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$CC"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}cc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
fi
if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$CC"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
ac_prog_rejected=no
@@ -2642,24 +1528,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
ac_prog_rejected=yes
continue
fi
ac_cv_prog_CC="cc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
if test $ac_prog_rejected = yes; then
# We found a bogon in the path, so make sure we never use it.
@@ -2670,280 +1551,146 @@ if test $ac_prog_rejected = yes; then
# However, it has the same basename, so the bogon will be chosen
# first if we set CC to just the basename; use the full file name.
shift
- ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@"
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
fi
fi
-fi ;;
-esac
+fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
fi
if test -z "$CC"; then
if test -n "$ac_tool_prefix"; then
- for ac_prog in cl.exe
+ for ac_prog in cl
do
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$CC"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
test -n "$CC" && break
done
fi
if test -z "$CC"; then
ac_ct_CC=$CC
- for ac_prog in cl.exe
+ for ac_prog in cl
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$ac_ct_CC"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
test -n "$ac_ct_CC" && break
done
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
-set dummy ${ac_tool_prefix}clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}clang"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi ;;
-esac
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "clang", so it can be a program name with args.
-set dummy clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="clang"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi ;;
-esac
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
+ CC=$ac_ct_CC
fi
fi
-test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
-as_fn_error $? "no acceptable C compiler found in \$PATH
-See 'config.log' for more details" "$LINENO" 5; }
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
# Provide some information about the compiler.
-printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-for ac_option in --version -v -V -qversion -version; do
- { { ac_try="$ac_compiler $ac_option >&5"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
ac_status=$?
- if test -s conftest.err; then
- sed '10a\
-... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
- cat conftest.er1 >&5
- fi
- rm -f conftest.er1 conftest.err
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-done
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
@@ -2951,213 +1698,155 @@ main (void)
}
_ACEOF
ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
# Try to create an executable without -o first, disregard a.out.
# It will help us diagnose broken compilers, and finding out an intuition
# of exeext.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-printf %s "checking whether the C compiler works... " >&6; }
-ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-
-# The possible output files:
-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
-
-ac_rmfiles=
-for ac_file in $ac_files
-do
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
- * ) ac_rmfiles="$ac_rmfiles $ac_file";;
- esac
-done
-rm -f $ac_rmfiles
-
-if { { ac_try="$ac_link_default"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link_default") 2>&5
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'.
-# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no'
-# in a Makefile. We should not override ac_cv_exeext if it was cached,
-# so that the user can short-circuit this test for compilers unknown to
-# Autoconf.
-for ac_file in $ac_files ''
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
do
test -f "$ac_file" || continue
case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
;;
[ab].out )
# We found the default executable, but exeext='' is most
# certainly right.
break;;
*.* )
- if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no;
- then :; else
- ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- fi
- # We set ac_cv_exeext here because the later test for it is not
- # safe: cross compilers may not add the suffix if given an '-o'
- # argument, so we may need to know it at that point already.
- # Even if this section looks crufty: it has the advantage of
- # actually working.
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
break;;
* )
break;;
esac
done
-test "$ac_cv_exeext" = no && ac_cv_exeext=
-
-else case e in #(
- e) ac_file='' ;;
-esac
-fi
-if test -z "$ac_file"
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-printf "%s\n" "$as_me: failed program was:" >&5
+else
+ echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
-as_fn_error 77 "C compiler cannot create executables
-See 'config.log' for more details" "$LINENO" 5; }
-else case e in #(
- e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; } ;;
-esac
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-printf %s "checking for C compiler default output file name... " >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-printf "%s\n" "$ac_file" >&6; }
+
ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
ac_clean_files=$ac_clean_files_save
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-printf %s "checking for suffix of executables... " >&6; }
-if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- # If both 'conftest.exe' and 'conftest' are 'present' (well, observable)
-# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will
-# work properly (i.e., refer to 'conftest.exe'), while it won't with
-# 'rm'.
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
for ac_file in conftest.exe conftest conftest.*; do
test -f "$ac_file" || continue
case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
*.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
break;;
* ) break;;
esac
done
-else case e in #(
- e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See 'config.log' for more details" "$LINENO" 5; } ;;
-esac
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
fi
-rm -f conftest conftest$ac_cv_exeext
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-printf "%s\n" "$ac_cv_exeext" >&6; }
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
rm -f conftest.$ac_ext
EXEEXT=$ac_cv_exeext
ac_exeext=$EXEEXT
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdio.h>
-int
-main (void)
-{
-FILE *f = fopen ("conftest.out", "w");
- if (!f)
- return 1;
- return ferror (f) || fclose (f) != 0;
-
- ;
- return 0;
-}
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
_ACEOF
-ac_clean_files="$ac_clean_files conftest.out"
-# Check that the compiler produces executables we can run. If not, either
-# the compiler is broken, or we cross compile.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-printf %s "checking whether we are cross compiling... " >&6; }
-if test "$cross_compiling" != yes; then
- { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- if { ac_try='./conftest$ac_cv_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }; then
- cross_compiling=no
- else
- if test "$cross_compiling" = maybe; then
- cross_compiling=yes
- else
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
-as_fn_error 77 "cannot run C compiled programs.
-If you meant to cross compile, use '--host'.
-See 'config.log' for more details" "$LINENO" 5; }
- fi
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-printf "%s\n" "$cross_compiling" >&6; }
-
-rm -f conftest.$ac_ext conftest$ac_cv_exeext \
- conftest.o conftest.obj conftest.out
-ac_clean_files=$ac_clean_files_save
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-printf %s "checking for suffix of object files... " >&6; }
-if test ${ac_cv_objext+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
@@ -3165,54 +1854,49 @@ main (void)
}
_ACEOF
rm -f conftest.o conftest.obj
-if { { ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compile") 2>&5
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- for ac_file in conftest.o conftest.obj conftest.*; do
- test -f "$ac_file" || continue;
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
*) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
break;;
esac
done
-else case e in #(
- e) printf "%s\n" "$as_me: failed program was:" >&5
+else
+ echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of object files: cannot compile
-See 'config.log' for more details" "$LINENO" 5; } ;;
-esac
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
fi
-rm -f conftest.$ac_cv_objext conftest.$ac_ext ;;
-esac
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-printf "%s\n" "$ac_cv_objext" >&6; }
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
OBJEXT=$ac_cv_objext
ac_objext=$OBJEXT
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
-printf %s "checking whether the compiler supports GNU C... " >&6; }
-if test ${ac_cv_c_compiler_gnu+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
int
-main (void)
+main ()
{
#ifndef __GNUC__
choke me
@@ -3222,100 +1906,99 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
ac_compiler_gnu=yes
-else case e in #(
- e) ac_compiler_gnu=no ;;
-esac
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
ac_cv_c_compiler_gnu=$ac_compiler_gnu
- ;;
-esac
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test $ac_compiler_gnu = yes; then
- GCC=yes
-else
- GCC=
fi
-ac_test_CFLAGS=${CFLAGS+y}
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
ac_save_CFLAGS=$CFLAGS
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-printf %s "checking whether $CC accepts -g... " >&6; }
-if test ${ac_cv_prog_cc_g+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) ac_save_c_werror_flag=$ac_c_werror_flag
- ac_c_werror_flag=yes
- ac_cv_prog_cc_g=no
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_g=yes
-else case e in #(
- e) CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else case e in #(
- e) ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag ;;
-esac
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
-if test $ac_test_CFLAGS; then
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
CFLAGS=$ac_save_CFLAGS
elif test $ac_cv_prog_cc_g = yes; then
if test "$GCC" = yes; then
@@ -3330,155 +2013,264 @@ else
CFLAGS=
fi
fi
-ac_prog_cc_stdc=no
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
-printf %s "checking for $CC option to enable C11 features... " >&6; }
-if test ${ac_cv_prog_cc_c11+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) ac_cv_prog_cc_c11=no
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$ac_c_conftest_c11_program
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
_ACEOF
-for ac_arg in '' -std=gnu11
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
do
CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c11=$ac_arg
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c11" != "xno" && break
+rm -f conftest.err conftest.$ac_objext
done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC ;;
-esac
-fi
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
-if test "x$ac_cv_prog_cc_c11" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else case e in #(
- e) if test "x$ac_cv_prog_cc_c11" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else case e in #(
- e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
-printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
- CC="$CC $ac_cv_prog_cc_c11" ;;
-esac
fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
- ac_prog_cc_stdc=c11 ;;
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
esac
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
-printf %s "checking for $CC option to enable C99 features... " >&6; }
-if test ${ac_cv_prog_cc_c99+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) ac_cv_prog_cc_c99=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c99_program
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c99=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c99" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC ;;
-esac
-fi
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
-if test "x$ac_cv_prog_cc_c99" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else case e in #(
- e) if test "x$ac_cv_prog_cc_c99" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else case e in #(
- e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
- CC="$CC $ac_cv_prog_cc_c99" ;;
-esac
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
- ac_prog_cc_stdc=c99 ;;
-esac
-fi
+continue
fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
-printf %s "checking for $CC option to enable C89 features... " >&6; }
-if test ${ac_cv_prog_cc_c89+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$ac_c_conftest_c89_program
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c89=$ac_arg
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c89" != "xno" && break
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC ;;
-esac
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
fi
-if test "x$ac_cv_prog_cc_c89" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else case e in #(
- e) if test "x$ac_cv_prog_cc_c89" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else case e in #(
- e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
- CC="$CC $ac_cv_prog_cc_c89" ;;
-esac
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
- ac_prog_cc_stdc=c89 ;;
-esac
-fi
-fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -3486,35 +2278,61 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
-printf %s "checking for inline... " >&6; }
-if test ${ac_cv_c_inline+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) ac_cv_c_inline=no
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_c_inline=no
for ac_kw in inline __inline__ __inline; do
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#ifndef __cplusplus
typedef int foo_t;
-static $ac_kw foo_t static_foo (void) {return 0; }
-$ac_kw foo_t foo (void) {return 0; }
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
#endif
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_c_inline=$ac_kw
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_inline=$ac_kw; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- test "$ac_cv_c_inline" != no && break
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
done
- ;;
-esac
+
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
-printf "%s\n" "$ac_cv_c_inline" >&6; }
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
case $ac_cv_c_inline in
inline | yes) ;;
@@ -3531,107 +2349,498 @@ _ACEOF
;;
esac
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
set dummy ${ac_tool_prefix}ar; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_AR+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$AR"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AR"; then
ac_cv_prog_AR="$AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_AR="${ac_tool_prefix}ar"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
AR=$ac_cv_prog_AR
if test -n "$AR"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
-printf "%s\n" "$AR" >&6; }
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
fi
if test -z "$ac_cv_prog_AR"; then
ac_ct_AR=$AR
# Extract the first word of "ar", so it can be a program name with args.
set dummy ar; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_AR+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$ac_ct_AR"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_AR"; then
ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_AR="ar"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
ac_ct_AR=$ac_cv_prog_ac_ct_AR
if test -n "$ac_ct_AR"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
-printf "%s\n" "$ac_ct_AR" >&6; }
+ echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+echo "${ECHO_T}$ac_ct_AR" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
- if test "x$ac_ct_AR" = x; then
- AR=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- AR=$ac_ct_AR
- fi
+ AR=$ac_ct_AR
else
AR="$ac_cv_prog_AR"
fi
@@ -3639,103 +2848,78 @@ fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$RANLIB"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
RANLIB=$ac_cv_prog_RANLIB
if test -n "$RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-printf "%s\n" "$RANLIB" >&6; }
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
fi
if test -z "$ac_cv_prog_RANLIB"; then
ac_ct_RANLIB=$RANLIB
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$ac_ct_RANLIB"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_RANLIB="ranlib"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
if test -n "$ac_ct_RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-printf "%s\n" "$ac_ct_RANLIB" >&6; }
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
- if test "x$ac_ct_RANLIB" = x; then
- RANLIB=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- RANLIB=$ac_ct_RANLIB
- fi
+ RANLIB=$ac_ct_RANLIB
else
RANLIB="$ac_cv_prog_RANLIB"
fi
@@ -3743,103 +2927,78 @@ fi
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args.
set dummy ${ac_tool_prefix}windres; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_RC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$RC"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RC"; then
ac_cv_prog_RC="$RC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_RC="${ac_tool_prefix}windres"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
RC=$ac_cv_prog_RC
if test -n "$RC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RC" >&5
-printf "%s\n" "$RC" >&6; }
+ echo "$as_me:$LINENO: result: $RC" >&5
+echo "${ECHO_T}$RC" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
fi
if test -z "$ac_cv_prog_RC"; then
ac_ct_RC=$RC
# Extract the first word of "windres", so it can be a program name with args.
set dummy windres; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_RC+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$ac_ct_RC"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RC"; then
ac_cv_prog_ac_ct_RC="$ac_ct_RC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_RC="windres"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
-fi ;;
-esac
+fi
fi
ac_ct_RC=$ac_cv_prog_ac_ct_RC
if test -n "$ac_ct_RC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RC" >&5
-printf "%s\n" "$ac_ct_RC" >&6; }
+ echo "$as_me:$LINENO: result: $ac_ct_RC" >&5
+echo "${ECHO_T}$ac_ct_RC" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
- if test "x$ac_ct_RC" = x; then
- RC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- RC=$ac_ct_RC
- fi
+ RC=$ac_ct_RC
else
RC="$ac_cv_prog_RC"
fi
@@ -3849,36 +3008,32 @@ fi
# Checks to see if the make program sets the $MAKE variable.
#--------------------------------------------------------------------
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
-printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
-set x ${MAKE-make}
-ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
-if eval test \${ac_cv_prog_make_${ac_make}_set+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat >conftest.make <<\_ACEOF
-SHELL = /bin/sh
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
all:
- @echo '@@@%%%=$(MAKE)=@@@%%%'
+ @echo 'ac_maketemp="$(MAKE)"'
_ACEOF
-# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
-case `${MAKE-make} -f conftest.make 2>/dev/null` in
- *@@@%%%=?*=@@@%%%*)
- eval ac_cv_prog_make_${ac_make}_set=yes;;
- *)
- eval ac_cv_prog_make_${ac_make}_set=no;;
-esac
-rm -f conftest.make ;;
-esac
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
fi
-if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
SET_MAKE=
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
SET_MAKE="MAKE=${MAKE-make}"
fi
@@ -3890,24 +3045,65 @@ fi
+#--------------------------------------------------------------------
+# Check whether --enable-threads or --disable-threads was given.
+#--------------------------------------------------------------------
+
+
+ echo "$as_me:$LINENO: checking for building with threads" >&5
+echo $ECHO_N "checking for building with threads... $ECHO_C" >&6
+ # Check whether --enable-threads or --disable-threads was given.
+if test "${enable_threads+set}" = set; then
+ enableval="$enable_threads"
+ tcl_ok=$enableval
+else
+ tcl_ok=no
+fi;
+
+ if test "$tcl_ok" = "yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ TCL_THREADS=1
+ cat >>confdefs.h <<\_ACEOF
+#define TCL_THREADS 1
+_ACEOF
+
+ # USE_THREAD_ALLOC tells us to try the special thread-based
+ # allocator that significantly reduces lock contention
+ cat >>confdefs.h <<\_ACEOF
+#define USE_THREAD_ALLOC 1
+_ACEOF
+
+ else
+ TCL_THREADS=0
+ echo "$as_me:$LINENO: result: no (default)" >&5
+echo "${ECHO_T}no (default)" >&6
+ fi
+
+
+
#------------------------------------------------------------------------
# Embedded configuration information, encoding to use for the values, TIP #59
#------------------------------------------------------------------------
-# Check whether --with-encoding was given.
-if test ${with_encoding+y}
-then :
- withval=$with_encoding; with_tcencoding=${withval}
-fi
-
+# Check whether --with-encoding or --without-encoding was given.
+if test "${with_encoding+set}" = set; then
+ withval="$with_encoding"
+ with_tcencoding=${withval}
+fi;
if test x"${with_tcencoding}" != x ; then
- printf "%s\n" "#define TCL_CFGVAL_ENCODING \"${with_tcencoding}\"" >>confdefs.h
+ cat >>confdefs.h <<_ACEOF
+#define TCL_CFGVAL_ENCODING "${with_tcencoding}"
+_ACEOF
else
- printf "%s\n" "#define TCL_CFGVAL_ENCODING \"utf-8\"" >>confdefs.h
+ # Default encoding on windows is not "iso8859-1"
+ cat >>confdefs.h <<\_ACEOF
+#define TCL_CFGVAL_ENCODING "cp1252"
+_ACEOF
fi
@@ -3918,74 +3114,46 @@ fi
#--------------------------------------------------------------------
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5
-printf %s "checking how to build libraries... " >&6; }
- # Check whether --enable-shared was given.
-if test ${enable_shared+y}
-then :
- enableval=$enable_shared; tcl_ok=$enableval
-else case e in #(
- e) tcl_ok=yes ;;
-esac
-fi
+ echo "$as_me:$LINENO: checking how to build libraries" >&5
+echo $ECHO_N "checking how to build libraries... $ECHO_C" >&6
+ # Check whether --enable-shared or --disable-shared was given.
+if test "${enable_shared+set}" = set; then
+ enableval="$enable_shared"
+ tcl_ok=$enableval
+else
+ tcl_ok=yes
+fi;
+
+ if test "${enable_shared+set}" = set; then
+ enableval="$enable_shared"
+ tcl_ok=$enableval
+ else
+ tcl_ok=yes
+ fi
if test "$tcl_ok" = "yes" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: shared" >&5
-printf "%s\n" "shared" >&6; }
+ echo "$as_me:$LINENO: result: shared" >&5
+echo "${ECHO_T}shared" >&6
SHARED_BUILD=1
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: static" >&5
-printf "%s\n" "static" >&6; }
+ echo "$as_me:$LINENO: result: static" >&5
+echo "${ECHO_T}static" >&6
SHARED_BUILD=0
-printf "%s\n" "#define STATIC_BUILD 1" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define STATIC_BUILD 1
+_ACEOF
fi
-
-#--------------------------------------------------------------------
-# Check whether --enable-time64bit was given.
-#--------------------------------------------------------------------
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking force of 64-bit time_t" >&5
-printf %s "checking force of 64-bit time_t... " >&6; }
-# Check whether --enable-time64bit was given.
-if test ${enable_time64bit+y}
-then :
- enableval=$enable_time64bit; tcl_ok=$enableval
-else case e in #(
- e) tcl_ok=no ;;
-esac
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$tcl_ok\"" >&5
-printf "%s\n" "\"$tcl_ok\"" >&6; }
-if test "$tcl_ok" = "yes"; then
- CFLAGS="${CFLAGS} -D_USE_64BIT_TIME_T"
-fi
-
#--------------------------------------------------------------------
# The statements below define a collection of compile flags. This
# macro depends on the value of SHARED_BUILD, and should be called
# after SC_ENABLE_SHARED checks the configure switches.
#--------------------------------------------------------------------
-ac_header= ac_cache=
-for ac_item in $ac_header_c_list
-do
- if test $ac_cache; then
- ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
- if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
- printf "%s\n" "#define $ac_item 1" >> confdefs.h
- fi
- ac_header= ac_cache=
- elif test $ac_header; then
- ac_cache=$ac_item
- else
- ac_header=$ac_item
- fi
-done
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
@@ -3994,185 +3162,230 @@ done
-if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
-then :
-printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
fi
+done
- # Step 0: Enable 64 bit support?
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5
-printf %s "checking if 64bit support is requested... " >&6; }
- # Check whether --enable-64bit was given.
-if test ${enable_64bit+y}
-then :
- enableval=$enable_64bit; do64bit=$enableval
-else case e in #(
- e) do64bit=no ;;
-esac
-fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $do64bit" >&5
-printf "%s\n" "$do64bit" >&6; }
- # Set some defaults (may get changed below)
- EXTRA_CFLAGS=""
+ # Step 0: Enable 64 bit support?
-printf "%s\n" "#define MODULE_SCOPE extern" >>confdefs.h
+ echo "$as_me:$LINENO: checking if 64bit support is requested" >&5
+echo $ECHO_N "checking if 64bit support is requested... $ECHO_C" >&6
+ # Check whether --enable-64bit or --disable-64bit was given.
+if test "${enable_64bit+set}" = set; then
+ enableval="$enable_64bit"
+ do64bit=$enableval
+else
+ do64bit=no
+fi;
+ echo "$as_me:$LINENO: result: $do64bit" >&5
+echo "${ECHO_T}$do64bit" >&6
+
+ # Cross-compiling options for Windows/CE builds
+
+ echo "$as_me:$LINENO: checking if Windows/CE build is requested" >&5
+echo $ECHO_N "checking if Windows/CE build is requested... $ECHO_C" >&6
+ # Check whether --enable-wince or --disable-wince was given.
+if test "${enable_wince+set}" = set; then
+ enableval="$enable_wince"
+ doWince=$enableval
+else
+ doWince=no
+fi;
+ echo "$as_me:$LINENO: result: $doWince" >&5
+echo "${ECHO_T}$doWince" >&6
+
+ echo "$as_me:$LINENO: checking for Windows/CE celib directory" >&5
+echo $ECHO_N "checking for Windows/CE celib directory... $ECHO_C" >&6
+
+# Check whether --with-celib or --without-celib was given.
+if test "${with_celib+set}" = set; then
+ withval="$with_celib"
+ CELIB_DIR=$withval
+else
+ CELIB_DIR=NO_CELIB
+fi;
+ echo "$as_me:$LINENO: result: $CELIB_DIR" >&5
+echo "${ECHO_T}$CELIB_DIR" >&6
+ # Set some defaults (may get changed below)
+ EXTRA_CFLAGS=""
# Extract the first word of "cygpath", so it can be a program name with args.
set dummy cygpath; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CYGPATH+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$CYGPATH"; then
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CYGPATH+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CYGPATH"; then
ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CYGPATH="cygpath -m"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
- done
-IFS=$as_save_IFS
+done
test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo"
-fi ;;
-esac
+fi
fi
CYGPATH=$ac_cv_prog_CYGPATH
if test -n "$CYGPATH"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5
-printf "%s\n" "$CYGPATH" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- # Extract the first word of "wine", so it can be a program name with args.
-set dummy wine; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_WINE+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -n "$WINE"; then
- ac_cv_prog_WINE="$WINE" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_WINE="wine"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi ;;
-esac
-fi
-WINE=$ac_cv_prog_WINE
-if test -n "$WINE"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WINE" >&5
-printf "%s\n" "$WINE" >&6; }
+ echo "$as_me:$LINENO: result: $CYGPATH" >&5
+echo "${ECHO_T}$CYGPATH" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
SHLIB_SUFFIX=".dll"
# MACHINE is IX86 for LINK, but this is used by the manifest,
- # which requires x86|amd64|arm64|ia64.
+ # which requires x86|amd64|ia64.
MACHINE="X86"
if test "$GCC" = "yes"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cross-compile version of gcc" >&5
-printf %s "checking for cross-compile version of gcc... " >&6; }
-if test ${ac_cv_cross+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ echo "$as_me:$LINENO: checking for cross-compile version of gcc" >&5
+echo $ECHO_N "checking for cross-compile version of gcc... $ECHO_C" >&6
+if test "${ac_cv_cross+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
- #ifndef _WIN32
+ #ifndef __WIN32__
#error cross-compiler
#endif
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
ac_cv_cross=no
-else case e in #(
- e) ac_cv_cross=yes ;;
-esac
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_cross=yes
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ;;
-esac
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cross" >&5
-printf "%s\n" "$ac_cv_cross" >&6; }
+echo "$as_me:$LINENO: result: $ac_cv_cross" >&5
+echo "${ECHO_T}$ac_cv_cross" >&6
if test "$ac_cv_cross" = "yes"; then
case "$do64bit" in
amd64|x64|yes)
- CC="x86_64-w64-mingw32-${CC}"
+ CC="x86_64-w64-mingw32-gcc"
LD="x86_64-w64-mingw32-ld"
AR="x86_64-w64-mingw32-ar"
RANLIB="x86_64-w64-mingw32-ranlib"
RC="x86_64-w64-mingw32-windres"
;;
- arm64|aarch64)
- CC="aarch64-w64-mingw32-${CC}"
- LD="aarch64-w64-mingw32-ld"
- AR="aarch64-w64-mingw32-ar"
- RANLIB="aarch64-w64-mingw32-ranlib"
- RC="aarch64-w64-mingw32-windres"
- ;;
*)
- CC="i686-w64-mingw32-${CC}"
+ CC="i686-w64-mingw32-gcc"
LD="i686-w64-mingw32-ld"
AR="i686-w64-mingw32-ar"
RANLIB="i686-w64-mingw32-ranlib"
@@ -4195,20 +3408,20 @@ printf "%s\n" "$ac_cv_cross" >&6; }
echo "101 \"name\"" >> $conftest
echo "END" >> $conftest
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Windows native path bug in windres" >&5
-printf %s "checking for Windows native path bug in windres... " >&6; }
+ echo "$as_me:$LINENO: checking for Windows native path bug in windres" >&5
+echo $ECHO_N "checking for Windows native path bug in windres... $ECHO_C" >&6
cyg_conftest=`$CYGPATH $conftest`
if { ac_try='$RC -o conftest.res.o $cyg_conftest'
- { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; } ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } ; then
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
CYGPATH=echo
fi
conftest=
@@ -4226,254 +3439,79 @@ printf "%s\n" "yes" >&6; }
if test "${GCC}" = "yes" ; then
extra_cflags="-pipe"
extra_ldflags="-pipe -static-libgcc"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mingw32 version of gcc" >&5
-printf %s "checking for mingw32 version of gcc... " >&6; }
-if test ${ac_cv_win32+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ echo "$as_me:$LINENO: checking for mingw32 version of gcc" >&5
+echo $ECHO_N "checking for mingw32 version of gcc... $ECHO_C" >&6
+if test "${ac_cv_win32+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
- #ifdef _WIN32
+ #ifdef __WIN32__
#error win32
#endif
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_win32=no
-else case e in #(
- e) ac_cv_win32=yes ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ;;
-esac
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_win32" >&5
-printf "%s\n" "$ac_cv_win32" >&6; }
- if test "$ac_cv_win32" != "yes"; then
- as_fn_error $? "${CC} cannot produce win32 executables." "$LINENO" 5
- fi
- if test "$do64bit" != "arm64"; then
- extra_cflags="$extra_cflags -DHAVE_CPUID=1"
- fi
-
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -mwindows -municode -Dmain=xxmain"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working -municode linker flag" >&5
-printf %s "checking for working -municode linker flag... " >&6; }
-if test ${ac_cv_municode+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e)
-# ac_fn_c_try_link LINENO
-# -----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_link ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>conftest.err
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest$ac_exeext && {
- test "$cross_compiling" = yes ||
- test -x conftest$ac_exeext
- }
-then :
- ac_retval=0
-else case e in #(
- e) printf "%s\n" "$as_me: failed program was:" >&5
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_win32=no
+else
+ echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
- ac_retval=1 ;;
-esac
-fi
- # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
- # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
- # interfere with the next link command; also delete a directory that is
- # left behind by Apple's compiler. We do this before executing the actions.
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_link
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
- #include <windows.h>
- int APIENTRY wWinMain(HINSTANCE a, HINSTANCE b, LPWSTR c, int d) {return 0;}
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_municode=yes
-else case e in #(
- e) ac_cv_municode=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- ;;
-esac
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_municode" >&5
-printf "%s\n" "$ac_cv_municode" >&6; }
- CFLAGS=$hold_cflags
- if test "$ac_cv_municode" = "yes" ; then
- extra_ldflags="$extra_ldflags -municode"
- else
- extra_cflags="$extra_cflags -DTCL_BROKEN_MAINARGS"
- fi
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -fno-lto"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working -fno-lto" >&5
-printf %s "checking for working -fno-lto... " >&6; }
-if test ${ac_cv_nolto+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_nolto=yes
-else case e in #(
- e) ac_cv_nolto=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ;;
-esac
+ac_cv_win32=yes
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_nolto" >&5
-printf "%s\n" "$ac_cv_nolto" >&6; }
- CFLAGS=$hold_cflags
- if test "$ac_cv_nolto" = "yes" ; then
- CFLAGS_NOLTO="-fno-lto"
- else
- CFLAGS_NOLTO=""
- fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the compiler understands -finput-charset" >&5
-printf %s "checking if the compiler understands -finput-charset... " >&6; }
-if test ${tcl_cv_cc_input_charset+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e)
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -finput-charset=UTF-8"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_cc_input_charset=yes
-else case e in #(
- e) tcl_cv_cc_input_charset=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- CFLAGS=$hold_cflags ;;
-esac
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_input_charset" >&5
-printf "%s\n" "$tcl_cv_cc_input_charset" >&6; }
- if test $tcl_cv_cc_input_charset = yes; then
- extra_cflags="$extra_cflags -finput-charset=UTF-8"
+echo "$as_me:$LINENO: result: $ac_cv_win32" >&5
+echo "${ECHO_T}$ac_cv_win32" >&6
+ if test "$ac_cv_win32" != "yes"; then
+ { { echo "$as_me:$LINENO: error: ${CC} cannot produce win32 executables." >&5
+echo "$as_me: error: ${CC} cannot produce win32 executables." >&2;}
+ { (exit 1); exit 1; }; }
fi
fi
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Wl,--enable-auto-image-base"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working --enable-auto-image-base" >&5
-printf %s "checking for working --enable-auto-image-base... " >&6; }
-if test ${ac_cv_enable_auto_image_base+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_enable_auto_image_base=yes
-else case e in #(
- e) ac_cv_enable_auto_image_base=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ;;
-esac
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_enable_auto_image_base" >&5
-printf "%s\n" "$ac_cv_enable_auto_image_base" >&6; }
- CFLAGS=$hold_cflags
- if test "$ac_cv_enable_auto_image_base" == "yes" ; then
- extra_ldflags="$extra_ldflags -Wl,--enable-auto-image-base"
- fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking compiler flags" >&5
-printf %s "checking compiler flags... " >&6; }
+ echo "$as_me:$LINENO: checking compiler flags" >&5
+echo $ECHO_N "checking compiler flags... $ECHO_C" >&6
if test "${GCC}" = "yes" ; then
SHLIB_LD=""
- SHLIB_LD_LIBS='${LIBS}'
- LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -luserenv -lws2_32"
+ SHLIB_LD_LIBS=""
+ LIBS="-lws2_32"
# mingw needs to link ole32 and oleaut32 for [send], but MSVC doesn't
- LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32 -luuid -lole32 -loleaut32 -lwinspool"
+ LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32 -luuid -lole32 -loleaut32"
STLIB_LD='${AR} cr'
RC_OUT=-o
RC_TYPE=
@@ -4488,58 +3526,55 @@ printf %s "checking compiler flags... " >&6; }
if test "${SHARED_BUILD}" = "0" ; then
# static
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using static flags" >&5
-printf "%s\n" "using static flags" >&6; }
+ echo "$as_me:$LINENO: result: using static flags" >&5
+echo "${ECHO_T}using static flags" >&6
runtime=
+ MAKE_DLL="echo "
+ LIBSUFFIX="s\${DBGX}.a"
+ LIBFLAGSUFFIX="s\${DBGX}"
LIBRARIES="\${STATIC_LIBRARIES}"
- EXESUFFIX="s.exe"
+ EXESUFFIX="s\${DBGX}.exe"
else
# dynamic
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using shared flags" >&5
-printf "%s\n" "using shared flags" >&6; }
+ echo "$as_me:$LINENO: result: using shared flags" >&5
+echo "${ECHO_T}using shared flags" >&6
# ad-hoc check to see if CC supports -shared.
if "${CC}" -shared 2>&1 | egrep ': -shared not supported' >/dev/null; then
- as_fn_error $? "${CC} does not support the -shared option.
- You will need to upgrade to a newer version of the toolchain." "$LINENO" 5
+ { { echo "$as_me:$LINENO: error: ${CC} does not support the -shared option.
+ You will need to upgrade to a newer version of the toolchain." >&5
+echo "$as_me: error: ${CC} does not support the -shared option.
+ You will need to upgrade to a newer version of the toolchain." >&2;}
+ { (exit 1); exit 1; }; }
fi
runtime=
+ # Link with gcc since ld does not link to default libs like
+ # -luser32 and -lmsvcrt by default.
+ SHLIB_LD='${CC} -shared'
+ SHLIB_LD_LIBS='${LIBS}'
# Add SHLIB_LD_LIBS to the Make rule, not here.
+ MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -o \$@ ${extra_ldflags} \
+ -Wl,--out-implib,\$(patsubst %.dll,lib%.a,\$@)"
- EXESUFFIX=".exe"
+ LIBSUFFIX="\${DBGX}.a"
+ LIBFLAGSUFFIX="\${DBGX}"
+ EXESUFFIX="\${DBGX}.exe"
LIBRARIES="\${SHARED_LIBRARIES}"
fi
- # Link with gcc since ld does not link to default libs like
- # -luser32 and -lmsvcrt by default.
- SHLIB_LD='${CC} -shared'
- SHLIB_LD_LIBS='${LIBS}'
- MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -o \$@ ${extra_ldflags} \
- -Wl,--out-implib,\$(patsubst %.dll,lib%.dll.a,\$@)"
# DLLSUFFIX is separate because it is the building block for
# users of tclConfig.sh that may build shared or static.
- DLLSUFFIX=".dll"
- LIBSUFFIX=".a"
- LIBFLAGSUFFIX=""
+ DLLSUFFIX="\${DBGX}.dll"
SHLIB_SUFFIX=.dll
EXTRA_CFLAGS="${extra_cflags}"
CFLAGS_DEBUG=-g
CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
- CFLAGS_WARNING="-Wall -Wextra -Wshadow -Wundef -Wwrite-strings -Wpointer-arith"
+ CFLAGS_WARNING="-Wall"
LDFLAGS_DEBUG=
LDFLAGS_OPTIMIZE=
- case "${CC}" in
- *++)
- CFLAGS_WARNING="${CFLAGS_WARNING} -Wno-format"
- ;;
- *)
- CFLAGS_WARNING="${CFLAGS_WARNING} -Wc++-compat -fextended-identifiers"
- ;;
- esac
-
# Specify the CC output file names based on the target name
CC_OBJNAME="-o \$@"
CC_EXENAME="-o \$@"
@@ -4564,21 +3599,20 @@ printf "%s\n" "using shared flags" >&6; }
case "$do64bit" in
amd64|x64|yes)
MACHINE="AMD64" ; # assume AMD64 as default 64-bit build
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5
-printf "%s\n" " Using 64-bit $MACHINE mode" >&6; }
- ;;
- arm64|aarch64)
- MACHINE="ARM64"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using ARM64 $MACHINE mode" >&5
-printf "%s\n" " Using ARM64 $MACHINE mode" >&6; }
+ echo "$as_me:$LINENO: result: Using 64-bit $MACHINE mode" >&5
+echo "${ECHO_T} Using 64-bit $MACHINE mode" >&6
;;
ia64)
MACHINE="IA64"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using IA64 $MACHINE mode" >&5
-printf "%s\n" " Using IA64 $MACHINE mode" >&6; }
+ echo "$as_me:$LINENO: result: Using 64-bit $MACHINE mode" >&5
+echo "${ECHO_T} Using 64-bit $MACHINE mode" >&6
;;
*)
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#ifndef _WIN64
@@ -4586,46 +3620,76 @@ printf "%s\n" " Using IA64 $MACHINE mode" >&6; }
#endif
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
tcl_win_64bit=yes
-else case e in #(
- e) tcl_win_64bit=no
- ;;
-esac
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_win_64bit=no
+
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
if test "$tcl_win_64bit" = "yes" ; then
- do64bit=amd64
- MACHINE="AMD64"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5
-printf "%s\n" " Using 64-bit $MACHINE mode" >&6; }
+ do64bit=amd64
+ MACHINE="AMD64"
+ echo "$as_me:$LINENO: result: Using 64-bit $MACHINE mode" >&5
+echo "${ECHO_T} Using 64-bit $MACHINE mode" >&6
fi
;;
esac
else
if test "${SHARED_BUILD}" = "0" ; then
# static
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using static flags" >&5
-printf "%s\n" "using static flags" >&6; }
+ echo "$as_me:$LINENO: result: using static flags" >&5
+echo "${ECHO_T}using static flags" >&6
runtime=-MT
+ MAKE_DLL="echo "
+ LIBSUFFIX="s\${DBGX}.lib"
+ LIBFLAGSUFFIX="s\${DBGX}"
LIBRARIES="\${STATIC_LIBRARIES}"
- EXESUFFIX="s.exe"
+ EXESUFFIX="s\${DBGX}.exe"
+ SHLIB_LD_LIBS=""
else
# dynamic
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using shared flags" >&5
-printf "%s\n" "using shared flags" >&6; }
+ echo "$as_me:$LINENO: result: using shared flags" >&5
+echo "${ECHO_T}using shared flags" >&6
runtime=-MD
# Add SHLIB_LD_LIBS to the Make rule, not here.
+ MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -out:\$@"
+ LIBSUFFIX="\${DBGX}.lib"
+ LIBFLAGSUFFIX="\${DBGX}"
+ EXESUFFIX="\${DBGX}.exe"
LIBRARIES="\${SHARED_LIBRARIES}"
- EXESUFFIX=".exe"
+ SHLIB_LD_LIBS='${LIBS}'
case "x`echo \${VisualStudioVersion}`" in
x1[4-9]*)
lflags="${lflags} -nodefaultlib:libucrt.lib"
@@ -4634,30 +3698,38 @@ printf "%s\n" "using shared flags" >&6; }
;;
esac
fi
- MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -out:\$@"
# DLLSUFFIX is separate because it is the building block for
# users of tclConfig.sh that may build shared or static.
- DLLSUFFIX=".dll"
- LIBSUFFIX=".lib"
- LIBFLAGSUFFIX=""
+ DLLSUFFIX="\${DBGX}.dll"
+ # This is a 2-stage check to make sure we have the 64-bit SDK
+ # We have to know where the SDK is installed.
+ # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs
if test "$do64bit" != "no" ; then
+ if test "x${MSSDK}x" = "xx" ; then
+ MSSDK="C:/Progra~1/Microsoft Platform SDK"
+ fi
+ MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'`
+ PATH64=""
case "$do64bit" in
amd64|x64|yes)
MACHINE="AMD64" ; # assume AMD64 as default 64-bit build
- ;;
- arm64|aarch64)
- MACHINE="ARM64"
+ PATH64="${MSSDK}/Bin/Win64/x86/AMD64"
;;
ia64)
MACHINE="IA64"
+ PATH64="${MSSDK}/Bin/Win64"
;;
esac
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5
-printf "%s\n" " Using 64-bit $MACHINE mode" >&6; }
+ if test ! -d "${PATH64}" ; then
+ { echo "$as_me:$LINENO: WARNING: Could not find 64-bit $MACHINE SDK" >&5
+echo "$as_me: WARNING: Could not find 64-bit $MACHINE SDK" >&2;}
+ fi
+ echo "$as_me:$LINENO: result: Using 64-bit $MACHINE mode" >&5
+echo "${ECHO_T} Using 64-bit $MACHINE mode" >&6
fi
- LIBS="netapi32.lib kernel32.lib user32.lib advapi32.lib userenv.lib ws2_32.lib"
+ LIBS="user32.lib advapi32.lib ws2_32.lib"
case "x`echo \${VisualStudioVersion}`" in
x1[4-9]*)
@@ -4668,11 +3740,81 @@ printf "%s\n" " Using 64-bit $MACHINE mode" >&6; }
esac
if test "$do64bit" != "no" ; then
- RC="rc"
+ # The space-based-path will work for the Makefile, but will
+ # not work if AC_TRY_COMPILE is called. TEA has the
+ # TEA_PATH_NOSPACE to avoid this issue.
+ # Check if _WIN64 is already recognized, and if so we don't
+ # need to modify CC.
+ echo "$as_me:$LINENO: checking whether _WIN64 is declared" >&5
+echo $ECHO_N "checking whether _WIN64 is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl__WIN64+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef _WIN64
+ char *p = (char *) _WIN64;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl__WIN64=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl__WIN64=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl__WIN64" >&5
+echo "${ECHO_T}$ac_cv_have_decl__WIN64" >&6
+if test $ac_cv_have_decl__WIN64 = yes; then
+ :
+else
+ CC="\"${PATH64}/cl.exe\" -I\"${MSSDK}/Include\" \
+ -I\"${MSSDK}/Include/crt\" \
+ -I\"${MSSDK}/Include/crt/sys\""
+fi
+
+ RC="\"${MSSDK}/bin/rc.exe\""
CFLAGS_DEBUG="-nologo -Zi -Od ${runtime}d"
- CFLAGS_OPTIMIZE="-nologo -O2 ${runtime}"
- lflags="${lflags} -nologo -MACHINE:${MACHINE}"
- LINKBIN="link"
+ # Do not use -O2 for Win64 - this has proved buggy in code gen.
+ CFLAGS_OPTIMIZE="-nologo -O1 ${runtime}"
+ lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\""
+ LINKBIN="\"${PATH64}/link.exe\""
# Avoid 'unresolved external symbol __security_cookie' errors.
# c.f. http://support.microsoft.com/?id=894573
LIBS="$LIBS bufferoverflowU.lib"
@@ -4687,10 +3829,113 @@ printf "%s\n" " Using 64-bit $MACHINE mode" >&6; }
LINKBIN="link"
fi
- LIBS_GUI="gdi32.lib comdlg32.lib imm32.lib comctl32.lib shell32.lib uuid.lib winspool.lib"
+ if test "$doWince" != "no" ; then
+ # Set defaults for common evc4/PPC2003 setup
+ # Currently Tcl requires 300+, possibly 420+ for sockets
+ CEVERSION=420; # could be 211 300 301 400 420 ...
+ TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ...
+ ARCH=ARM; # could be ARM MIPS X86EM ...
+ PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002"
+ if test "$doWince" != "yes"; then
+ # If !yes then the user specified something
+ # Reset ARCH to allow user to skip specifying it
+ ARCH=
+ eval `echo $doWince | awk -F "," '{ \
+ if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \
+ if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \
+ if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \
+ if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \
+ if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \
+ }'`
+ if test "x${ARCH}" = "x" ; then
+ ARCH=$TARGETCPU;
+ fi
+ fi
+ OSVERSION=WCE$CEVERSION;
+ if test "x${WCEROOT}" = "x" ; then
+ WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0"
+ if test ! -d "${WCEROOT}" ; then
+ WCEROOT="C:/Program Files/Microsoft eMbedded Tools"
+ fi
+ fi
+ if test "x${SDKROOT}" = "x" ; then
+ SDKROOT="C:/Program Files/Windows CE Tools"
+ if test ! -d "${SDKROOT}" ; then
+ SDKROOT="C:/Windows CE Tools"
+ fi
+ fi
+ # The space-based-path will work for the Makefile, but will
+ # not work if AC_TRY_COMPILE is called.
+ WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'`
+ SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'`
+ CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'`
+ if test ! -d "${CELIB_DIR}/inc"; then
+ { { echo "$as_me:$LINENO: error: Invalid celib directory \"${CELIB_DIR}\"" >&5
+echo "$as_me: error: Invalid celib directory \"${CELIB_DIR}\"" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}"\
+ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then
+ { { echo "$as_me:$LINENO: error: could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" >&5
+echo "$as_me: error: could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include"
+ if test -d "${CEINCLUDE}/${TARGETCPU}" ; then
+ CEINCLUDE="${CEINCLUDE}/${TARGETCPU}"
+ fi
+ CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}"
+ fi
+ fi
+
+ if test "$doWince" != "no" ; then
+ CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin"
+ if test "${TARGETCPU}" = "X86"; then
+ CC="${CEBINROOT}/cl.exe"
+ else
+ CC="${CEBINROOT}/cl${ARCH}.exe"
+ fi
+ CC="\"${CC}\" -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\""
+ RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\""
+ arch=`echo ${ARCH} | awk '{print tolower($0)}'`
+ defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _DLL _WINDOWS"
+ for i in $defs ; do
+ cat >>confdefs.h <<_ACEOF
+#define $i 1
+_ACEOF
+
+ done
+# if test "${ARCH}" = "X86EM"; then
+# AC_DEFINE_UNQUOTED(_WIN32_WCE_EMULATION)
+# fi
+ cat >>confdefs.h <<_ACEOF
+#define _WIN32_WCE $CEVERSION
+_ACEOF
+
+ cat >>confdefs.h <<_ACEOF
+#define UNDER_CE $CEVERSION
+_ACEOF
+
+ CFLAGS_DEBUG="-nologo -Zi -Od"
+ CFLAGS_OPTIMIZE="-nologo -O2"
+ lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'`
+ lflags="-nodefaultlib -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo"
+ LINKBIN="\"${CEBINROOT}/link.exe\""
+
+ if test "${CEVERSION}" -lt 400 ; then
+ LIBS="coredll.lib corelibc.lib winsock.lib"
+ else
+ LIBS="coredll.lib corelibc.lib ws2.lib"
+ fi
+ # celib currently stuck at wce300 status
+ #LIBS="$LIBS \${CELIB_DIR}/wince-${ARCH}-pocket-${OSVERSION}-release/celib.lib"
+ LIBS="$LIBS \"\${CELIB_DIR}/wince-${ARCH}-pocket-wce300-release/celib.lib\""
+ LIBS_GUI="commctrl.lib commdlg.lib"
+ else
+ LIBS_GUI="gdi32.lib comdlg32.lib imm32.lib comctl32.lib shell32.lib uuid.lib"
+ fi
SHLIB_LD="${LINKBIN} -dll -incremental:no ${lflags}"
- SHLIB_LD_LIBS='${LIBS}'
# link -lib only works when -lib is the first arg
STLIB_LD="${LINKBIN} -lib ${lflags}"
RC_OUT=-fo
@@ -4718,7 +3963,7 @@ printf "%s\n" " Using 64-bit $MACHINE mode" >&6; }
# Specify linker flags depending on the type of app being
# built -- Console vs. Window.
- if test "${TARGETCPU}" != "X86"; then
+ if test "$doWince" != "no" -a "${TARGETCPU}" != "X86"; then
LDFLAGS_CONSOLE="-link ${lflags}"
LDFLAGS_WINDOW=${LDFLAGS_CONSOLE}
else
@@ -4728,66 +3973,26 @@ printf "%s\n" " Using 64-bit $MACHINE mode" >&6; }
fi
if test "$do64bit" != "no" ; then
- printf "%s\n" "#define TCL_CFG_DO64BIT 1" >>confdefs.h
+ cat >>confdefs.h <<\_ACEOF
+#define TCL_CFG_DO64BIT 1
+_ACEOF
fi
if test "${GCC}" = "yes" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SEH support in compiler" >&5
-printf %s "checking for SEH support in compiler... " >&6; }
-if test ${tcl_cv_seh+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test "$cross_compiling" = yes
-then :
+ echo "$as_me:$LINENO: checking for SEH support in compiler" >&5
+echo $ECHO_N "checking for SEH support in compiler... $ECHO_C" >&6
+if test "${tcl_cv_seh+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
tcl_cv_seh=no
-else case e in #(
- e)
-# ac_fn_c_try_run LINENO
-# ----------------------
-# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that
-# executables *can* be run.
-ac_fn_c_try_run ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }
-then :
- ac_retval=0
-else case e in #(
- e) printf "%s\n" "$as_me: program exited with status $ac_status" >&5
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=$ac_status ;;
-esac
-fi
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_run
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#define WIN32_LEAN_AND_MEAN
@@ -4806,26 +4011,37 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"
-then :
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
tcl_cv_seh=yes
-else case e in #(
- e) tcl_cv_seh=no ;;
-esac
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+tcl_cv_seh=no
fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
-esac
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
- ;;
-esac
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_seh" >&5
-printf "%s\n" "$tcl_cv_seh" >&6; }
+echo "$as_me:$LINENO: result: $tcl_cv_seh" >&5
+echo "${ECHO_T}$tcl_cv_seh" >&6
if test "$tcl_cv_seh" = "no" ; then
-printf "%s\n" "#define HAVE_NO_SEH 1" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_SEH 1
+_ACEOF
fi
@@ -4835,13 +4051,16 @@ printf "%s\n" "#define HAVE_NO_SEH 1" >>confdefs.h
# with Cygwin's version as of 2002-04-10, define it to be int,
# sufficient for getting the current code to work.
#
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for EXCEPTION_DISPOSITION support in include files" >&5
-printf %s "checking for EXCEPTION_DISPOSITION support in include files... " >&6; }
-if test ${tcl_cv_eh_disposition+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ echo "$as_me:$LINENO: checking for EXCEPTION_DISPOSITION support in include files" >&5
+echo $ECHO_N "checking for EXCEPTION_DISPOSITION support in include files... $ECHO_C" >&6
+if test "${tcl_cv_eh_disposition+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
# define WIN32_LEAN_AND_MEAN
@@ -4849,7 +4068,7 @@ else case e in #(
# undef WIN32_LEAN_AND_MEAN
int
-main (void)
+main ()
{
EXCEPTION_DISPOSITION x;
@@ -4858,49 +4077,141 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
tcl_cv_eh_disposition=yes
-else case e in #(
- e) tcl_cv_eh_disposition=no ;;
-esac
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_cv_eh_disposition=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ;;
-esac
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_eh_disposition" >&5
-printf "%s\n" "$tcl_cv_eh_disposition" >&6; }
+echo "$as_me:$LINENO: result: $tcl_cv_eh_disposition" >&5
+echo "${ECHO_T}$tcl_cv_eh_disposition" >&6
if test "$tcl_cv_eh_disposition" = "no" ; then
-printf "%s\n" "#define EXCEPTION_DISPOSITION int" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define EXCEPTION_DISPOSITION int
+_ACEOF
fi
- ac_fn_c_check_header_compile "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdbool_h" = xyes
-then :
+ # Check to see if winnt.h defines CHAR, SHORT, and LONG
+ # even if VOID has already been #defined. The win32api
+ # used by mingw and cygwin is known to do this.
+
+ echo "$as_me:$LINENO: checking for winnt.h that ignores VOID define" >&5
+echo $ECHO_N "checking for winnt.h that ignores VOID define... $ECHO_C" >&6
+if test "${tcl_cv_winnt_ignore_void+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+ #define VOID void
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+ #undef WIN32_LEAN_AND_MEAN
+
+int
+main ()
+{
-printf "%s\n" "#define HAVE_STDBOOL_H 1" >>confdefs.h
+ CHAR c;
+ SHORT s;
+ LONG l;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tcl_cv_winnt_ignore_void=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_cv_winnt_ignore_void=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
fi
+echo "$as_me:$LINENO: result: $tcl_cv_winnt_ignore_void" >&5
+echo "${ECHO_T}$tcl_cv_winnt_ignore_void" >&6
+ if test "$tcl_cv_winnt_ignore_void" = "yes" ; then
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WINNT_IGNORE_VOID 1
+_ACEOF
+
+ fi
# See if the compiler supports casting to a union type.
# This is used to stop gcc from printing a compiler
# warning when initializing a union member.
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cast to union support" >&5
-printf %s "checking for cast to union support... " >&6; }
-if test ${tcl_cv_cast_to_union+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ echo "$as_me:$LINENO: checking for cast to union support" >&5
+echo $ECHO_N "checking for cast to union support... $ECHO_C" >&6
+if test "${tcl_cv_cast_to_union+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
int
-main (void)
+main ()
{
union foo { int i; double d; };
@@ -4910,22 +4221,45 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
tcl_cv_cast_to_union=yes
-else case e in #(
- e) tcl_cv_cast_to_union=no ;;
-esac
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_cv_cast_to_union=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ;;
-esac
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cast_to_union" >&5
-printf "%s\n" "$tcl_cv_cast_to_union" >&6; }
+echo "$as_me:$LINENO: result: $tcl_cv_cast_to_union" >&5
+echo "${ECHO_T}$tcl_cv_cast_to_union" >&6
if test "$tcl_cv_cast_to_union" = "yes"; then
-printf "%s\n" "#define HAVE_CAST_TO_UNION 1" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CAST_TO_UNION 1
+_ACEOF
fi
fi
@@ -4937,506 +4271,295 @@ printf "%s\n" "#define HAVE_CAST_TO_UNION 1" >>confdefs.h
+echo "$as_me:$LINENO: checking for intptr_t" >&5
+echo $ECHO_N "checking for intptr_t... $ECHO_C" >&6
+if test "${ac_cv_type_intptr_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((intptr_t *) 0)
+ return 0;
+if (sizeof (intptr_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_intptr_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
-# Cross-compiling
-case ${host_alias} in
-*mingw32*)
- TCL_EXE="tclsh"
- ;;
-*)
- TCL_EXE="TCL_LIBRARY=\"\${LIBRARY_DIR}\"; export TCL_LIBRARY; ./\${TCLSH}"
- ;;
-esac
-
-#------------------------------------------------------------------------
-# Add stuff for zlib/libtommath; note that this is mostly done in the
-# makefile now as we just assume that the platform hasn't got usable
-# z.lib/tommath.lib
-#------------------------------------------------------------------------
-
-if test "${enable_shared+set}" = "set"
-then :
-
- enableval="$enable_shared"
- tcl_ok=$enableval
-
-else case e in #(
- e)
- tcl_ok=yes
- ;;
-esac
-fi
-zlib_lib_name=zdll.lib
-tommath_lib_name=tommath.lib
-if test "$tcl_ok" = "yes"
-then :
-
- ZLIB_DLL_FILE=\${ZLIB_DLL_FILE}
-
- TOMMATH_DLL_FILE=\${TOMMATH_DLL_FILE}
-
-
-printf "%s\n" "#define TCL_WITH_EXTERNAL_TOMMATH 1" >>confdefs.h
-
- if test "$do64bit" != "no"
-then :
-
-
-printf "%s\n" "#define MP_64BIT 1" >>confdefs.h
-
- if test "$do64bit" = "arm64"
-then :
-
- if test "$GCC" == "yes"
-then :
-
- ZLIB_LIBS=\${ZLIB_DIR_NATIVE}/win64-arm/libz.dll.a
-
- TOMMATH_LIBS=\${TOMMATH_DIR_NATIVE}/win64-arm/libtommath.dll.a
-
- zlib_lib_name=libz.dll.a
- tommath_lib_name=libtommath.dll.a
-
-else case e in #(
- e)
- ZLIB_LIBS=\${ZLIB_DIR_NATIVE}/win64-arm/zdll.lib
-
- TOMMATH_LIBS=\${TOMMATH_DIR_NATIVE}/win64-arm/tommath.lib
-
- ;;
-esac
-fi
-
-else case e in #(
- e)
- if test "$GCC" == "yes"
-then :
-
- ZLIB_LIBS=\${ZLIB_DIR_NATIVE}/win64/libz.dll.a
-
- TOMMATH_LIBS=\${TOMMATH_DIR_NATIVE}/win64/libtommath.dll.a
-
- zlib_lib_name=libz.dll.a
- tommath_lib_name=libtommath.dll.a
-
-else case e in #(
- e)
- ZLIB_LIBS=\${ZLIB_DIR_NATIVE}/win64/zdll.lib
-
- TOMMATH_LIBS=\${TOMMATH_DIR_NATIVE}/win64/tommath.lib
-
- ;;
-esac
-fi
- ;;
-esac
-fi
-
-else case e in #(
- e)
- ZLIB_LIBS=\${ZLIB_DIR_NATIVE}/win32/zdll.lib
-
- TOMMATH_LIBS=\${TOMMATH_DIR_NATIVE}/win32/tommath.lib
-
- ;;
-esac
-fi
-
-else case e in #(
- e)
- ZLIB_OBJS=\${ZLIB_OBJS}
-
- TOMMATH_OBJS=\${TOMMATH_OBJS}
-
- ;;
-esac
-fi
-
-printf "%s\n" "#define HAVE_ZLIB 1" >>confdefs.h
-
-TCL_ZLIB_LIB_NAME=$zlib_lib_name
-
-TCL_TOMMATH_LIB_NAME=$tommath_lib_name
-
-ac_fn_c_check_type "$LINENO" "intptr_t" "ac_cv_type_intptr_t" "
-#include <stdint.h>
-
-"
-if test "x$ac_cv_type_intptr_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_INTPTR_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "
-#include <stdint.h>
-
-"
-if test "x$ac_cv_type_uintptr_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_UINTPTR_T 1" >>confdefs.h
-
-
-fi
-
-
-#--------------------------------------------------------------------
-# Zipfs support - Tip 430
-#--------------------------------------------------------------------
-# Check whether --enable-zipfs was given.
-if test ${enable_zipfs+y}
-then :
- enableval=$enable_zipfs; tcl_ok=$enableval
-else case e in #(
- e) tcl_ok=yes ;;
-esac
-fi
-
-if test "$tcl_ok" = "yes" ; then
- #
- # Find a native compiler
- #
- # Put a plausible default for CC_FOR_BUILD in Makefile.
-if test -z "$CC_FOR_BUILD"; then
- if test "x$cross_compiling" = "xno"; then
- CC_FOR_BUILD='$(CC)'
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gcc" >&5
-printf %s "checking for gcc... " >&6; }
- if test ${ac_cv_path_cc+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e)
- search_path=`echo ${PATH} | sed -e 's/:/ /g'`
- for dir in $search_path ; do
- for j in `ls -r $dir/gcc 2> /dev/null` \
- `ls -r $dir/gcc 2> /dev/null` ; do
- if test x"$ac_cv_path_cc" = x ; then
- if test -f "$j" ; then
- ac_cv_path_cc=$j
- break
- fi
- fi
- done
- done
- ;;
-esac
-fi
-
- fi
-fi
-
-# Also set EXEEXT_FOR_BUILD.
-if test "x$cross_compiling" = "xno"; then
- EXEEXT_FOR_BUILD='$(EXEEXT)'
- OBJEXT_FOR_BUILD='$(OBJEXT)'
-else
- OBJEXT_FOR_BUILD='.no'
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build system executable suffix" >&5
-printf %s "checking for build system executable suffix... " >&6; }
-if test ${bfd_cv_build_exeext+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) rm -f conftest*
- echo 'int main () { return 0; }' > conftest.c
- bfd_cv_build_exeext=
- ${CC_FOR_BUILD} -o conftest conftest.c 1>&5 2>&5
- for file in conftest.*; do
- case $file in
- *.c | *.o | *.obj | *.ilk | *.pdb) ;;
- *) bfd_cv_build_exeext=`echo $file | sed -e s/conftest//` ;;
- esac
- done
- rm -f conftest*
- test x"${bfd_cv_build_exeext}" = x && bfd_cv_build_exeext=no ;;
-esac
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_build_exeext" >&5
-printf "%s\n" "$bfd_cv_build_exeext" >&6; }
- EXEEXT_FOR_BUILD=""
- test x"${bfd_cv_build_exeext}" != xno && EXEEXT_FOR_BUILD=${bfd_cv_build_exeext}
-fi
-
- #
- # Find a native zip implementation
- #
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5
-printf %s "checking for tclsh... " >&6; }
-
- if test ${ac_cv_path_tclsh+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e)
- search_path=`echo ${PATH} | sed -e 's/:/ /g'`
- for dir in $search_path ; do
- for j in `ls -r $dir/tclsh[8-9]*.exe 2> /dev/null` \
- `ls -r $dir/tclsh* 2> /dev/null` ; do
- if test x"$ac_cv_path_tclsh" = x ; then
- if test -f "$j" ; then
- ac_cv_path_tclsh=$j
- break
- fi
- fi
- done
- done
- ;;
-esac
+ac_cv_type_intptr_t=no
fi
-
-
- if test -f "$ac_cv_path_tclsh" ; then
- TCLSH_PROG="$ac_cv_path_tclsh"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TCLSH_PROG" >&5
-printf "%s\n" "$TCLSH_PROG" >&6; }
- else
- # It is not an error if an installed version of Tcl can't be located.
- TCLSH_PROG=""
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: No tclsh found on PATH" >&5
-printf "%s\n" "No tclsh found on PATH" >&6; }
- fi
-
-
-
- ZIP_PROG=""
- ZIP_PROG_OPTIONS=""
- ZIP_PROG_VFSSEARCH=""
- ZIP_INSTALL_OBJS=""
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zip" >&5
-printf %s "checking for zip... " >&6; }
- if test ${ac_cv_path_zip+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e)
- search_path=`echo ${PATH} | sed -e 's/:/ /g'`
- for dir in $search_path ; do
- for j in `ls -r $dir/zip 2> /dev/null` \
- `ls -r $dir/zip 2> /dev/null` ; do
- if test x"$ac_cv_path_zip" = x ; then
- if test -f "$j" ; then
- ac_cv_path_zip=$j
- break
- fi
- fi
- done
- done
- ;;
-esac
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-
- if test -f "$ac_cv_path_zip" ; then
- ZIP_PROG="$ac_cv_path_zip"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ZIP_PROG" >&5
-printf "%s\n" "$ZIP_PROG" >&6; }
- ZIP_PROG_OPTIONS="-rq"
- ZIP_PROG_VFSSEARCH="*"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Found INFO Zip in environment" >&5
-printf "%s\n" "Found INFO Zip in environment" >&6; }
- # Use standard arguments for zip
- else
- # It is not an error if an installed version of Zip can't be located.
- # We can use the locally distributed minizip instead
- ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}"
- ZIP_PROG_OPTIONS="-o -r"
- ZIP_PROG_VFSSEARCH="*"
- ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: No zip found on PATH building minizip" >&5
-printf "%s\n" "No zip found on PATH building minizip" >&6; }
- fi
-
-
+echo "$as_me:$LINENO: result: $ac_cv_type_intptr_t" >&5
+echo "${ECHO_T}$ac_cv_type_intptr_t" >&6
+if test $ac_cv_type_intptr_t = yes; then
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_INTPTR_T 1
+_ACEOF
- ZIPFS_BUILD=1
- TCL_ZIP_FILE=libtcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_PATCH_LEVEL}.zip
else
- ZIPFS_BUILD=0
- TCL_ZIP_FILE=
-fi
-# Do checking message here to not mess up interleaved configure output
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for building with zipfs" >&5
-printf %s "checking for building with zipfs... " >&6; }
-if test "${ZIPFS_BUILD}" = 1; then
- if test "${SHARED_BUILD}" = 0; then
- ZIPFS_BUILD=2;
-
-printf "%s\n" "#define ZIPFS_BUILD 2" >>confdefs.h
-
- else
-printf "%s\n" "#define ZIPFS_BUILD 1" >>confdefs.h
-\
- fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
+ echo "$as_me:$LINENO: checking for pointer-size signed integer type" >&5
+echo $ECHO_N "checking for pointer-size signed integer type... $ECHO_C" >&6
+if test "${tcl_cv_intptr_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-INSTALL_LIBRARIES=install-libraries
-INSTALL_MSGS=install-msgs
-fi
-
-
-
-
-
-#--------------------------------------------------------------------
-# Perform additinal compiler tests.
-#--------------------------------------------------------------------
-
-# See if declarations like FINDEX_INFO_LEVELS are
-# missing from winbase.h. This is known to be
-# a problem with VC++ 5.2.
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for FINDEX_INFO_LEVELS in winbase.h" >&5
-printf %s "checking for FINDEX_INFO_LEVELS in winbase.h... " >&6; }
-if test ${tcl_cv_findex_enums+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ for tcl_cv_intptr_t in "int" "long" "long long" none; do
+ if test "$tcl_cv_intptr_t" != none; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-
+$ac_includes_default
int
-main (void)
+main ()
{
-
- FINDEX_INFO_LEVELS i;
- FINDEX_SEARCH_OPS j;
+static int test_array [1 - 2 * !(sizeof (void *) <= sizeof ($tcl_cv_intptr_t))];
+test_array [0] = 0
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_findex_enums=yes
-else case e in #(
- e) tcl_cv_findex_enums=no ;;
-esac
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tcl_ok=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_ok=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ;;
-esac
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$tcl_ok" = yes && break; fi
+ done
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_findex_enums" >&5
-printf "%s\n" "$tcl_cv_findex_enums" >&6; }
-if test "$tcl_cv_findex_enums" = "no"; then
+echo "$as_me:$LINENO: result: $tcl_cv_intptr_t" >&5
+echo "${ECHO_T}$tcl_cv_intptr_t" >&6
+ if test "$tcl_cv_intptr_t" != none; then
+
+cat >>confdefs.h <<_ACEOF
+#define intptr_t $tcl_cv_intptr_t
+_ACEOF
-printf "%s\n" "#define HAVE_NO_FINDEX_ENUMS 1" >>confdefs.h
+ fi
fi
-# See if the compiler supports intrinsics.
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for intrinsics support in compiler" >&5
-printf %s "checking for intrinsics support in compiler... " >&6; }
-if test ${tcl_cv_intrinsics+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+echo "$as_me:$LINENO: checking for uintptr_t" >&5
+echo $ECHO_N "checking for uintptr_t... $ECHO_C" >&6
+if test "${ac_cv_type_uintptr_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#include <intrin.h>
-
+$ac_includes_default
int
-main (void)
+main ()
{
-
- __cpuidex(0,0,0);
-
+if ((uintptr_t *) 0)
+ return 0;
+if (sizeof (uintptr_t))
+ return 0;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_intrinsics=yes
-else case e in #(
- e) tcl_cv_intrinsics=no ;;
-esac
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_uintptr_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_uintptr_t=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- ;;
-esac
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_intrinsics" >&5
-printf "%s\n" "$tcl_cv_intrinsics" >&6; }
-if test "$tcl_cv_intrinsics" = "yes"; then
+echo "$as_me:$LINENO: result: $ac_cv_type_uintptr_t" >&5
+echo "${ECHO_T}$ac_cv_type_uintptr_t" >&6
+if test $ac_cv_type_uintptr_t = yes; then
-printf "%s\n" "#define HAVE_INTRIN_H 1" >>confdefs.h
-fi
-
-# See if the <wspiapi.h> header file is present
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_UINTPTR_T 1
+_ACEOF
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wspiapi.h" >&5
-printf %s "checking for wspiapi.h... " >&6; }
-if test ${tcl_cv_wspiapi_h+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+else
-#include <wspiapi.h>
+ echo "$as_me:$LINENO: checking for pointer-size unsigned integer type" >&5
+echo $ECHO_N "checking for pointer-size unsigned integer type... $ECHO_C" >&6
+if test "${tcl_cv_uintptr_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ for tcl_cv_uintptr_t in "unsigned int" "unsigned long" "unsigned long long" \
+ none; do
+ if test "$tcl_cv_uintptr_t" != none; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
int
-main (void)
+main ()
{
+static int test_array [1 - 2 * !(sizeof (void *) <= sizeof ($tcl_cv_uintptr_t))];
+test_array [0] = 0
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- tcl_cv_wspiapi_h=yes
-else case e in #(
- e) tcl_cv_wspiapi_h=no ;;
-esac
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tcl_ok=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_ok=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ;;
-esac
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$tcl_ok" = yes && break; fi
+ done
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_wspiapi_h" >&5
-printf "%s\n" "$tcl_cv_wspiapi_h" >&6; }
-if test "$tcl_cv_wspiapi_h" = "yes"; then
+echo "$as_me:$LINENO: result: $tcl_cv_uintptr_t" >&5
+echo "${ECHO_T}$tcl_cv_uintptr_t" >&6
+ if test "$tcl_cv_uintptr_t" != none; then
-printf "%s\n" "#define HAVE_WSPIAPI_H 1" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define uintptr_t $tcl_cv_uintptr_t
+_ACEOF
+
+ fi
fi
+#--------------------------------------------------------------------
+# Perform additinal compiler tests.
+#--------------------------------------------------------------------
+
# See if declarations like FINDEX_INFO_LEVELS are
# missing from winbase.h. This is known to be
# a problem with VC++ 5.2.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for FINDEX_INFO_LEVELS in winbase.h" >&5
-printf %s "checking for FINDEX_INFO_LEVELS in winbase.h... " >&6; }
-if test ${tcl_cv_findex_enums+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+echo "$as_me:$LINENO: checking for FINDEX_INFO_LEVELS in winbase.h" >&5
+echo $ECHO_N "checking for FINDEX_INFO_LEVELS in winbase.h... $ECHO_C" >&6
+if test "${tcl_cv_findex_enums+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#define WIN32_LEAN_AND_MEAN
@@ -5444,7 +4567,7 @@ else case e in #(
#undef WIN32_LEAN_AND_MEAN
int
-main (void)
+main ()
{
FINDEX_INFO_LEVELS i;
@@ -5454,22 +4577,45 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
tcl_cv_findex_enums=yes
-else case e in #(
- e) tcl_cv_findex_enums=no ;;
-esac
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_cv_findex_enums=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ;;
-esac
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_findex_enums" >&5
-printf "%s\n" "$tcl_cv_findex_enums" >&6; }
+echo "$as_me:$LINENO: result: $tcl_cv_findex_enums" >&5
+echo "${ECHO_T}$tcl_cv_findex_enums" >&6
if test "$tcl_cv_findex_enums" = "no"; then
-printf "%s\n" "#define HAVE_NO_FINDEX_ENUMS 1" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_NO_FINDEX_ENUMS 1
+_ACEOF
fi
@@ -5480,35 +4626,39 @@ fi
#--------------------------------------------------------------------
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build with symbols" >&5
-printf %s "checking for build with symbols... " >&6; }
- # Check whether --enable-symbols was given.
-if test ${enable_symbols+y}
-then :
- enableval=$enable_symbols; tcl_ok=$enableval
-else case e in #(
- e) tcl_ok=no ;;
-esac
-fi
-
+ echo "$as_me:$LINENO: checking for build with symbols" >&5
+echo $ECHO_N "checking for build with symbols... $ECHO_C" >&6
+ # Check whether --enable-symbols or --disable-symbols was given.
+if test "${enable_symbols+set}" = set; then
+ enableval="$enable_symbols"
+ tcl_ok=$enableval
+else
+ tcl_ok=no
+fi;
# FIXME: Currently, LDFLAGS_DEFAULT is not used, it should work like CFLAGS_DEFAULT.
if test "$tcl_ok" = "no"; then
CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)'
LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)'
+ DBGX=""
-printf "%s\n" "#define NDEBUG 1" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define NDEBUG 1
+_ACEOF
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
- printf "%s\n" "#define TCL_CFG_OPTIMIZED 1" >>confdefs.h
+ cat >>confdefs.h <<\_ACEOF
+#define TCL_CFG_OPTIMIZED 1
+_ACEOF
else
CFLAGS_DEFAULT='$(CFLAGS_DEBUG)'
LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)'
+ DBGX=g
if test "$tcl_ok" = "yes"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (standard debugging)" >&5
-printf "%s\n" "yes (standard debugging)" >&6; }
+ echo "$as_me:$LINENO: result: yes (standard debugging)" >&5
+echo "${ECHO_T}yes (standard debugging)" >&6
fi
fi
@@ -5516,319 +4666,52 @@ printf "%s\n" "yes (standard debugging)" >&6; }
if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then
-printf "%s\n" "#define TCL_MEM_DEBUG 1" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define TCL_MEM_DEBUG 1
+_ACEOF
fi
if test "$tcl_ok" = "compile" -o "$tcl_ok" = "all"; then
-printf "%s\n" "#define TCL_COMPILE_DEBUG 1" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define TCL_COMPILE_DEBUG 1
+_ACEOF
-printf "%s\n" "#define TCL_COMPILE_STATS 1" >>confdefs.h
+cat >>confdefs.h <<\_ACEOF
+#define TCL_COMPILE_STATS 1
+_ACEOF
fi
if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then
if test "$tcl_ok" = "all"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled symbols mem compile debugging" >&5
-printf "%s\n" "enabled symbols mem compile debugging" >&6; }
+ echo "$as_me:$LINENO: result: enabled symbols mem compile debugging" >&5
+echo "${ECHO_T}enabled symbols mem compile debugging" >&6
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5
-printf "%s\n" "enabled $tcl_ok debugging" >&6; }
+ echo "$as_me:$LINENO: result: enabled $tcl_ok debugging" >&5
+echo "${ECHO_T}enabled $tcl_ok debugging" >&6
fi
fi
+TCL_DBGX=${DBGX}
+
#--------------------------------------------------------------------
# Embed the manifest if we can determine how
#--------------------------------------------------------------------
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-printf %s "checking how to run the C preprocessor... " >&6; }
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
- CPP=
-fi
-if test -z "$CPP"; then
- if test ${ac_cv_prog_CPP+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) # Double quotes because $CC needs to be expanded
- for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp
- do
- ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <limits.h>
- Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
-
-else case e in #(
- e) # Broken: fails on valid input.
-continue ;;
-esac
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
- # OK, works on sane cases. Now check whether nonexistent headers
- # can be detected and how.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
- # Broken: success on invalid input.
-continue
-else case e in #(
- e) # Passes both tests.
-ac_preproc_ok=:
-break ;;
-esac
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-done
-# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok
-then :
- break
-fi
- done
- ac_cv_prog_CPP=$CPP
- ;;
-esac
-fi
- CPP=$ac_cv_prog_CPP
+ echo "$as_me:$LINENO: checking whether to embed manifest" >&5
+echo $ECHO_N "checking whether to embed manifest... $ECHO_C" >&6
+ # Check whether --enable-embedded-manifest or --disable-embedded-manifest was given.
+if test "${enable_embedded_manifest+set}" = set; then
+ enableval="$enable_embedded_manifest"
+ embed_ok=$enableval
else
- ac_cv_prog_CPP=$CPP
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-printf "%s\n" "$CPP" >&6; }
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <limits.h>
- Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
-
-else case e in #(
- e) # Broken: fails on valid input.
-continue ;;
-esac
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
- # OK, works on sane cases. Now check whether nonexistent headers
- # can be detected and how.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
- # Broken: success on invalid input.
-continue
-else case e in #(
- e) # Passes both tests.
-ac_preproc_ok=:
-break ;;
-esac
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-done
-# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok
-then :
-
-else case e in #(
- e) { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See 'config.log' for more details" "$LINENO" 5; } ;;
-esac
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep -e" >&5
-printf %s "checking for egrep -e... " >&6; }
-if test ${ac_cv_path_EGREP_TRADITIONAL+y}
-then :
- printf %s "(cached) " >&6
-else case e in #(
- e) if test -z "$EGREP_TRADITIONAL"; then
- ac_path_EGREP_TRADITIONAL_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in grep ggrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue
-# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found.
- # Check for GNU $ac_path_EGREP_TRADITIONAL
-case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #(
-*GNU*)
- ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;;
-#(
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'EGREP_TRADITIONAL' >> "conftest.nl"
- "$ac_path_EGREP_TRADITIONAL" -E 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL"
- ac_path_EGREP_TRADITIONAL_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_EGREP_TRADITIONAL_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then
- :
- fi
-else
- ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL
-fi
-
- if test "$ac_cv_path_EGREP_TRADITIONAL"
-then :
- ac_cv_path_EGREP_TRADITIONAL="$ac_cv_path_EGREP_TRADITIONAL -E"
-else case e in #(
- e) if test -z "$EGREP_TRADITIONAL"; then
- ac_path_EGREP_TRADITIONAL_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in egrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue
-# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found.
- # Check for GNU $ac_path_EGREP_TRADITIONAL
-case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #(
-*GNU*)
- ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;;
-#(
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'EGREP_TRADITIONAL' >> "conftest.nl"
- "$ac_path_EGREP_TRADITIONAL" 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL"
- ac_path_EGREP_TRADITIONAL_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_EGREP_TRADITIONAL_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then
- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL
-fi
- ;;
-esac
-fi ;;
-esac
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP_TRADITIONAL" >&5
-printf "%s\n" "$ac_cv_path_EGREP_TRADITIONAL" >&6; }
- EGREP_TRADITIONAL=$ac_cv_path_EGREP_TRADITIONAL
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to embed manifest" >&5
-printf %s "checking whether to embed manifest... " >&6; }
- # Check whether --enable-embedded-manifest was given.
-if test ${enable_embedded_manifest+y}
-then :
- enableval=$enable_embedded_manifest; embed_ok=$enableval
-else case e in #(
- e) embed_ok=yes ;;
-esac
-fi
-
+ embed_ok=yes
+fi;
VC_MANIFEST_EMBED_DLL=
VC_MANIFEST_EMBED_EXE=
@@ -5836,7 +4719,11 @@ fi
if test "$embed_ok" = "yes" -a "${SHARED_BUILD}" = "1" \
-a "$GCC" != "yes" ; then
# Add the magic to embed the manifest into the dll/exe
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#if defined(_MSC_VER) && _MSC_VER >= 1400
@@ -5845,8 +4732,7 @@ print("manifest needed")
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP_TRADITIONAL "manifest needed" >/dev/null 2>&1
-then :
+ $EGREP "manifest needed" >/dev/null 2>&1; then
# Could do a CHECK_PROG for mt, but should always be with MSVC8+
# Could add 'if test -f' check, but manifest should be created
@@ -5862,11 +4748,11 @@ then :
fi
fi
-rm -rf conftest*
+rm -f conftest*
fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $result" >&5
-printf "%s\n" "$result" >&6; }
+ echo "$as_me:$LINENO: result: $result" >&5
+echo "${ECHO_T}$result" >&6
@@ -5881,10 +4767,20 @@ TCL_SHARED_BUILD=${SHARED_BUILD}
# Perform final evaluations of variables with possible substitutions.
#--------------------------------------------------------------------
+TCL_SHARED_LIB_SUFFIX="\${NODOT_VERSION}${DLLSUFFIX}"
+TCL_UNSHARED_LIB_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}"
+TCL_EXPORT_FILE_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}"
+
eval "TCL_SRC_DIR=\"`cd $srcdir/..; $CYGPATH $(pwd)`\""
eval "TCL_DLL_FILE=tcl${VER}${DLLSUFFIX}"
+eval "TCL_LIB_FILE=${LIBPREFIX}tcl$VER${LIBSUFFIX}"
+
+eval "TCL_LIB_FLAG=\"-ltcl${VER}${LIBFLAGSUFFIX}\""
+eval "TCL_BUILD_LIB_SPEC=\"-L`$CYGPATH $(pwd)` ${TCL_LIB_FLAG}\""
+eval "TCL_LIB_SPEC=\"-L${libdir} ${TCL_LIB_FLAG}\""
+
eval "TCL_STUB_LIB_FILE=\"${LIBPREFIX}tclstub${VER}${LIBSUFFIX}\""
eval "TCL_STUB_LIB_FLAG=\"-ltclstub${VER}${LIBFLAGSUFFIX}\""
eval "TCL_BUILD_STUB_LIB_SPEC=\"-L`$CYGPATH $(pwd)` ${TCL_STUB_LIB_FLAG}\""
@@ -5892,24 +4788,18 @@ eval "TCL_STUB_LIB_SPEC=\"-L${libdir} ${TCL_STUB_LIB_FLAG}\""
eval "TCL_BUILD_STUB_LIB_PATH=\"`$CYGPATH $(pwd)`/${TCL_STUB_LIB_FILE}\""
eval "TCL_STUB_LIB_PATH=\"${libdir}/${TCL_STUB_LIB_FILE}\""
-if test ${SHARED_BUILD} = 0 -o "$GCC" != "yes" ; then
- eval "TCL_LIB_FLAG=\"${LIBPREFIX}tcl${VER}${LIBSUFFIX}\""
- eval "TCL_LIB_FILE=\"${LIBPREFIX}tcl${VER}${LIBSUFFIX}\""
-else
- eval "TCL_LIB_FLAG=\"-ltcl${VER}${FLAGSUFFIX}\""
- eval "TCL_LIB_FILE=\"${LIBPREFIX}tcl${VER}${DLLSUFFIX}.a\""
-fi
-eval "TCL_BUILD_LIB_SPEC=\"-L`$CYGPATH $(pwd)` ${TCL_LIB_FLAG}\""
-eval "TCL_LIB_SPEC=\"-L${libdir} ${TCL_LIB_FLAG}\""
-
# Install time header dir can be set via --includedir
eval "TCL_INCLUDE_SPEC=\"-I${includedir}\""
-TCL_SHARED_LIB_SUFFIX="\${NODOT_VERSION}${DLLSUFFIX}"
-TCL_UNSHARED_LIB_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}"
+
+eval "DLLSUFFIX=${DLLSUFFIX}"
+eval "LIBPREFIX=${LIBPREFIX}"
+eval "LIBSUFFIX=${LIBSUFFIX}"
+eval "EXESUFFIX=${EXESUFFIX}"
CFG_TCL_SHARED_LIB_SUFFIX=${TCL_SHARED_LIB_SUFFIX}
CFG_TCL_UNSHARED_LIB_SUFFIX=${TCL_UNSHARED_LIB_SUFFIX}
+CFG_TCL_EXPORT_FILE_SUFFIX=${TCL_EXPORT_FILE_SUFFIX}
#--------------------------------------------------------------------
# Adjust the defines for how the resources are built depending
@@ -5917,9 +4807,17 @@ CFG_TCL_UNSHARED_LIB_SUFFIX=${TCL_UNSHARED_LIB_SUFFIX}
#--------------------------------------------------------------------
if test ${SHARED_BUILD} = 0 ; then
- RC_DEFINES="${RC_DEFINE} STATIC_BUILD"
+ if test "${DBGX}" = "g"; then
+ RC_DEFINES="${RC_DEFINE} STATIC_BUILD ${RC_DEFINE} DEBUG"
+ else
+ RC_DEFINES="${RC_DEFINE} STATIC_BUILD"
+ fi
else
- RC_DEFINES=""
+ if test "${DBGX}" = "g"; then
+ RC_DEFINES="${RC_DEFINE} DEBUG"
+ else
+ RC_DEFINES=""
+ fi
fi
#--------------------------------------------------------------------
@@ -5930,9 +4828,9 @@ fi
#--------------------------------------------------------------------
if test "$prefix/lib" != "$libdir"; then
- TCL_PACKAGE_PATH="${libdir};${prefix}\\lib"
+ TCL_PACKAGE_PATH="${libdir} ${prefix}/lib"
else
- TCL_PACKAGE_PATH="${prefix}\\lib"
+ TCL_PACKAGE_PATH="${prefix}/lib"
fi
# The tclsh.exe.manifest requires these
@@ -5945,10 +4843,7 @@ case "$TCL_PATCH_LEVEL" in
esac
TCL_WIN_VERSION="$TCL_VERSION.$TCL_RELEASE_LEVEL.`echo $TCL_PATCH_LEVEL | tr -d ab.`"
-# X86|AMD64|ARM64|IA64 for manifest
-
-
-
+# X86|AMD64|IA64 for manifest
@@ -5958,11 +4853,10 @@ TCL_WIN_VERSION="$TCL_VERSION.$TCL_RELEASE_LEVEL.`echo $TCL_PATCH_LEVEL | tr -d
+# empty on win
-# empty on win
-
@@ -6023,8 +4917,8 @@ TCL_WIN_VERSION="$TCL_VERSION.$TCL_RELEASE_LEVEL.`echo $TCL_PATCH_LEVEL | tr -d
-# win only
+# win only
@@ -6039,8 +4933,8 @@ TCL_WIN_VERSION="$TCL_VERSION.$TCL_RELEASE_LEVEL.`echo $TCL_PATCH_LEVEL | tr -d
-ac_config_files="$ac_config_files Makefile tclConfig.sh tclsh.exe.manifest"
+ ac_config_files="$ac_config_files Makefile tclConfig.sh tcl.hpj tclsh.exe.manifest"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -6051,78 +4945,47 @@ cat >confcache <<\_ACEOF
# config.status only pays attention to the cache file if you give it
# the --recheck option to rerun configure.
#
-# 'ac_cv_env_foo' variables (set or unset) will be overridden when
-# loading this file, other *unset* 'ac_cv_foo' will be assigned the
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
# following values.
_ACEOF
# The following way of writing the cache mishandles newlines in values,
# but we know of no workaround that is simple, portable, and efficient.
-# So, we kill variables containing newlines.
+# So, don't put newlines in cache variables' values.
# Ultrix sh set writes to stderr and can't be redirected directly,
# and sets the high bit in the cache file unless we assign to the vars.
-(
- for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
- eval ac_val=\$$ac_var
- case $ac_val in #(
- *${as_nl}*)
- case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
- esac
- case $ac_var in #(
- _ | IFS | as_nl) ;; #(
- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
- *) { eval $ac_var=; unset $ac_var;} ;;
- esac ;;
- esac
- done
-
+{
(set) 2>&1 |
- case $as_nl`(ac_space=' '; set) 2>&1` in #(
- *${as_nl}ac_space=\ *)
- # 'set' does not quote correctly, so add quotes: double-quote
- # substitution turns \\\\ into \\, and sed turns \\ into \.
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
sed -n \
"s/'/'\\\\''/g;
s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
- ;; #(
+ ;;
*)
- # 'set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
;;
- esac |
- sort
-) |
+ esac;
+} |
sed '
- /^ac_cv_env_/b end
t clear
- :clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
t end
- s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
- :end' >>confcache
-if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
- if test -w "$cache_file"; then
- if test "x$cache_file" != "x/dev/null"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-printf "%s\n" "$as_me: updating cache $cache_file" >&6;}
- if test ! -f "$cache_file" || test -h "$cache_file"; then
- cat confcache >"$cache_file"
- else
- case $cache_file in #(
- */* | ?:*)
- mv -f confcache "$cache_file"$$ &&
- mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
- mv -f confcache "$cache_file" ;;
- esac
- fi
- fi
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;}
+ echo "not updating unwritable cache $cache_file"
fi
fi
rm -f confcache
@@ -6131,53 +4994,63 @@ test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
# Transform confdefs.h into DEFS.
# Protect against shell expansion while executing Makefile rules.
# Protect against Makefile macro expansion.
#
# If the first sed substitution is executed (which looks for macros that
-# take arguments), then branch to the quote section. Otherwise,
+# take arguments), then we branch to the quote section. Otherwise,
# look for a macro that doesn't take arguments.
-ac_script='
-:mline
-/\\$/{
- N
- s,\\\n,,
- b mline
-}
+cat >confdef2opt.sed <<\_ACEOF
t clear
-:clear
-s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g
t quote
-s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g
t quote
-b any
-:quote
-s/[][ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
-s/\$/$$/g
-H
-:any
-${
- g
- s/^\n//
- s/\n/ /g
- p
-}
-'
-DEFS=`sed -n "$ac_script" confdefs.h`
+d
+: quote
+s,[ `~#$^&*(){}\\|;'"<>?],\\&,g
+s,\[,\\&,g
+s,\],\\&,g
+s,\$,$$,g
+p
+_ACEOF
+# We use echo to avoid assuming a particular line-breaking character.
+# The extra dot is to prevent the shell from consuming trailing
+# line-breaks from the sub-command output. A line-break within
+# single-quotes doesn't work because, if this script is created in a
+# platform that uses two characters for line-breaks (e.g., DOS), tr
+# would break.
+ac_LF_and_DOT=`echo; echo .`
+DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
+rm -f confdef2opt.sed
ac_libobjs=
ac_ltlibobjs=
-U=
for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
# 1. Remove the extension, and $U if already installed.
- ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
- ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"`
- # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
- # will be set to the directory where LIBOBJS objects are built.
- as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
- as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
done
LIBOBJS=$ac_libobjs
@@ -6185,14 +5058,12 @@ LTLIBOBJS=$ac_ltlibobjs
-: "${CONFIG_STATUS=./config.status}"
-ac_write_fail=0
+: ${CONFIG_STATUS=./config.status}
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;}
-as_write_fail=0
-cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
#! $SHELL
# Generated by $as_me.
# Run this file to recreate the current configuration.
@@ -6202,237 +5073,81 @@ cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
debug=false
ac_cs_recheck=false
ac_cs_silent=false
-
SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else case e in #(
- e) case `(set -o) 2>/dev/null` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac ;;
-esac
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
fi
+DUALCASE=1; export DUALCASE # for MKS sh
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
-as_nl='
-'
-export as_nl
-IFS=" "" $as_nl"
-
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
PS1='$ '
PS2='> '
PS4='+ '
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
-if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
-
-# The user is always right.
-if ${PATH_SEPARATOR+false} :; then
- PATH_SEPARATOR=:
- (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
- (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
- PATH_SEPARATOR=';'
- }
-fi
-
-
-# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-# We did not find ourselves, most probably we were run as 'sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
- as_myself=$0
-fi
-if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
- exit 1
-fi
-
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
fi
- printf "%s\n" "$as_me: error: $2" >&2
- as_fn_exit $as_status
-} # as_fn_error
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
- return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
- set +e
- as_fn_set_status $1
- exit $1
-} # as_fn_exit
-
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
- { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
-then :
- eval 'as_fn_append ()
- {
- eval $1+=\$2
- }'
-else case e in #(
- e) as_fn_append ()
- {
- eval $1=\$$1\$2
- } ;;
-esac
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
-then :
- eval 'as_fn_arith ()
- {
- as_val=$(( $* ))
- }'
-else case e in #(
- e) as_fn_arith ()
- {
- as_val=`expr "$@" || test $? -eq 1`
- } ;;
-esac
-fi # as_fn_arith
-
+done
-if expr a : '\(a\)' >/dev/null 2>&1 &&
- test "X`expr 00001 : '.*\(...\)'`" = X001; then
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
as_expr=expr
else
as_expr=false
fi
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
as_basename=basename
else
as_basename=false
fi
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
- as_dirname=dirname
-else
- as_dirname=false
-fi
-as_me=`$as_basename -- "$0" ||
+# Name of the executable.
+as_me=`$as_basename "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{
- s//\1/
- q
- }
- /^X\/\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\/\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+# PATH needs CR, and LINENO needs CR and PATH.
# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
@@ -6440,145 +5155,181 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
- case `echo 'xy\c'` in
- *c*) ECHO_T=' ';; # ECHO_T is single tab character.
- xy) ECHO_C='\c';;
- *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
- ECHO_T=' ';;
- esac;;
-*)
- ECHO_N='-n';;
-esac
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
- rm -f conf$$.dir/conf$$.file
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
else
- rm -f conf$$.dir
- mkdir conf$$.dir 2>/dev/null
+ as_expr=false
fi
-if (echo >conf$$.file) 2>/dev/null; then
- if ln -s conf$$.file conf$$ 2>/dev/null; then
- as_ln_s='ln -s'
- # ... but there are two gotchas:
- # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail.
- # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable.
- # In both cases, we have to default to 'cp -pR'.
- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
- elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
else
- as_ln_s='cp -pR'
+ as_ln_s='ln -s'
fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
else
- as_ln_s='cp -pR'
+ as_ln_s='cp -p'
fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
- case $as_dir in #(
- -*) as_dir=./$as_dir;;
- esac
- test -d "$as_dir" || eval $as_mkdir_p || {
- as_dirs=
- while :; do
- case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
- *) as_qdir=$as_dir;;
- esac
- as_dirs="'$as_qdir' $as_dirs"
- as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_dir" : 'X\(//\)[^/]' \| \
- X"$as_dir" : 'X\(//\)$' \| \
- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- test -d "$as_dir" && break
- done
- test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
+rm -f conf$$ conf$$.exe conf$$.file
-} # as_fn_mkdir_p
if mkdir -p . 2>/dev/null; then
- as_mkdir_p='mkdir -p "$as_dir"'
+ as_mkdir_p=:
else
test -d ./-p && rmdir ./-p
as_mkdir_p=false
fi
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
+as_executable_p="test -f"
# Sed expression to map a string onto a valid CPP name.
-as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
-as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
# Sed expression to map a string onto a valid variable name.
-as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
-as_tr_sh="eval sed '$as_sed_sh'" # deprecated
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+# CDPATH.
+$as_unset CDPATH
exec 6>&1
-## ----------------------------------- ##
-## Main body of $CONFIG_STATUS script. ##
-## ----------------------------------- ##
-_ASEOF
-test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# Save the log message, to keep $0 and so on meaningful, and to
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling.
-ac_log="
-This file was extended by tcl $as_me 8.7, which was
-generated by GNU Autoconf 2.72. Invocation command line was
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -6586,118 +5337,124 @@ generated by GNU Autoconf 2.72. Invocation command line was
CONFIG_COMMANDS = $CONFIG_COMMANDS
$ $0 $@
-on `(hostname || uname -n) 2>/dev/null | sed 1q`
-"
-
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
_ACEOF
-case $ac_config_files in *"
-"*) set x $ac_config_files; shift; ac_config_files=$*;;
-esac
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-# Files that config.status was made for.
-config_files="$ac_config_files"
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
-_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
ac_cs_usage="\
-'$as_me' instantiates files and other configuration actions
-from templates according to the current configuration. Unless the files
-and actions are specified as TAGs, all are instantiated by default.
+\`$as_me' instantiates files from templates according to the
+current configuration.
-Usage: $0 [OPTION]... [TAG]...
+Usage: $0 [OPTIONS] [FILE]...
-h, --help print this help, then exit
- -V, --version print version number and configuration settings, then exit
- --config print configuration, then exit
- -q, --quiet, --silent
- do not print progress messages
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
- --file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
Configuration files:
$config_files
-Report bugs to the package provider."
-
+Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
-ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
-ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"`
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config='$ac_cs_config_escaped'
+
+cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-tcl config.status 8.7
-configured by $0, generated by GNU Autoconf 2.72,
- with options \\"\$ac_cs_config\\"
+config.status
+configured by $0, generated by GNU Autoconf 2.59,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
-Copyright (C) 2023 Free Software Foundation, Inc.
+Copyright (C) 2003 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
-
-ac_pwd='$ac_pwd'
-srcdir='$srcdir'
-test -n "\$AWK" || AWK=awk
+srcdir=$srcdir
_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# The default lists apply if the user does not specify any file.
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
ac_need_defaults=:
while test $# != 0
do
case $1 in
- --*=?*)
- ac_option=`expr "X$1" : 'X\([^=]*\)='`
- ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
- ac_shift=:
- ;;
- --*=)
- ac_option=`expr "X$1" : 'X\([^=]*\)='`
- ac_optarg=
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
ac_shift=:
;;
- *)
+ -*)
ac_option=$1
ac_optarg=$2
ac_shift=shift
;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
esac
case $ac_option in
# Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
ac_cs_recheck=: ;;
- --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
- printf "%s\n" "$ac_cs_version"; exit ;;
- --config | --confi | --conf | --con | --co | --c )
- printf "%s\n" "$ac_cs_config"; exit ;;
- --debug | --debu | --deb | --de | --d | -d )
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
debug=: ;;
--file | --fil | --fi | --f )
$ac_shift
- case $ac_optarg in
- *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
- '') as_fn_error $? "missing file argument" ;;
- esac
- as_fn_append CONFIG_FILES " '$ac_optarg'"
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
ac_need_defaults=false;;
- --he | --h | --help | --hel | -h )
- printf "%s\n" "$ac_cs_usage"; exit ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil | --si | --s)
ac_cs_silent=: ;;
# This is an error.
- -*) as_fn_error $? "unrecognized option: '$1'
-Try '$0 --help' for more information." ;;
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
- *) as_fn_append ac_config_targets " $1"
- ac_need_defaults=false ;;
+ *) ac_config_targets="$ac_config_targets $1" ;;
esac
shift
@@ -6711,463 +5468,447 @@ if $ac_cs_silent; then
fi
_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>$CONFIG_STATUS <<_ACEOF
if \$ac_cs_recheck; then
- set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
- shift
- \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6
- CONFIG_SHELL='$SHELL'
- export CONFIG_SHELL
- exec "\$@"
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
fi
_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-exec 5>>config.log
-{
- echo
- sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
- printf "%s\n" "$ac_log"
-} >&5
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# Handling of arguments.
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
for ac_config_target in $ac_config_targets
do
- case $ac_config_target in
- "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
- "tclConfig.sh") CONFIG_FILES="$CONFIG_FILES tclConfig.sh" ;;
- "tclsh.exe.manifest") CONFIG_FILES="$CONFIG_FILES tclsh.exe.manifest" ;;
-
- *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;;
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "tclConfig.sh" ) CONFIG_FILES="$CONFIG_FILES tclConfig.sh" ;;
+ "tcl.hpj" ) CONFIG_FILES="$CONFIG_FILES tcl.hpj" ;;
+ "tclsh.exe.manifest" ) CONFIG_FILES="$CONFIG_FILES tclsh.exe.manifest" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
esac
done
-
# If the user did not use the arguments to specify the items to instantiate,
# then the envvar interface is used. Set only those that are not.
# We use the long form for the default assignment because of an extremely
# bizarre bug on SunOS 4.1.3.
if $ac_need_defaults; then
- test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
fi
# Have a temporary directory for convenience. Make it in the build tree
-# simply because there is no reason against having it here, and in addition,
+# simply because there is no reason to put it here, and in addition,
# creating and moving files from /tmp can sometimes cause problems.
-# Hook for its removal unless debugging.
-# Note that there is a small window in which the directory will not be cleaned:
-# after its creation but before its name has been assigned to '$tmp'.
+# Create a temporary directory, and hook for its removal unless debugging.
$debug ||
{
- tmp= ac_tmp=
- trap 'exit_status=$?
- : "${ac_tmp:=$tmp}"
- { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
-' 0
- trap 'as_fn_exit 1' 1 2 13 15
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
}
+
# Create a (secure) tmp directory for tmp files.
{
- tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
- test -d "$tmp"
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
} ||
{
- tmp=./conf$$-$RANDOM
- (umask 077 && mkdir "$tmp")
-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
-
-# Set up the scripts for CONFIG_FILES section.
-# No need to generate them if there are no CONFIG_FILES.
-# This happens for instance with './config.status config.h'.
-if test -n "$CONFIG_FILES"; then
-
-
-ac_cr=`echo X | tr X '\015'`
-# On cygwin, bash can eat \r inside `` if the user requested igncr.
-# But we know of no other shell where ac_cr would be empty at this
-# point, so we can use a bashism as a fallback.
-if test "x$ac_cr" = x; then
- eval ac_cr=\$\'\\r\'
-fi
-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
- ac_cs_awk_cr='\\r'
-else
- ac_cs_awk_cr=$ac_cr
-fi
-
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
-_ACEOF
-
-
-{
- echo "cat >conf$$subs.awk <<_ACEOF" &&
- echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
- echo "_ACEOF"
-} >conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
-ac_delim='%!_!# '
-for ac_last_try in false false false false false :; do
- . ./conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-
- ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
- if test $ac_delim_n = $ac_delim_num; then
- break
- elif $ac_last_try; then
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
- else
- ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
- fi
-done
-rm -f conf$$subs.sh
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
-_ACEOF
-sed -n '
-h
-s/^/S["/; s/!.*/"]=/
-p
-g
-s/^[^!]*!//
-:repl
-t repl
-s/'"$ac_delim"'$//
-t delim
-:nl
-h
-s/\(.\{148\}\)..*/\1/
-t more1
-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
-p
-n
-b repl
-:more1
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t nl
-:delim
-h
-s/\(.\{148\}\)..*/\1/
-t more2
-s/["\\]/\\&/g; s/^/"/; s/$/"/
-p
-b
-:more2
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t delim
-' <conf$$subs.awk | sed '
-/^[^""]/{
- N
- s/\n//
-}
-' >>$CONFIG_STATUS || ac_write_fail=1
-rm -f conf$$subs.awk
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
- for (key in S) S_is_set[key] = 1
- FS = ""
-
-}
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
{
- line = $ 0
- nfields = split(line, field, "@")
- substed = 0
- len = length(field[1])
- for (i = 2; i < nfields; i++) {
- key = field[i]
- keylen = length(key)
- if (S_is_set[key]) {
- value = S[key]
- line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
- len += length(value) + length(field[++i])
- substed = 1
- } else
- len += 1 + keylen
- }
-
- print line
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
}
-_ACAWK
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
- sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
-else
- cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
- || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
_ACEOF
-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
-# trailing colons and then remove the whole line if VPATH becomes empty
-# (actually we leave an empty line to preserve line numbers).
-if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
-h
-s///
-s/^/:/
-s/[ ]*$/:/
-s/:\$(srcdir):/:/g
-s/:\${srcdir}:/:/g
-s/:@srcdir@:/:/g
-s/^:*//
-s/:*$//
-x
-s/\(=[ ]*\).*/\1/
-G
-s/\n//
-s/^[^=]*=[ ]*$//
-}'
-fi
+cat >>$CONFIG_STATUS <<_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-fi # test -n "$CONFIG_FILES"
+#
+# CONFIG_FILES section.
+#
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@AR@,$AR,;t t
+s,@ac_ct_AR@,$ac_ct_AR,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@RC@,$RC,;t t
+s,@ac_ct_RC@,$ac_ct_RC,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@TCL_THREADS@,$TCL_THREADS,;t t
+s,@CYGPATH@,$CYGPATH,;t t
+s,@CELIB_DIR@,$CELIB_DIR,;t t
+s,@DL_LIBS@,$DL_LIBS,;t t
+s,@CFLAGS_DEBUG@,$CFLAGS_DEBUG,;t t
+s,@CFLAGS_OPTIMIZE@,$CFLAGS_OPTIMIZE,;t t
+s,@CFLAGS_WARNING@,$CFLAGS_WARNING,;t t
+s,@CFLAGS_DEFAULT@,$CFLAGS_DEFAULT,;t t
+s,@LDFLAGS_DEFAULT@,$LDFLAGS_DEFAULT,;t t
+s,@VC_MANIFEST_EMBED_DLL@,$VC_MANIFEST_EMBED_DLL,;t t
+s,@VC_MANIFEST_EMBED_EXE@,$VC_MANIFEST_EMBED_EXE,;t t
+s,@TCL_WIN_VERSION@,$TCL_WIN_VERSION,;t t
+s,@MACHINE@,$MACHINE,;t t
+s,@TCL_VERSION@,$TCL_VERSION,;t t
+s,@TCL_MAJOR_VERSION@,$TCL_MAJOR_VERSION,;t t
+s,@TCL_MINOR_VERSION@,$TCL_MINOR_VERSION,;t t
+s,@TCL_PATCH_LEVEL@,$TCL_PATCH_LEVEL,;t t
+s,@TCL_LIB_FILE@,$TCL_LIB_FILE,;t t
+s,@TCL_LIB_FLAG@,$TCL_LIB_FLAG,;t t
+s,@TCL_LIB_SPEC@,$TCL_LIB_SPEC,;t t
+s,@TCL_STUB_LIB_FILE@,$TCL_STUB_LIB_FILE,;t t
+s,@TCL_STUB_LIB_FLAG@,$TCL_STUB_LIB_FLAG,;t t
+s,@TCL_STUB_LIB_SPEC@,$TCL_STUB_LIB_SPEC,;t t
+s,@TCL_STUB_LIB_PATH@,$TCL_STUB_LIB_PATH,;t t
+s,@TCL_INCLUDE_SPEC@,$TCL_INCLUDE_SPEC,;t t
+s,@TCL_BUILD_STUB_LIB_SPEC@,$TCL_BUILD_STUB_LIB_SPEC,;t t
+s,@TCL_BUILD_STUB_LIB_PATH@,$TCL_BUILD_STUB_LIB_PATH,;t t
+s,@TCL_DLL_FILE@,$TCL_DLL_FILE,;t t
+s,@TCL_SRC_DIR@,$TCL_SRC_DIR,;t t
+s,@TCL_BIN_DIR@,$TCL_BIN_DIR,;t t
+s,@TCL_DBGX@,$TCL_DBGX,;t t
+s,@CFG_TCL_SHARED_LIB_SUFFIX@,$CFG_TCL_SHARED_LIB_SUFFIX,;t t
+s,@CFG_TCL_UNSHARED_LIB_SUFFIX@,$CFG_TCL_UNSHARED_LIB_SUFFIX,;t t
+s,@CFG_TCL_EXPORT_FILE_SUFFIX@,$CFG_TCL_EXPORT_FILE_SUFFIX,;t t
+s,@EXTRA_CFLAGS@,$EXTRA_CFLAGS,;t t
+s,@DEPARG@,$DEPARG,;t t
+s,@CC_OBJNAME@,$CC_OBJNAME,;t t
+s,@CC_EXENAME@,$CC_EXENAME,;t t
+s,@LDFLAGS_DEBUG@,$LDFLAGS_DEBUG,;t t
+s,@LDFLAGS_OPTIMIZE@,$LDFLAGS_OPTIMIZE,;t t
+s,@LDFLAGS_CONSOLE@,$LDFLAGS_CONSOLE,;t t
+s,@LDFLAGS_WINDOW@,$LDFLAGS_WINDOW,;t t
+s,@STLIB_LD@,$STLIB_LD,;t t
+s,@SHLIB_LD@,$SHLIB_LD,;t t
+s,@SHLIB_LD_LIBS@,$SHLIB_LD_LIBS,;t t
+s,@SHLIB_CFLAGS@,$SHLIB_CFLAGS,;t t
+s,@SHLIB_SUFFIX@,$SHLIB_SUFFIX,;t t
+s,@TCL_SHARED_BUILD@,$TCL_SHARED_BUILD,;t t
+s,@LIBS_GUI@,$LIBS_GUI,;t t
+s,@DLLSUFFIX@,$DLLSUFFIX,;t t
+s,@LIBPREFIX@,$LIBPREFIX,;t t
+s,@LIBSUFFIX@,$LIBSUFFIX,;t t
+s,@EXESUFFIX@,$EXESUFFIX,;t t
+s,@LIBRARIES@,$LIBRARIES,;t t
+s,@MAKE_LIB@,$MAKE_LIB,;t t
+s,@MAKE_STUB_LIB@,$MAKE_STUB_LIB,;t t
+s,@POST_MAKE_LIB@,$POST_MAKE_LIB,;t t
+s,@MAKE_DLL@,$MAKE_DLL,;t t
+s,@MAKE_EXE@,$MAKE_EXE,;t t
+s,@TCL_BUILD_LIB_SPEC@,$TCL_BUILD_LIB_SPEC,;t t
+s,@TCL_LD_SEARCH_FLAGS@,$TCL_LD_SEARCH_FLAGS,;t t
+s,@TCL_NEEDS_EXP_FILE@,$TCL_NEEDS_EXP_FILE,;t t
+s,@TCL_BUILD_EXP_FILE@,$TCL_BUILD_EXP_FILE,;t t
+s,@TCL_EXP_FILE@,$TCL_EXP_FILE,;t t
+s,@TCL_LIB_VERSIONS_OK@,$TCL_LIB_VERSIONS_OK,;t t
+s,@TCL_PACKAGE_PATH@,$TCL_PACKAGE_PATH,;t t
+s,@TCL_DDE_VERSION@,$TCL_DDE_VERSION,;t t
+s,@TCL_DDE_MAJOR_VERSION@,$TCL_DDE_MAJOR_VERSION,;t t
+s,@TCL_DDE_MINOR_VERSION@,$TCL_DDE_MINOR_VERSION,;t t
+s,@TCL_REG_VERSION@,$TCL_REG_VERSION,;t t
+s,@TCL_REG_MAJOR_VERSION@,$TCL_REG_MAJOR_VERSION,;t t
+s,@TCL_REG_MINOR_VERSION@,$TCL_REG_MINOR_VERSION,;t t
+s,@RC_OUT@,$RC_OUT,;t t
+s,@RC_TYPE@,$RC_TYPE,;t t
+s,@RC_INCLUDE@,$RC_INCLUDE,;t t
+s,@RC_DEFINE@,$RC_DEFINE,;t t
+s,@RC_DEFINES@,$RC_DEFINES,;t t
+s,@RES@,$RES,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
-eval set X " :F $CONFIG_FILES "
-shift
-for ac_tag
-do
- case $ac_tag in
- :[FHLC]) ac_mode=$ac_tag; continue;;
- esac
- case $ac_mode$ac_tag in
- :[FHL]*:*);;
- :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;;
- :[FH]-) ac_tag=-:-;;
- :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
- esac
- ac_save_IFS=$IFS
- IFS=:
- set x $ac_tag
- IFS=$ac_save_IFS
- shift
- ac_file=$1
- shift
-
- case $ac_mode in
- :L) ac_source=$1;;
- :[FH])
- ac_file_inputs=
- for ac_f
- do
- case $ac_f in
- -) ac_f="$ac_tmp/stdin";;
- *) # Look for the file first in the build tree, then in the source tree
- # (if the path is not absolute). The absolute path cannot be DOS-style,
- # because $ac_f cannot contain ':'.
- test -f "$ac_f" ||
- case $ac_f in
- [\\/$]*) false;;
- *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
- esac ||
- as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;;
- esac
- case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
- as_fn_append ac_file_inputs " '$ac_f'"
- done
+_ACEOF
- # Let's still pretend it is 'configure' which instantiates (i.e., don't
- # use $as_me), people would be surprised to read:
- # /* config.h. Generated by config.status. */
- configure_input='Generated from '`
- printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
- `' by configure.'
- if test x"$ac_file" != x-; then
- configure_input="$ac_file. $configure_input"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-printf "%s\n" "$as_me: creating $ac_file" >&6;}
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
fi
- # Neutralize special characters interpreted by sed in replacement strings.
- case $configure_input in #(
- *\&* | *\|* | *\\* )
- ac_sed_conf_input=`printf "%s\n" "$configure_input" |
- sed 's/[\\\\&|]/\\\\&/g'`;; #(
- *) ac_sed_conf_input=$configure_input;;
- esac
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
- case $ac_tag in
- *:-:* | *:-) cat >"$ac_tmp/stdin" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
- esac
- ;;
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
esac
- ac_dir=`$as_dirname -- "$ac_file" ||
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$ac_file" : 'X\(//\)[^/]' \| \
X"$ac_file" : 'X\(//\)$' \| \
- X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$ac_file" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- as_dir="$ac_dir"; as_fn_mkdir_p
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
ac_builddir=.
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
- # A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
- case $ac_top_builddir_sub in
- "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
- esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
case $srcdir in
- .) # We are building in place.
+ .) # No --srcdir option. We are building in place.
ac_srcdir=.
- ac_top_srcdir=$ac_top_builddir_sub
- ac_abs_top_srcdir=$ac_pwd ;;
- [\\/]* | ?:[\\/]* ) # Absolute name.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir
- ac_abs_top_srcdir=$srcdir ;;
- *) # Relative name.
- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_build_prefix$srcdir
- ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
- case $ac_mode in
- :F)
- #
- # CONFIG_FILE
- #
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# If the template does not know about datarootdir, expand it.
-# FIXME: This hack should be removed a few years after 2.60.
-ac_datarootdir_hack=; ac_datarootdir_seen=
-ac_sed_dataroot='
-/datarootdir/ {
- p
- q
-}
-/@datadir@/p
-/@docdir@/p
-/@infodir@/p
-/@localedir@/p
-/@mandir@/p'
-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
-*datarootdir*) ac_datarootdir_seen=yes;;
-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
- ac_datarootdir_hack='
- s&@datadir@&$datadir&g
- s&@docdir@&$docdir&g
- s&@infodir@&$infodir&g
- s&@localedir@&$localedir&g
- s&@mandir@&$mandir&g
- s&\\\${datarootdir}&$datarootdir&g' ;;
-esac
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
_ACEOF
-
-# Neutralize VPATH when '$srcdir' = '.'.
-# Shell code in configure.ac might set extrasub.
-# FIXME: do we really want to maintain this feature?
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_sed_extra="$ac_vpsub
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
$extrasub
_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+cat >>$CONFIG_STATUS <<\_ACEOF
:t
/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s|@configure_input@|$ac_sed_conf_input|;t t
-s&@top_builddir@&$ac_top_builddir_sub&;t t
-s&@top_build_prefix@&$ac_top_build_prefix&;t t
-s&@srcdir@&$ac_srcdir&;t t
-s&@abs_srcdir@&$ac_abs_srcdir&;t t
-s&@top_srcdir@&$ac_top_srcdir&;t t
-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
-s&@builddir@&$ac_builddir&;t t
-s&@abs_builddir@&$ac_abs_builddir&;t t
-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
-$ac_datarootdir_hack
-"
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
- >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-
-test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
- { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
- "$ac_tmp/out"`; test -z "$ac_out"; } &&
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir'
-which seems to be undefined. Please make sure it is defined" >&5
-printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir'
-which seems to be undefined. Please make sure it is defined" >&2;}
-
- rm -f "$ac_tmp/stdin"
- case $ac_file in
- -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
- *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
- esac \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- ;;
-
-
-
- esac
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
-done # for ac_tag
+done
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
-as_fn_exit 0
+{ (exit 0); exit 0; }
_ACEOF
+chmod +x $CONFIG_STATUS
ac_clean_files=$ac_clean_files_save
-test $ac_write_fail = 0 ||
- as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
-
# configure is writing to config.log, and then calls config.status.
# config.status does its own redirection, appending to config.log.
@@ -7187,12 +5928,7 @@ if test "$no_create" != yes; then
exec 5>>config.log
# Use ||, not &&, to avoid exiting from the if with $? = 1, which
# would make configure fail if this is the last instruction.
- $ac_cs_success || as_fn_exit 1
-fi
-if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+ $ac_cs_success || { (exit 1); exit 1; }
fi
-
diff --git a/win/configure.ac b/win/configure.in
index 25fa29f..6b30162 100644
--- a/win/configure.ac
+++ b/win/configure.in
@@ -3,38 +3,30 @@
# generate the file "configure", which is run during Tcl installation
# to configure the system for the local environment.
-AC_INIT([tcl],[8.7])
-AC_CONFIG_SRCDIR([../generic/tcl.h])
-AC_PREREQ([2.69])
+AC_INIT(../generic/tcl.h)
+AC_PREREQ(2.59)
# The following define is needed when building with Cygwin since newer
# versions of autoconf incorrectly set SHELL to /bin/bash instead of
# /bin/sh. The bash shell seems to suffer from some strange failures.
SHELL=/bin/sh
-TCL_VERSION=8.7
+TCL_VERSION=8.5
TCL_MAJOR_VERSION=8
-TCL_MINOR_VERSION=7
-TCL_PATCH_LEVEL="b1"
+TCL_MINOR_VERSION=5
+TCL_PATCH_LEVEL=".18"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION
-TCL_DDE_VERSION=1.4
+TCL_DDE_VERSION=1.3
TCL_DDE_MAJOR_VERSION=1
-TCL_DDE_MINOR_VERSION=4
+TCL_DDE_MINOR_VERSION=3
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION
-TCL_REG_VERSION=1.3
+TCL_REG_VERSION=1.2
TCL_REG_MAJOR_VERSION=1
-TCL_REG_MINOR_VERSION=3
+TCL_REG_MINOR_VERSION=2
REGVER=$TCL_REG_MAJOR_VERSION$TCL_REG_MINOR_VERSION
-PKG_CFG_ARGS=$@
-
-#------------------------------------------------------------------------
-# Empty slate for bundled packages, to avoid stale configuration
-#------------------------------------------------------------------------
-rm -Rf pkgs
-
#------------------------------------------------------------------------
# Handle the --prefix=... option
#------------------------------------------------------------------------
@@ -60,6 +52,7 @@ fi
AC_PROG_CC
AC_C_INLINE
+AC_HEADER_STDC
AC_CHECK_TOOL(AR, ar)
AC_CHECK_TOOL(RANLIB, ranlib)
@@ -78,6 +71,12 @@ AC_PROG_MAKE_SET
AC_OBJEXT
AC_EXEEXT
+#--------------------------------------------------------------------
+# Check whether --enable-threads or --disable-threads was given.
+#--------------------------------------------------------------------
+
+SC_ENABLE_THREADS
+
#------------------------------------------------------------------------
# Embedded configuration information, encoding to use for the values, TIP #59
#------------------------------------------------------------------------
@@ -92,20 +91,6 @@ SC_TCL_CFG_ENCODING
SC_ENABLE_SHARED
#--------------------------------------------------------------------
-# Check whether --enable-time64bit was given.
-#--------------------------------------------------------------------
-
-AC_MSG_CHECKING([force of 64-bit time_t])
-AC_ARG_ENABLE(time64bit,
- AS_HELP_STRING([--enable-time64bit],
- [force 64-bit time_t for 32-bit build (default: off)]),
- [tcl_ok=$enableval], [tcl_ok=no])
-AC_MSG_RESULT("$tcl_ok")
-if test "$tcl_ok" = "yes"; then
- CFLAGS="${CFLAGS} -D_USE_64BIT_TIME_T"
-fi
-
-#--------------------------------------------------------------------
# The statements below define a collection of compile flags. This
# macro depends on the value of SHARED_BUILD, and should be called
# after SC_ENABLE_SHARED checks the configure switches.
@@ -113,116 +98,37 @@ fi
SC_CONFIG_CFLAGS
-# Cross-compiling
-case ${host_alias} in
-*mingw32*)
- TCL_EXE="tclsh"
- ;;
-*)
- TCL_EXE="TCL_LIBRARY=\"\${LIBRARY_DIR}\"; export TCL_LIBRARY; ./\${TCLSH}"
- ;;
-esac
-
-#------------------------------------------------------------------------
-# Add stuff for zlib/libtommath; note that this is mostly done in the
-# makefile now as we just assume that the platform hasn't got usable
-# z.lib/tommath.lib
-#------------------------------------------------------------------------
-
-AS_IF([test "${enable_shared+set}" = "set"], [
- enableval="$enable_shared"
- tcl_ok=$enableval
-], [
- tcl_ok=yes
-])
-zlib_lib_name=zdll.lib
-tommath_lib_name=tommath.lib
-AS_IF([test "$tcl_ok" = "yes"], [
- AC_SUBST(ZLIB_DLL_FILE,[\${ZLIB_DLL_FILE}])
- AC_SUBST(TOMMATH_DLL_FILE,[\${TOMMATH_DLL_FILE}])
- AC_DEFINE(TCL_WITH_EXTERNAL_TOMMATH, 1, [Tcl with external libtommath])
- AS_IF([test "$do64bit" != "no"], [
- AC_DEFINE(MP_64BIT, 1, [Using libtommath.dll in 64-bit mode])
- AS_IF([test "$do64bit" = "arm64"], [
- AS_IF([test "$GCC" == "yes"],[
- AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR_NATIVE}/win64-arm/libz.dll.a])
- AC_SUBST(TOMMATH_LIBS,[\${TOMMATH_DIR_NATIVE}/win64-arm/libtommath.dll.a])
- zlib_lib_name=libz.dll.a
- tommath_lib_name=libtommath.dll.a
- ], [
- AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR_NATIVE}/win64-arm/zdll.lib])
- AC_SUBST(TOMMATH_LIBS,[\${TOMMATH_DIR_NATIVE}/win64-arm/tommath.lib])
- ])
- ], [
- AS_IF([test "$GCC" == "yes"],[
- AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR_NATIVE}/win64/libz.dll.a])
- AC_SUBST(TOMMATH_LIBS,[\${TOMMATH_DIR_NATIVE}/win64/libtommath.dll.a])
- zlib_lib_name=libz.dll.a
- tommath_lib_name=libtommath.dll.a
- ], [
- AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR_NATIVE}/win64/zdll.lib])
- AC_SUBST(TOMMATH_LIBS,[\${TOMMATH_DIR_NATIVE}/win64/tommath.lib])
- ])
- ])
- ], [
- AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR_NATIVE}/win32/zdll.lib])
- AC_SUBST(TOMMATH_LIBS,[\${TOMMATH_DIR_NATIVE}/win32/tommath.lib])
- ])
-], [
- AC_SUBST(ZLIB_OBJS,[\${ZLIB_OBJS}])
- AC_SUBST(TOMMATH_OBJS,[\${TOMMATH_OBJS}])
+AC_CHECK_TYPE([intptr_t], [
+ AC_DEFINE([HAVE_INTPTR_T], 1, [Do we have the intptr_t type?])], [
+ AC_CACHE_CHECK([for pointer-size signed integer type], tcl_cv_intptr_t, [
+ for tcl_cv_intptr_t in "int" "long" "long long" none; do
+ if test "$tcl_cv_intptr_t" != none; then
+ AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT],
+ [[sizeof (void *) <= sizeof ($tcl_cv_intptr_t)]])],
+ [tcl_ok=yes], [tcl_ok=no])
+ test "$tcl_ok" = yes && break; fi
+ done])
+ if test "$tcl_cv_intptr_t" != none; then
+ AC_DEFINE_UNQUOTED([intptr_t], [$tcl_cv_intptr_t], [Signed integer
+ type wide enough to hold a pointer.])
+ fi
])
-AC_DEFINE(HAVE_ZLIB, 1, [Is there an installed zlib?])
-AC_SUBST(TCL_ZLIB_LIB_NAME, $zlib_lib_name)
-AC_SUBST(TCL_TOMMATH_LIB_NAME, $tommath_lib_name)
-AC_CHECK_TYPES([intptr_t, uintptr_t],,,[[
-#include <stdint.h>
-]])
-
-#--------------------------------------------------------------------
-# Zipfs support - Tip 430
-#--------------------------------------------------------------------
-AC_ARG_ENABLE(zipfs,
- AS_HELP_STRING([--enable-zipfs],
- [build with Zipfs support (default: on)]),
- [tcl_ok=$enableval], [tcl_ok=yes])
-if test "$tcl_ok" = "yes" ; then
- #
- # Find a native compiler
- #
- AX_CC_FOR_BUILD
- #
- # Find a native zip implementation
- #
- SC_PROG_TCLSH
- SC_ZIPFS_SUPPORT
- ZIPFS_BUILD=1
- TCL_ZIP_FILE=libtcl${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_PATCH_LEVEL}.zip
-else
- ZIPFS_BUILD=0
- TCL_ZIP_FILE=
-fi
-# Do checking message here to not mess up interleaved configure output
-AC_MSG_CHECKING([for building with zipfs])
-if test "${ZIPFS_BUILD}" = 1; then
- if test "${SHARED_BUILD}" = 0; then
- ZIPFS_BUILD=2;
- AC_DEFINE(ZIPFS_BUILD, 2, [Are we building with zipfs enabled?])
- else
- AC_DEFINE(ZIPFS_BUILD, 1, [Are we building with zipfs enabled?])\
+AC_CHECK_TYPE([uintptr_t], [
+ AC_DEFINE([HAVE_UINTPTR_T], 1, [Do we have the uintptr_t type?])], [
+ AC_CACHE_CHECK([for pointer-size unsigned integer type], tcl_cv_uintptr_t, [
+ for tcl_cv_uintptr_t in "unsigned int" "unsigned long" "unsigned long long" \
+ none; do
+ if test "$tcl_cv_uintptr_t" != none; then
+ AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT],
+ [[sizeof (void *) <= sizeof ($tcl_cv_uintptr_t)]])],
+ [tcl_ok=yes], [tcl_ok=no])
+ test "$tcl_ok" = yes && break; fi
+ done])
+ if test "$tcl_cv_uintptr_t" != none; then
+ AC_DEFINE_UNQUOTED([uintptr_t], [$tcl_cv_uintptr_t], [Unsigned integer
+ type wide enough to hold a pointer.])
fi
- AC_MSG_RESULT([yes])
-else
-AC_MSG_RESULT([no])
-INSTALL_LIBRARIES=install-libraries
-INSTALL_MSGS=install-msgs
-fi
-AC_SUBST(ZIPFS_BUILD)
-AC_SUBST(TCL_ZIP_FILE)
-AC_SUBST(INSTALL_LIBRARIES)
-AC_SUBST(INSTALL_MSGS)
-
-
+])
#--------------------------------------------------------------------
# Perform additinal compiler tests.
#--------------------------------------------------------------------
@@ -233,73 +139,17 @@ AC_SUBST(INSTALL_MSGS)
AC_CACHE_CHECK(for FINDEX_INFO_LEVELS in winbase.h,
tcl_cv_findex_enums,
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-]], [[
- FINDEX_INFO_LEVELS i;
- FINDEX_SEARCH_OPS j;
-]])],
- [tcl_cv_findex_enums=yes],
- [tcl_cv_findex_enums=no])
-)
-if test "$tcl_cv_findex_enums" = "no"; then
- AC_DEFINE(HAVE_NO_FINDEX_ENUMS, 1,
- [Defined when enums are missing from winbase.h])
-fi
-
-# See if the compiler supports intrinsics.
-
-AC_CACHE_CHECK(for intrinsics support in compiler,
- tcl_cv_intrinsics,
-AC_LINK_IFELSE([AC_LANG_PROGRAM([[
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#include <intrin.h>
-]], [[
- __cpuidex(0,0,0);
-]])],
- [tcl_cv_intrinsics=yes],
- [tcl_cv_intrinsics=no])
-)
-if test "$tcl_cv_intrinsics" = "yes"; then
- AC_DEFINE(HAVE_INTRIN_H, 1,
- [Defined when the compilers supports intrinsics])
-fi
-
-# See if the <wspiapi.h> header file is present
-
-AC_CACHE_CHECK(for wspiapi.h,
- tcl_cv_wspiapi_h,
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-#include <wspiapi.h>
-]], [[]])],
- [tcl_cv_wspiapi_h=yes],
- [tcl_cv_wspiapi_h=no])
-)
-if test "$tcl_cv_wspiapi_h" = "yes"; then
- AC_DEFINE(HAVE_WSPIAPI_H, 1,
- [Defined when wspiapi.h exists])
-fi
-
-# See if declarations like FINDEX_INFO_LEVELS are
-# missing from winbase.h. This is known to be
-# a problem with VC++ 5.2.
-
-AC_CACHE_CHECK(for FINDEX_INFO_LEVELS in winbase.h,
- tcl_cv_findex_enums,
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+AC_TRY_COMPILE([
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
-]], [[
+],
+[
FINDEX_INFO_LEVELS i;
FINDEX_SEARCH_OPS j;
-]])],
- [tcl_cv_findex_enums=yes],
- [tcl_cv_findex_enums=no])
+],
+ tcl_cv_findex_enums=yes,
+ tcl_cv_findex_enums=no)
)
if test "$tcl_cv_findex_enums" = "no"; then
AC_DEFINE(HAVE_NO_FINDEX_ENUMS, 1,
@@ -314,6 +164,8 @@ fi
SC_ENABLE_SYMBOLS
+TCL_DBGX=${DBGX}
+
#--------------------------------------------------------------------
# Embed the manifest if we can determine how
#--------------------------------------------------------------------
@@ -330,10 +182,20 @@ TCL_SHARED_BUILD=${SHARED_BUILD}
# Perform final evaluations of variables with possible substitutions.
#--------------------------------------------------------------------
+TCL_SHARED_LIB_SUFFIX="\${NODOT_VERSION}${DLLSUFFIX}"
+TCL_UNSHARED_LIB_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}"
+TCL_EXPORT_FILE_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}"
+
eval "TCL_SRC_DIR=\"`cd $srcdir/..; $CYGPATH $(pwd)`\""
eval "TCL_DLL_FILE=tcl${VER}${DLLSUFFIX}"
+eval "TCL_LIB_FILE=${LIBPREFIX}tcl$VER${LIBSUFFIX}"
+
+eval "TCL_LIB_FLAG=\"-ltcl${VER}${LIBFLAGSUFFIX}\""
+eval "TCL_BUILD_LIB_SPEC=\"-L`$CYGPATH $(pwd)` ${TCL_LIB_FLAG}\""
+eval "TCL_LIB_SPEC=\"-L${libdir} ${TCL_LIB_FLAG}\""
+
eval "TCL_STUB_LIB_FILE=\"${LIBPREFIX}tclstub${VER}${LIBSUFFIX}\""
eval "TCL_STUB_LIB_FLAG=\"-ltclstub${VER}${LIBFLAGSUFFIX}\""
eval "TCL_BUILD_STUB_LIB_SPEC=\"-L`$CYGPATH $(pwd)` ${TCL_STUB_LIB_FLAG}\""
@@ -341,24 +203,18 @@ eval "TCL_STUB_LIB_SPEC=\"-L${libdir} ${TCL_STUB_LIB_FLAG}\""
eval "TCL_BUILD_STUB_LIB_PATH=\"`$CYGPATH $(pwd)`/${TCL_STUB_LIB_FILE}\""
eval "TCL_STUB_LIB_PATH=\"${libdir}/${TCL_STUB_LIB_FILE}\""
-if test ${SHARED_BUILD} = 0 -o "$GCC" != "yes" ; then
- eval "TCL_LIB_FLAG=\"${LIBPREFIX}tcl${VER}${LIBSUFFIX}\""
- eval "TCL_LIB_FILE=\"${LIBPREFIX}tcl${VER}${LIBSUFFIX}\""
-else
- eval "TCL_LIB_FLAG=\"-ltcl${VER}${FLAGSUFFIX}\""
- eval "TCL_LIB_FILE=\"${LIBPREFIX}tcl${VER}${DLLSUFFIX}.a\""
-fi
-eval "TCL_BUILD_LIB_SPEC=\"-L`$CYGPATH $(pwd)` ${TCL_LIB_FLAG}\""
-eval "TCL_LIB_SPEC=\"-L${libdir} ${TCL_LIB_FLAG}\""
-
# Install time header dir can be set via --includedir
eval "TCL_INCLUDE_SPEC=\"-I${includedir}\""
-TCL_SHARED_LIB_SUFFIX="\${NODOT_VERSION}${DLLSUFFIX}"
-TCL_UNSHARED_LIB_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}"
+
+eval "DLLSUFFIX=${DLLSUFFIX}"
+eval "LIBPREFIX=${LIBPREFIX}"
+eval "LIBSUFFIX=${LIBSUFFIX}"
+eval "EXESUFFIX=${EXESUFFIX}"
CFG_TCL_SHARED_LIB_SUFFIX=${TCL_SHARED_LIB_SUFFIX}
CFG_TCL_UNSHARED_LIB_SUFFIX=${TCL_UNSHARED_LIB_SUFFIX}
+CFG_TCL_EXPORT_FILE_SUFFIX=${TCL_EXPORT_FILE_SUFFIX}
#--------------------------------------------------------------------
# Adjust the defines for how the resources are built depending
@@ -366,9 +222,17 @@ CFG_TCL_UNSHARED_LIB_SUFFIX=${TCL_UNSHARED_LIB_SUFFIX}
#--------------------------------------------------------------------
if test ${SHARED_BUILD} = 0 ; then
- RC_DEFINES="${RC_DEFINE} STATIC_BUILD"
+ if test "${DBGX}" = "g"; then
+ RC_DEFINES="${RC_DEFINE} STATIC_BUILD ${RC_DEFINE} DEBUG"
+ else
+ RC_DEFINES="${RC_DEFINE} STATIC_BUILD"
+ fi
else
- RC_DEFINES=""
+ if test "${DBGX}" = "g"; then
+ RC_DEFINES="${RC_DEFINE} DEBUG"
+ else
+ RC_DEFINES=""
+ fi
fi
#--------------------------------------------------------------------
@@ -379,9 +243,9 @@ fi
#--------------------------------------------------------------------
if test "$prefix/lib" != "$libdir"; then
- TCL_PACKAGE_PATH="${libdir};${prefix}\\lib"
+ TCL_PACKAGE_PATH="${libdir} ${prefix}/lib"
else
- TCL_PACKAGE_PATH="${prefix}\\lib"
+ TCL_PACKAGE_PATH="${prefix}/lib"
fi
# The tclsh.exe.manifest requires these
@@ -394,22 +258,16 @@ case "$TCL_PATCH_LEVEL" in
esac
TCL_WIN_VERSION="$TCL_VERSION.$TCL_RELEASE_LEVEL.`echo $TCL_PATCH_LEVEL | tr -d ab.`"
AC_SUBST(TCL_WIN_VERSION)
-# X86|AMD64|ARM64|IA64 for manifest
+# X86|AMD64|IA64 for manifest
AC_SUBST(MACHINE)
AC_SUBST(TCL_VERSION)
AC_SUBST(TCL_MAJOR_VERSION)
AC_SUBST(TCL_MINOR_VERSION)
AC_SUBST(TCL_PATCH_LEVEL)
-AC_SUBST(PKG_CFG_ARGS)
-AC_SUBST(TCL_EXE)
AC_SUBST(TCL_LIB_FILE)
AC_SUBST(TCL_LIB_FLAG)
-AC_SUBST(TCL_STATIC_LIB_FILE)
-AC_SUBST(TCL_STATIC_LIB_FLAG)
-AC_SUBST(TCL_IMPORT_LIB_FILE)
-AC_SUBST(TCL_IMPORT_LIB_FLAG)
# empty on win
AC_SUBST(TCL_LIB_SPEC)
AC_SUBST(TCL_STUB_LIB_FILE)
@@ -423,8 +281,10 @@ AC_SUBST(TCL_DLL_FILE)
AC_SUBST(TCL_SRC_DIR)
AC_SUBST(TCL_BIN_DIR)
+AC_SUBST(TCL_DBGX)
AC_SUBST(CFG_TCL_SHARED_LIB_SUFFIX)
AC_SUBST(CFG_TCL_UNSHARED_LIB_SUFFIX)
+AC_SUBST(CFG_TCL_EXPORT_FILE_SUFFIX)
# win/tcl.m4 doesn't set (CFLAGS)
AC_SUBST(CFLAGS_DEFAULT)
@@ -465,11 +325,12 @@ AC_SUBST(MAKE_EXE)
# empty on win, but needs sub'ing
AC_SUBST(TCL_BUILD_LIB_SPEC)
-AC_SUBST(TCL_CC_SEARCH_FLAGS)
AC_SUBST(TCL_LD_SEARCH_FLAGS)
+AC_SUBST(TCL_NEEDS_EXP_FILE)
AC_SUBST(TCL_BUILD_EXP_FILE)
AC_SUBST(TCL_EXP_FILE)
AC_SUBST(DL_LIBS)
+AC_SUBST(TCL_LIB_VERSIONS_OK)
AC_SUBST(TCL_PACKAGE_PATH)
# win only
@@ -488,9 +349,8 @@ AC_SUBST(RC_DEFINE)
AC_SUBST(RC_DEFINES)
AC_SUBST(RES)
-AC_CONFIG_FILES([Makefile tclConfig.sh tclsh.exe.manifest])
-AC_OUTPUT
+AC_OUTPUT(Makefile tclConfig.sh tcl.hpj tclsh.exe.manifest)
dnl Local Variables:
-dnl mode: autoconf
+dnl mode: autoconf;
dnl End:
diff --git a/win/gitmanifest.in b/win/gitmanifest.in
deleted file mode 100644
index 3e7de84..0000000
--- a/win/gitmanifest.in
+++ /dev/null
@@ -1 +0,0 @@
-git- \ No newline at end of file
diff --git a/win/makefile.bc b/win/makefile.bc
new file mode 100644
index 0000000..6421682
--- /dev/null
+++ b/win/makefile.bc
@@ -0,0 +1,597 @@
+#
+# Makefile for Borland C++ 5.5 (or C++ Builder 5), adapted from the makefile
+# for Visual C++ that came with tcl 8.3.3
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+# Copyright (c) 1995-1996 Sun Microsystems, Inc.
+# Copyright (c) 1998-1999 by Scriptics Corporation.
+
+# TIP #59 information.
+#
+# This makefile does not set the following configuration cpp
+# defines. Behind the defines are the makefile variables listed to set
+# to -D... when that feature is enabled.
+#
+# - TCL_CFG_PROFILED PROFDEFINES
+# - TCL_CFG_OPTIMIZED OPTDEFINES
+# - TCL_CFG_DO64BIT SIXFOURDEFINES
+
+# Have a look at the complete description on how to build and test Tcl with
+# the current Borland compilers at www.ratiosoft.com/tcl/borland.
+#
+# Usage:
+# - Adapt the paths below to match your compiler's location
+# - Make sure the compiler's bin directory is on your path
+# - Open a console
+# - To make a debug version enter
+# make -fmakefile.bc -DNODEBUG=0 xxx
+# where 'xxx' is the target you want (e.g. 'all', 'test', ...)
+# Please note: I omitted the 'd' suffix for debug versions because Tcl
+# will always call tclpip83.dll and not tclpip83d.dll, causing an error.
+# ^
+# Besides, the debug version goes into a separate directory, so there
+# should be no problem having DLLs and EXEs with the same name.
+# If you prefer your debug version having the 'd' suffix just uncomment
+# the line
+# #DBGX = d
+#
+# - To make a 'normal' version enter
+# make -fmakefile.bc xxx
+# where 'xxx' is the target you want (e.g. 'all', 'test', ...)
+#
+# DISCLAIMER:
+# This makefile has an experimental status - that is those targets which
+# have been modified do in fact compile and link with Borland's C++
+# Builder 5 and with the free Borland compiler (Borland C++ 5.5).
+# However the author assumes no responsiblity for any effect which the use of
+# this makefile or of the resulting programs might have on your system.
+#
+# Not yet modified:
+# - The 'plug-in-DLL' and the associated shell.
+# - The programs to create the windows help files.
+#
+# Suggestions and / or improvements are always welcome.
+#
+# May 2001, H. Giese (hgiese@ratiosoft.com)
+#
+
+# Does not depend on the presence of any environment variables in
+# order to compile tcl; all needed information is derived from
+# location of the compiler directories.
+
+#
+# Project directories
+#
+# ROOT = top of source tree
+#
+# TOOLS32 = location of Borland development tools.
+#
+# INSTALLDIR = where the install-targets should copy the binaries and
+# support files
+#
+
+ROOT = ..
+INSTALLDIR = c:\program files\tcl
+
+# If you have C++ Builder 5 or the free Borland C++ 5.5 compiler
+# adapt the following paths as appropriate for your system
+TOOLS32 = c:\dev\bcc55
+TOOLS32_rc = c:\dev\bcc55
+#TOOLS32 = c:\bc55
+#TOOLS32_rc = c:\bc55
+
+cc32 = "$(TOOLS32)\bin\bcc32.exe"
+link32 = "$(TOOLS32)\bin\ilink32.exe"
+lib32 = "$(TOOLS32)\bin\tlib.exe"
+rc32 = "$(TOOLS32_rc)\bin\brcc32.exe"
+include32 = -I"$(TOOLS32)\include"
+libpath32 = -L"$(TOOLS32)\lib"
+
+# Uncomment the following line to compile with thread support
+#THREADDEFINES = -DTCL_THREADS=1
+
+# Allow definition of NDEBUG via command line
+# Set NODEBUG to 0 to compile with symbols
+!if !defined(NODEBUG)
+NODEBUG = 1
+!endif
+
+# CFG_ENCODING=encoding
+# name of encoding for configuration information. Defaults
+# to cp1252
+!if !defined(CFG_ENCODING)
+CFG_ENCODING = \"cp1252\"
+!endif
+
+# The following defines can be used to control the amount of debugging
+# code that is added to the compilation.
+#
+# -DTCL_MEM_DEBUG Enables the debugging memory allocator.
+# -DTCL_COMPILE_DEBUG Enables byte compilation logging.
+# -DTCL_COMPILE_STATS Enables byte compilation statistics gathering.
+# -DUSE_TCLALLOC=0 Disables the Tcl memory allocator in favor
+# of the native malloc implementation. This is
+# needed when using Purify.
+#
+#DEBUGDEFINES = -DTCL_MEM_DEBUG -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS
+#DEBUGDEFINES = -DUSE_TCLALLOC=0
+
+######################################################################
+# Do not modify below this line
+######################################################################
+
+NAMEPREFIX = tcl
+STUBPREFIX = $(NAMEPREFIX)stub
+DOTVERSION = 8.5
+VERSION = 85
+
+DDEVERSION = 13
+DDEDOTVERSION = 1.3
+
+REGVERSION = 12
+REGDOTVERSION = 1.2
+
+BINROOT = ..
+!IF "$(NODEBUG)" == "1"
+TMPDIRNAME = Release
+DBGX =
+SYMDEFINES = -DNDEBUG
+!ELSE
+TMPDIRNAME = Debug
+#DBGX = d
+DBGX =
+SYMDEFINES = -DTCL_CFG_DEBUG
+!ENDIF
+TMPDIR = $(BINROOT)\$(TMPDIRNAME)
+OUTDIRNAME = $(TMPDIRNAME)
+OUTDIR = $(TMPDIR)
+
+TCLLIB = $(OUTDIR)\$(NAMEPREFIX)$(VERSION)$(DBGX).lib
+TCLDLLNAME = $(NAMEPREFIX)$(VERSION)$(DBGX).dll
+TCLDLL = $(OUTDIR)\$(TCLDLLNAME)
+
+TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION)$(DBGX).lib
+TCLSTUBLIB = $(OUTDIR)\$(TCLSTUBLIBNAME)
+
+TCLPLUGINLIB = $(OUTDIR)\$(NAMEPREFIX)$(VERSION)p$(DBGX).lib
+TCLPLUGINDLLNAME = $(NAMEPREFIX)$(VERSION)p$(DBGX).dll
+TCLPLUGINDLL = $(OUTDIR)\$(TCLPLUGINDLLNAME)
+TCLSH = $(OUTDIR)\$(NAMEPREFIX)sh$(VERSION)$(DBGX).exe
+TCLSHP = $(OUTDIR)\$(NAMEPREFIX)shp$(VERSION)$(DBGX).exe
+TCLPIPEDLLNAME = $(NAMEPREFIX)pip$(VERSION)$(DBGX).dll
+TCLPIPEDLL = $(OUTDIR)\$(TCLPIPEDLLNAME)
+TCLREGDLLNAME = $(NAMEPREFIX)reg$(REGVERSION)$(DBGX).dll
+TCLREGDLL = $(OUTDIR)\$(TCLREGDLLNAME)
+TCLDDEDLLNAME = $(NAMEPREFIX)dde$(DDEVERSION)$(DBGX).dll
+TCLDDEDLL = $(OUTDIR)\$(TCLDDEDLLNAME)
+TCLTEST = $(OUTDIR)\$(NAMEPREFIX)test.exe
+CAT32 = $(TMPDIR)\cat32.exe
+RMDIR = .\rmd.bat
+MKDIR = .\mkd.bat
+RM = del
+
+LIB_INSTALL_DIR = $(INSTALLDIR)\lib
+BIN_INSTALL_DIR = $(INSTALLDIR)\bin
+SCRIPT_INSTALL_DIR = $(INSTALLDIR)\lib\tcl$(DOTVERSION)
+INCLUDE_INSTALL_DIR = $(INSTALLDIR)\include
+
+TCLSHOBJS = \
+ $(TMPDIR)\tclAppInit.obj
+
+TCLTESTOBJS = \
+ $(TMPDIR)\tclTest.obj \
+ $(TMPDIR)\tclTestObj.obj \
+ $(TMPDIR)\tclTestProcBodyObj.obj \
+ $(TMPDIR)\tclThreadTest.obj \
+ $(TMPDIR)\tclWinTest.obj \
+ $(TMPDIR)\testMain.obj
+
+TCLOBJS = \
+ $(TMPDIR)\regcomp.obj \
+ $(TMPDIR)\regexec.obj \
+ $(TMPDIR)\regfree.obj \
+ $(TMPDIR)\regerror.obj \
+ $(TMPDIR)\tclAlloc.obj \
+ $(TMPDIR)\tclAsync.obj \
+ $(TMPDIR)\tclBasic.obj \
+ $(TMPDIR)\tclBinary.obj \
+ $(TMPDIR)\tclCkalloc.obj \
+ $(TMPDIR)\tclClock.obj \
+ $(TMPDIR)\tclCmdAH.obj \
+ $(TMPDIR)\tclCmdIL.obj \
+ $(TMPDIR)\tclCmdMZ.obj \
+ $(TMPDIR)\tclCompCmds.obj \
+ $(TMPDIR)\tclCompExpr.obj \
+ $(TMPDIR)\tclCompile.obj \
+ $(TMPDIR)\tclConfig.obj \
+ $(TMPDIR)\tclDate.obj \
+ $(TMPDIR)\tclDictObj.obj \
+ $(TMPDIR)\tclEncoding.obj \
+ $(TMPDIR)\tclEnv.obj \
+ $(TMPDIR)\tclEvent.obj \
+ $(TMPDIR)\tclExecute.obj \
+ $(TMPDIR)\tclFCmd.obj \
+ $(TMPDIR)\tclFileName.obj \
+ $(TMPDIR)\tclGet.obj \
+ $(TMPDIR)\tclHash.obj \
+ $(TMPDIR)\tclHistory.obj \
+ $(TMPDIR)\tclIndexObj.obj \
+ $(TMPDIR)\tclInterp.obj \
+ $(TMPDIR)\tclIO.obj \
+ $(TMPDIR)\tclIOCmd.obj \
+ $(TMPDIR)\tclIOGT.obj \
+ $(TMPDIR)\tclIOSock.obj \
+ $(TMPDIR)\tclIOUtil.obj \
+ $(TMPDIR)\tclLink.obj \
+ $(TMPDIR)\tclLiteral.obj \
+ $(TMPDIR)\tclListObj.obj \
+ $(TMPDIR)\tclLoad.obj \
+ $(TMPDIR)\tclMain.obj \
+ $(TMPDIR)\tclNamesp.obj \
+ $(TMPDIR)\tclNotify.obj \
+ $(TMPDIR)\tclObj.obj \
+ $(TMPDIR)\tclPanic.obj \
+ $(TMPDIR)\tclParse.obj \
+ $(TMPDIR)\tclPipe.obj \
+ $(TMPDIR)\tclPkg.obj \
+ $(TMPDIR)\tclPkgConfig.obj \
+ $(TMPDIR)\tclPosixStr.obj \
+ $(TMPDIR)\tclPreserve.obj \
+ $(TMPDIR)\tclProc.obj \
+ $(TMPDIR)\tclRegexp.obj \
+ $(TMPDIR)\tclResolve.obj \
+ $(TMPDIR)\tclResult.obj \
+ $(TMPDIR)\tclScan.obj \
+ $(TMPDIR)\tclStringObj.obj \
+ $(TMPDIR)\tclStubInit.obj \
+ $(TMPDIR)\tclStubLib.obj \
+ $(TMPDIR)\tclThread.obj \
+ $(TMPDIR)\tclThreadJoin.obj \
+ $(TMPDIR)\tclTimer.obj \
+ $(TMPDIR)\tclTrace.obj \
+ $(TMPDIR)\tclUtf.obj \
+ $(TMPDIR)\tclUtil.obj \
+ $(TMPDIR)\tclVar.obj \
+ $(TMPDIR)\tclWin32Dll.obj \
+ $(TMPDIR)\tclWinChan.obj \
+ $(TMPDIR)\tclWinConsole.obj \
+ $(TMPDIR)\tclWinSerial.obj \
+ $(TMPDIR)\tclWinError.obj \
+ $(TMPDIR)\tclWinFCmd.obj \
+ $(TMPDIR)\tclWinFile.obj \
+ $(TMPDIR)\tclWinInit.obj \
+ $(TMPDIR)\tclWinLoad.obj \
+ $(TMPDIR)\tclWinNotify.obj \
+ $(TMPDIR)\tclWinPipe.obj \
+ $(TMPDIR)\tclWinSock.obj \
+ $(TMPDIR)\tclWinThrd.obj \
+ $(TMPDIR)\tclWinTime.obj
+
+TCLSTUBOBJS = $(TMPDIR)\tclStubLib.obj
+
+WINDIR = $(ROOT)\win
+GENERICDIR = $(ROOT)\generic
+
+TCL_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)"
+TCL_DEFINES = $(DEBUGDEFINES) $(THREADDEFINES) $(SYMDEFINES) \
+ $(PROFDEFINES) $(OPTDEFINES) $(SIXFOURDEFINES) \
+ -DTCL_CFGVAL_ENCODING=${CFG_ENCODING}
+
+######################################################################
+# Compiler flags
+######################################################################
+
+!IF "$(NODEBUG)" == "1"
+# these macros cause maximum optimization and no symbols
+cdebug = -v- -vi- -O2 -D_DEBUG
+!ELSE
+# these macros enable debugging
+cdebug = -k -Od -r- -v -vi- -y
+!ENDIF
+
+SYSDEFINES = _MT;NO_STRICT;_NO_VCL
+
+# declarations common to all compiler options
+cbase = -c -q -3 -a4 -g0 -tWM -Ve -Vx -X-
+WARNINGS = -w-rch -w-pch -w-par -w-dup -w-pro -w-dpu
+
+ccons = -tWC
+
+INCLUDEPATH = $(include32) $(TCL_INCLUDES)
+
+CFLAGS = $(cdebug) $(cbase) $(INCLUDEPATH) $(WARNINGS) -D$(SYSDEFINES)
+TCL_CFLAGS = $(CFLAGS) $(TCL_DEFINES)
+CONS_CFLAGS = $(CFLAGS) $(TCL_DEFINES) $(ccons)
+
+######################################################################
+# Linker flags
+######################################################################
+
+!IF "$(NODEBUG)" == "1"
+ldebug =
+!ELSE
+ldebug = -v
+!ENDIF
+
+# declarations common to all linker options
+LNFLAGS = -D"" -Gn -I$(TMPDIR) -x $(ldebug) $(libpath32)
+# -Gi: create lib file (is -Gl in doc)
+# -aa: Windows app, -ap: Windows console app
+LNFLAGS_DLL = -ap -Gi -Tpd
+LNFLAGS_CONS = -ap -Tpe
+
+LNLIBS = import32 cw32mt
+
+
+######################################################################
+# Project specific targets
+######################################################################
+
+release: setup $(TCLSH) dlls
+dlls: setup $(TCLPIPEDLL) $(TCLREGDLL) $(TCLDDEDLL)
+all: setup $(TCLSH) dlls $(CAT32)
+tcltest: setup $(TCLTEST) dlls $(CAT32)
+plugin: setup $(TCLPLUGINDLL) $(TCLSHP)
+install: install-binaries install-libraries
+
+test: setup $(TCLTEST) dlls $(CAT32)
+ set TCL_LIBRARY=$(ROOT)/library
+ $(TCLTEST) $(ROOT)/tests/all.tcl
+
+setup:
+ @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) &\
+ echo *** Created directory '$(OUT_DIR)'
+ @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) &\
+ echo *** Created directory '$(TMP_DIR)'
+
+
+$(TCLLIB): $(TCLDLL)
+
+$(TCLDLL): $(TCLOBJS) $(TMPDIR)\$(NAMEPREFIX).res
+ $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_DLL) $(TOOLS32)\lib\c0d32 @&&!
+ $(TCLOBJS), $@, -x, $(LNLIBS),, $(TMPDIR)\$(NAMEPREFIX).res
+!
+
+$(TCLSTUBLIB): $(TCLSTUBOBJS)
+ $(lib32) /u $@ $(TCLSTUBOBJS)
+
+$(TCLPLUGINLIB): $(TCLPLUGINDLL)
+
+$(TCLPLUGINDLL): $(TCLOBJS) $(TMPDIR)\tcl.res
+ $(link32) $(ldebug) $(dlllflags) \
+ -out:$@ $(TMPDIR)\tcl.res $(guilibsdll) @&&!
+$(TCLOBJS)
+!
+
+$(TCLSH): $(TCLSHOBJS) $(TCLLIB) $(TMPDIR)\$(NAMEPREFIX)sh.res
+ $(link32) $(ldebug) -S:2400000 $(LNFLAGS) $(LNFLAGS_CONS) $(TOOLS32)\lib\c0x32 @&&!
+ $(TCLSHOBJS), $@, -x, $(LNLIBS) $(TCLLIB),, $(TMPDIR)\$(NAMEPREFIX)sh.res
+!
+
+$(TCLSHP): $(TCLSHOBJS) $(TCLPLUGINLIB) $(TMPDIR)\tclsh.res
+ $(link32) $(ldebug) $(conlflags) $(TMPDIR)\tclsh.res -stack:2300000 \
+ -out:$@ $(conlibsdll) $(TCLPLUGINLIB) $(TCLSHOBJS)
+
+$(TCLTEST): $(TCLTESTOBJS) $(TCLLIB) $(TMPDIR)\$(NAMEPREFIX)sh.res
+ $(link32) $(ldebug) -S:2400000 $(LNFLAGS) $(LNFLAGS_CONS) $(TOOLS32)\lib\c0x32 @&&!
+ $(TCLTESTOBJS), $@, -x, $(LNLIBS) $(TCLLIB),, $(TMPDIR)\$(NAMEPREFIX)sh.res
+!
+
+$(TCLPIPEDLL): $(WINDIR)\stub16.c
+ $(cc32) $(CFLAGS) -o$(TMPDIR)\stub16.obj $(WINDIR)\stub16.c
+ $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_CONS) $(TOOLS32)\lib\c0x32 \
+ $(TMPDIR)\stub16.obj, $@, -x, $(LNLIBS),, $(TMPDIR)\$(NAMEPREFIX).res
+
+$(TCLDDEDLL): $(TMPDIR)\tclWinDde.obj $(TCLSTUBLIB)
+ $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_DLL) $(TOOLS32)\lib\c0d32 \
+ $(TMPDIR)\tclWinDde.obj, $@, -x, $(LNLIBS) $(TCLSTUBLIB),, \
+ $(TMPDIR)\$(NAMEPREFIX).res
+
+$(TCLREGDLL): $(TMPDIR)\tclWinReg.obj $(TCLSTUBLIB)
+ $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_DLL) $(TOOLS32)\lib\c0d32 \
+ $(TMPDIR)\tclWinReg.obj, $@, -x, $(LNLIBS) $(TCLSTUBLIB),, \
+ $(TMPDIR)\$(NAMEPREFIX).res
+
+$(CAT32): $(WINDIR)\cat.c
+ $(cc32) $(CONS_CFLAGS) -o$(TMPDIR)\cat.obj $?
+ $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_CONS) $(TOOLS32)\lib\c0x32 \
+ $(TMPDIR)\cat.obj, $@, -x, $(LNLIBS),,
+
+install-binaries: $(TCLSH)
+ $(MKDIR) "$(BIN_INSTALL_DIR)"
+ $(MKDIR) "$(LIB_INSTALL_DIR)"
+ @echo Installing $(TCLDLLNAME)
+ @copy "$(TCLDLL)" "$(BIN_INSTALL_DIR)"
+ @copy "$(TCLLIB)" "$(LIB_INSTALL_DIR)"
+ @echo Installing "$(TCLSH)"
+ @copy "$(TCLSH)" "$(BIN_INSTALL_DIR)"
+ @echo Installing $(TCLPIPEDLLNAME)
+ @copy "$(TCLPIPEDLL)" "$(BIN_INSTALL_DIR)"
+ @echo Installing $(TCLSTUBLIBNAME)
+ @copy "$(TCLSTUBLIB)" "$(LIB_INSTALL_DIR)"
+
+install-libraries:
+ -@$(MKDIR) "$(LIB_INSTALL_DIR)"
+ -@$(MKDIR) "$(INCLUDE_INSTALL_DIR)"
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)"
+ @echo Installing http1.0
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\http1.0"
+ -@copy "$(ROOT)\library\http1.0\http.tcl" "$(SCRIPT_INSTALL_DIR)\http1.0"
+ -@copy "$(ROOT)\library\http1.0\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\http1.0"
+ @echo Installing http2.7
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\http2.7"
+ -@copy "$(ROOT)\library\http\http.tcl" "$(SCRIPT_INSTALL_DIR)\http2.7"
+ -@copy "$(ROOT)\library\http\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\http2.7"
+ @echo Installing opt0.4
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\opt0.4"
+ -@copy "$(ROOT)\library\opt\optparse.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4"
+ -@copy "$(ROOT)\library\opt\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4"
+ @echo Installing msgcat1.5
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\msgcat1.5"
+ -@copy "$(ROOT)\library\msgcat\msgcat.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.5"
+ -@copy "$(ROOT)\library\msgcat\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.5"
+ @echo Installing tcltest2.3
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\tcltest2.3"
+ -@copy "$(ROOT)\library\tcltest\tcltest.tcl" "$(SCRIPT_INSTALL_DIR)\tcltest2.3"
+ -@copy "$(ROOT)\library\tcltest\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\tcltest2.3"
+ @echo Installing platform1.0
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\platform1.0"
+ -@copy "$(ROOT)\library\platform\platform.tcl" "$(SCRIPT_INSTALL_DIR)\platform1.0"
+ -@copy "$(ROOT)\library\platform\shell.tcl" "$(SCRIPT_INSTALL_DIR)\platform1.0"
+ -@copy "$(ROOT)\library\platform\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\platform1.0"
+ @echo Installing $(TCLDDEDLLNAME)
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\dde1.3"
+ -@copy "$(TCLDDEDLL)" "$(SCRIPT_INSTALL_DIR)\dde1.3"
+ -@copy "$(ROOT)\library\dde\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\dde1.3"
+ @echo Installing $(TCLREGDLLNAME)
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\reg1.2"
+ -@copy "$(TCLREGDLL)" "$(SCRIPT_INSTALL_DIR)\reg1.2"
+ -@copy "$(ROOT)\library\reg\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\reg1.2"
+ @echo Installing encoding files
+ -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\encoding"
+ -@copy "$(ROOT)\library\encoding\*.enc" "$(SCRIPT_INSTALL_DIR)\encoding"
+ @echo Installing library files
+ -@copy "$(GENERICDIR)\tcl.h" "$(INCLUDE_INSTALL_DIR)"
+ -@copy "$(GENERICDIR)\tclDecls.h" "$(INCLUDE_INSTALL_DIR)"
+ -@copy "$(GENERICDIR)\tclPlatDecls.h" "$(INCLUDE_INSTALL_DIR)"
+ -@copy "$(ROOT)\library\history.tcl" "$(SCRIPT_INSTALL_DIR)"
+ -@copy "$(ROOT)\library\init.tcl" "$(SCRIPT_INSTALL_DIR)"
+ -@copy "$(ROOT)\library\parray.tcl" "$(SCRIPT_INSTALL_DIR)"
+ -@copy "$(ROOT)\library\safe.tcl" "$(SCRIPT_INSTALL_DIR)"
+ -@copy "$(ROOT)\library\tclIndex" "$(SCRIPT_INSTALL_DIR)"
+ -@copy "$(ROOT)\library\package.tcl" "$(SCRIPT_INSTALL_DIR)"
+ -@copy "$(ROOT)\library\word.tcl" "$(SCRIPT_INSTALL_DIR)"
+ -@copy "$(ROOT)\library\auto.tcl" "$(SCRIPT_INSTALL_DIR)"
+
+#
+# Regenerate the stubs files.
+#
+
+genstubs:
+ tclsh$(VERSION) $(ROOT)\tools\genStubs.tcl $(GENERICDIR) \
+ $(GENERICDIR)\tcl.decls $(GENERICDIR)\tclInt.decls
+
+#
+# Regenerate the windows help files.
+#
+
+TCLTOOLS = $(ROOT)/tools
+MAN2TCL = $(TCLTOOLS)/man2tcl
+TCLRTF = $(TCLTOOLS)/tcl.rtf
+TCLHPJ = $(TCLTOOLS)/tcl.hpj
+MAN2HELP = $(TCLTOOLS)/man2help.tcl
+HCRTF = $(TOOLS32)/bin/hcrtf.exe
+
+winhelp: $(TCLRTF)
+ cd $(TCLTOOLS)
+ start /wait $(HCRTF) -xn $(TCLHPJ)
+
+$(MAN2TCL).exe: $(MAN2TCL).obj
+ cd $(TCLTOOLS)
+ $(cc32) /nologo /G4 /ML /O2 $(MAN2TCL).c
+
+$(TCLRTF): $(MAN2TCL).exe $(TCLSH)
+ cd $(TCLTOOLS)
+ ..\win\$(TCLSH) $(MAN2HELP) $(NAMEPREFIX) $(VERSION) $(ROOT)/doc ../../tk$(DOTVERSION)/doc
+
+#
+# Special case object file targets
+#
+$(TMPDIR)\tclWinInit.obj: $(WINDIR)\tclWinInit.c
+ $(cc32) -DBUILD_tcl $(TCL_CFLAGS) -o$(TMPDIR)\$@ $?
+
+$(TMPDIR)\testMain.obj: $(WINDIR)\tclAppInit.c
+ $(cc32) $(TCL_CFLAGS) -DTCL_TEST -o$(TMPDIR)\testMain.obj $?
+
+$(TMPDIR)\tclTest.obj: $(GENERICDIR)\tclTest.c
+ $(cc32) $(TCL_CFLAGS) -o$(TMPDIR)\$@ $?
+
+$(TMPDIR)\tclTestObj.obj: $(GENERICDIR)\tclTestObj.c
+ $(cc32) $(TCL_CFLAGS) -o$(TMPDIR)\$@ $?
+
+$(TMPDIR)\tclWinTest.obj: $(WINDIR)\tclWinTest.c
+ $(cc32) $(TCL_CFLAGS) -o$(TMPDIR)\$@ $?
+
+$(TMP_DIR)\tclPkgConfig.obj: $(GENERICDIR)\tclPkgConfig.c
+ $(cc32) $(TCL_CFLAGS) \
+ -DCFG_INSTALL_EXEC_PREFIX=\"$(INSTALL_EXEC_PREFIX)\" \
+ -DCFG_INSTALL_PREFIX=\"$(INSTALL_PREFIX)\" \
+ -DCFG_RUNTIME_EXEC_PREFIX=\"$(RUNTIME_EXEC_PREFIX)\" \
+ -DCFG_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" \
+ -o$(TMPDIR)\$@ $?
+
+$(TMPDIR)\tclAppInit.obj : $(WINDIR)\tclAppInit.c
+ $(cc32) $(TCL_CFLAGS) -o$(TMPDIR)\$@ $?
+
+# The following objects should be built using the stub interfaces
+
+# tclWinReg: Produces errors in ANSI mode
+$(TMPDIR)\tclWinReg.obj : $(WINDIR)\tclWinReg.c
+ $(cc32) $(TCL_CFLAGS) -DUSE_TCL_STUBS -o$(TMPDIR)\$@ $?
+
+# tclWinDde: Produces errors in ANSI mode
+$(TMPDIR)\tclWinDde.obj : $(WINDIR)\tclWinDde.c
+ $(cc32) $(TCL_CFLAGS) -DUSE_TCL_STUBS -o$(TMPDIR)\$@ $?
+
+
+# The following objects are part of the stub library and should not
+# be built as DLL objects but none of the symbols should be exported
+
+$(TMPDIR)\tclStubLib.obj : $(GENERICDIR)\tclStubLib.c
+ $(cc32) $(TCL_CFLAGS) -DSTATIC_BUILD -o$(TMPDIR)\$@ $?
+
+
+# Dedependency rules
+
+$(GENERICDIR)\regcomp.c: \
+ $(GENERICDIR)\regguts.h \
+ $(GENERICDIR)\regc_lex.c \
+ $(GENERICDIR)\regc_color.c \
+ $(GENERICDIR)\regc_nfa.c \
+ $(GENERICDIR)\regc_cvec.c \
+ $(GENERICDIR)\regc_locale.c
+
+$(GENERICDIR)\regcustom.h: \
+ $(GENERICDIR)\tclInt.h \
+ $(GENERICDIR)\tclPort.h \
+ $(GENERICDIR)\regex.h
+
+$(GENERICDIR)\regexec.c: \
+ $(GENERICDIR)\rege_dfa.c \
+ $(GENERICDIR)\regguts.h
+
+$(GENERICDIR)\regerror.c: $(GENERICDIR)\regguts.h
+$(GENERICDIR)\regfree.c: $(GENERICDIR)\regguts.h
+$(GENERICDIR)\regfronts.c: $(GENERICDIR)\regguts.h
+$(GENERICDIR)\regguts.h: $(GENERICDIR)\regcustom.h
+
+#
+# Implicit rules
+#
+
+{$(WINDIR)}.c{$(TMPDIR)}.obj:
+ $(cc32) -DBUILD_tcl $(TCL_CFLAGS) -o$@ $<
+
+{$(GENERICDIR)}.c{$(TMPDIR)}.obj:
+ $(cc32) -DBUILD_tcl $(TCL_CFLAGS) -o$@ $<
+
+{$(ROOT)\compat}.c{$(TMPDIR)}.obj:
+ $(cc32) -DBUILD_tcl $(TCL_CFLAGS) -o$@ $<
+
+{$(WINDIR)}.rc{$(TMPDIR)}.res:
+ $(rc32) $(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -fo$@ $<
+
+clean:
+ -@$(RM) $(OUTDIR)\*.exp
+ -@$(RM) $(OUTDIR)\*.lib
+ -@$(RM) $(OUTDIR)\*.dll
+ -@$(RM) $(OUTDIR)\*.exe
+ -@$(RM) $(OUTDIR)\*.pdb
+ -@$(RM) $(TMPDIR)\*.pch
+ -@$(RM) $(TMPDIR)\*.obj
+ -@$(RM) $(TMPDIR)\*.res
+ -@$(RM) $(TMPDIR)\*.exe
+ -@$(RMDIR) $(OUTDIR)
+ -@$(RMDIR) $(TMPDIR)
diff --git a/win/makefile.vc b/win/makefile.vc
index 987bcb8..8c8ecdf 100644
--- a/win/makefile.vc
+++ b/win/makefile.vc
@@ -1,6 +1,7 @@
#------------------------------------------------------------- -*- makefile -*-
+# makefile.vc --
#
-# Microsoft Visual C++ makefile for building Tcl with nmake
+# Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+)
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -10,20 +11,42 @@
# Copyright (c) 2001-2005 ActiveState Corporation.
# Copyright (c) 2001-2004 David Gravereaux.
# Copyright (c) 2003-2008 Pat Thoyts.
-# Copyright (c) 2017 Ashok P. Nadkarni
#------------------------------------------------------------------------------
-# General usage:
-# nmake [-nologo] -f makefile.vc [TARGET|MACRODEF [TARGET|MACRODEF] [...]]
+# Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or
+# VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir)
+!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR)
+MSG = ^
+You need to run vcvars32.bat from Developer Studio or setenv.bat from the^
+Platform SDK first to setup the environment. Jump to this line to read^
+the build instructions.
+!error $(MSG)
+!endif
+
+#------------------------------------------------------------------------------
+# HOW TO USE this makefile:
+#
+# 1) It is now necessary to have MSVCDir, MSDevDir or MSSDK set in the
+# environment. This is used as a check to see if vcvars32.bat had been
+# run prior to running nmake or during the installation of Microsoft
+# Visual C++, MSVCDir had been set globally and the PATH adjusted.
+# Either way is valid.
#
-# For MACRODEF, see TIP 477 (https://core.tcl-lang.org/tips/doc/main/tip/477.md)
-# or examine Sections 7-9 in rules.vc.
+# You'll need to run vcvars32.bat contained in the MsDev's vc(98)/bin
+# directory to setup the proper environment, if needed, for your
+# current setup. This is a needed bootstrap requirement and allows the
+# swapping of different environments to be easier.
#
-# Possible values for TARGET are:
-# release -- Builds everything that ships with a release. (default)
-# core -- Builds the core [tclXX.(dll|lib)]
-# shell -- Builds tclsh and the core.
-# dlls -- Just builds the windows extensions.
+# 2) To use the Platform SDK (not expressly needed), run setenv.bat after
+# vcvars32.bat according to the instructions for it. This can also
+# turn on the 64-bit compiler, if your SDK has it.
+#
+# 3) Targets are:
+# release -- Builds the core, the shell and the dlls. (default)
+# dlls -- Just builds the windows extensions and the 16-bit DOS
+# pipe/thunk helper app.
+# shell -- Just builds the shell and the core.
+# core -- Only builds the core [tclXX.(dll|lib)].
# all -- Builds everything.
# test -- Builds and runs the test suite.
# tcltest -- Just builds the test shell.
@@ -39,47 +62,38 @@
# troff manual pages found in $(ROOT)\doc. You need to
# have installed the HTML Help Compiler package from Microsoft
# to produce the .chm file.
+# winhelp -- Builds the windows .hlp file for Tcl from the troff man
+# files found in $(ROOT)\doc.
#
-# The steps to setup a Visual C++ environment depend on which
-# version of Visual Studio and/or the Windows SDK you are building
-# against and are not described here. The simplest method is generally
-# to start a command shell using one of the short cuts installed by
-# Visual Studio/Windows SDK for the appropriate target architecture.
-#
-# NOTE: For older (Visual C++ 6 or the 2003 SDK), to use the Platform
-# SDK (not expressly needed), run setenv.bat after vcvars32.bat
-# according to the instructions for it. This can also turn on the
-# 64-bit compiler, if your SDK has it.
+# 4) Macros usable on the commandline:
+# INSTALLDIR=<path>
+# Sets where to install Tcl from the built binaries.
+# C:\Progra~1\Tcl is assumed when not specified.
#
-# Basic macros and options usable on the commandline (see rules.vc for more info):
-# OPTS=msvcrt,noembed,nothreads,pdbs,profile,static,symbols,thrdalloc,time64bit,unchecked,none
+# OPTS=loimpact,msvcrt,static,staticpkg,symbols,threads,profile,unchecked,none
# Sets special options for the core. The default is for none.
# Any combination of the above may be used (comma separated).
# 'none' will over-ride everything to nothing.
#
-# noembed = Without this option, the Tcl core library scripts
-# are embedded into the executable if "static" is
-# specified in OPTS, or into the DLL otherwise. If
-# "noembed" is specified, the scripts are not embedded
-# but copied to the installation target (as in 8.6).
-# nomsvcrt = Affects the static option only to switch it from
-# using msvcrt(d) as the C runtime [by default] to
-# libcmt(d). This is useful for static embedding
-# support.
-# none = Overrides all other options to nothing.
-# nothreads = Turns off full multithreading support (default on).
-# pdbs = Produce separate debug symbol files.
-# profile = Adds profiling hooks. Map file is assumed.
-# static = Builds a static library of the core instead of a
-# dll. The shell will be static (and large), and
-# have the dde and registry extensions linked inside.
-# symbols = Adds symbols for step debugging.
+# loimpact = Adds a flag for how NT treats the heap to keep memory
+# in use, low. This is said to impact alloc performance.
+# msvcrt = Affects the static option only to switch it from
+# using libcmt(d) as the C runtime [by default] to
+# msvcrt(d). This is useful for static embedding
+# support.
+# static = Builds a static library of the core instead of a
+# dll. The shell will be static (and large), as well.
+# staticpkg= Affects the static option only to switch
+# tclshXX.exe to have the dde and reg extension linked
+# inside it.
+# threads = Turns on full multithreading support.
# thrdalloc = Use the thread allocator (shared global free pool).
-# time64bit = Forces a build using 64-bit time_t for 32-bit build
-# (CRT library should support this).
+# thrdstorage = Use the generic thread storage support.
+# symbols = Adds symbols for step debugging.
+# profile = Adds profiling hooks. Map file is assumed.
# unchecked = Allows a symbols build to not use the debug
-# enabled runtime (msvcrt.dll not msvcrtd.dll
-# or libcmt.lib not libcmtd.lib).
+# enabled runtime (msvcrt.dll not msvcrtd.dll
+# or libcmt.lib not libcmtd.lib).
#
# STATS=compdbg,memdbg,none
# Sets optional memory and bytecode compiler debugging code added
@@ -91,15 +105,15 @@
# memdbg = Enables the debugging memory allocator.
#
# CHECKS=64bit,fullwarn,nodep,none
-# Sets special macros for checking compatibility.
+# Sets special macros for checking compatability.
#
# 64bit = Enable 64bit portability warnings (if available)
# fullwarn = Builds with full compiler and link warnings enabled.
# Very verbose.
-# nodep = Turns off compatibility macros to ensure the core
+# nodep = Turns off compatability macros to ensure the core
# isn't being built with deprecated functions.
#
-# MACHINE=(ALPHA|AMD64|ARM64|IA64|IX86)
+# MACHINE=(ALPHA|AMD64|IA64|IX86)
# Set the machine type used for the compiler, linker, and
# resource compiler. This hook is needed to tell the tools
# when alternate platforms are requested. IX86 is the default
@@ -111,123 +125,115 @@
# Hooks to allow the intermediate and output directories to be
# changed. $(OUT_DIR) is assumed to be
# $(BINROOT)\(Release|Debug) based on if symbols are requested.
-# $(TMP_DIR) will be $(OUT_DIR)\<buildtype> by default.
+# $(TMP_DIR) will de $(OUT_DIR)\<buildtype> by default.
#
# TESTPAT=<file>
# Reads the tests requested to be run from this file.
#
-# Examples:
+# CFG_ENCODING=encoding
+# name of encoding for configuration information. Defaults
+# to cp1252
+#
+# 5) Examples:
+#
+# Basic syntax of calling nmake looks like this:
+# nmake [-nologo] -f makefile.vc [target|macrodef [target|macrodef] [...]]
+#
+# Standard (no frills)
+# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat
+# Setting environment for using Microsoft Visual C++ tools.
# c:\tcl_src\win\>nmake -f makefile.vc release
-# c:\tcl_src\win\>nmake -f makefile.vc test
# c:\tcl_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl
-# c:\tcl_src\win\>nmake -f makefile.vc release OPTS=pdbs
-# c:\tcl_src\win\>nmake -f makefile.vc release OPTS=symbols
#
+# Building for Win64
+# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat
+# Setting environment for using Microsoft Visual C++ tools.
+# c:\tcl_src\win\>c:\progra~1\platfo~1\setenv.bat /pre64 /RETAIL
+# Targeting Windows pre64 RETAIL
+# c:\tcl_src\win\>nmake -f makefile.vc MACHINE=IA64
+#
+#------------------------------------------------------------------------------
+#==============================================================================
+###############################################################################
-# NOTE:
-# Before modifying this file, check whether the modification is applicable
-# to building extensions as well and if so, modify rules.vc instead.
-# The PROJECT macro is used by rules.vc for generating appropriate
-# macros and rules.
-PROJECT = tcl
+# //==================================================================\\
+# >>[ -> Do not modify below this line. <- ]<<
+# >>[ Please, use the commandline macros to modify how Tcl is built. ]<<
+# >>[ If you need more features, send us a patch for more macros. ]<<
+# \\==================================================================//
-# Default target to build if no target is specified. If unspecified, the
-# rules.vc file will set up "all" as the target.
-DEFAULT_BUILD_TARGET = release
-# We have a custom resource file
-RCFILE = tcl.rc
+###############################################################################
+#==============================================================================
+#------------------------------------------------------------------------------
-# The rules.vc file does much of the hard work in terms of defining
-# the build configuration, macros, output directories etc.
-!include "rules.vc"
+!if !exist("makefile.vc")
+MSG = ^
+You must run this makefile only from the directory it is in.^
+Please `cd` to its location first.
+!error $(MSG)
+!endif
-#
-# The tclsh executable without the embedded libzip. We need this
-# separately from tclsh to have dependency and build order work right.
-# Ditto for the DLL and tcltest
-TCLSHRAW=$(TCLSH:.exe=-raw.exe)
-TCLLIBRAW=$(TCLLIB:.dll=-raw.dll)
+PROJECT = tcl
+!include "rules.vc"
-# Tcl version info based on macros set up by rules.vc
+STUBPREFIX = $(PROJECT)stub
DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)
VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION)
-# The staticpkg option is not longer supported in Tcl 8.7
-# though extensions may still be using it. If specified together
-# with "static", ignore it as that is now the default for
-# static build. For non-static builds, no longer supported
-# now (was permitted in 8.6)
-!if $(TCL_USE_STATIC_PACKAGES)
-!if $(STATIC_BUILD)
-!message *** NOTE: The "staticpkg" option redundant in 8.7.
-!else
-!message *** NOTE: The "staticpkg" option ignored for shared library builds.
-!endif
-!endif
+DDEDOTVERSION = 1.3
+DDEVERSION = $(DDEDOTVERSION:.=)
-!if [nmakehlp -f $(OPTS) "noembed"]
-!message *** Option noembed specified. Tcl script library will not be appended to the binary.
-TCL_EMBED_SCRIPTS = 0
-TCL_TEST_LIBRARY=$(ROOT:\=/)/library
-!else
-!message *** Tcl script library will be appended to the binary.
-TCL_EMBED_SCRIPTS = 1
-TCL_TEST_LIBRARY=
-!endif
+REGDOTVERSION = 1.2
+REGVERSION = $(REGDOTVERSION:.=)
-# We need versions of various core packages to generate appropriate
-# file names during installation.
-!if [echo REM = This file is generated from makefile.vc > versions.vc]
-!endif
-!if [echo PKG_HTTP_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\http\pkgIndex.tcl http >> versions.vc]
-!endif
-!if [echo PKG_OPT_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\opt\pkgIndex.tcl opt >> versions.vc]
-!endif
-!if [echo PKG_COOKIEJAR_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\cookiejar\pkgIndex.tcl cookiejar >> versions.vc]
-!endif
-!if [echo PKG_TCLTEST_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\tcltest\pkgIndex.tcl tcltest >> versions.vc]
-!endif
-!if [echo PKG_MSGCAT_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\msgcat\pkgIndex.tcl msgcat >> versions.vc]
-!endif
-!if [echo PKG_PLATFORM_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform " >> versions.vc]
-!endif
-!if [echo PKG_SHELL_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform::shell" >> versions.vc]
-!endif
-!if [echo PKG_DDE_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\dde\pkgIndex.tcl "dde " >> versions.vc]
-!endif
-!if [echo PKG_REG_VER =\>> versions.vc] \
- && [nmakehlp -V ..\library\registry\pkgIndex.tcl "registry " >> versions.vc]
-!endif
+BINROOT = .
+ROOT = ..
-!include versions.vc
+TCLIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
+TCLLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT)
+TCLLIB = $(OUT_DIR)\$(TCLLIBNAME)
-DDEDOTVERSION = 1.4
-DDEVERSION = $(DDEDOTVERSION:.=)
+TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib
+TCLSTUBLIB = $(OUT_DIR)\$(TCLSTUBLIBNAME)
-REGDOTVERSION = 1.3
-REGVERSION = $(REGDOTVERSION:.=)
+TCLSHNAME = $(PROJECT)sh$(VERSION)$(SUFX).exe
+TCLSH = $(OUT_DIR)\$(TCLSHNAME)
+TCLPIPEDLLNAME = $(PROJECT)pip$(VERSION)$(SUFX:t=).dll
+TCLPIPEDLL = $(OUT_DIR)\$(TCLPIPEDLLNAME)
-TCLREGLIBNAME = $(PROJECT)registry$(REGVERSION)$(SUFX:t=).$(EXT)
+TCLREGLIBNAME = $(PROJECT)reg$(REGVERSION)$(SUFX:t=).$(EXT)
TCLREGLIB = $(OUT_DIR)\$(TCLREGLIBNAME)
TCLDDELIBNAME = $(PROJECT)dde$(DDEVERSION)$(SUFX:t=).$(EXT)
TCLDDELIB = $(OUT_DIR)\$(TCLDDELIBNAME)
-TCLTEST = $(OUT_DIR)\$(PROJECT)test$(VERSION)$(SUFX:t=).exe
-TCLTESTRAW = $(TCLTEST:.exe=-raw.exe)
+TCLTEST = $(OUT_DIR)\$(PROJECT)test.exe
+CAT32 = $(OUT_DIR)\cat32.exe
+
+# Can we run what we build? IX86 runs on all architectures.
+!ifndef TCLSH_NATIVE
+!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)"
+TCLSH_NATIVE = $(TCLSH)
+!else
+!error You must explicitly set TCLSH_NATIVE for cross-compilation
+!endif
+!endif
+
+### Make sure we use backslash only.
+LIB_INSTALL_DIR = $(_INSTALLDIR)\lib
+BIN_INSTALL_DIR = $(_INSTALLDIR)\bin
+DOC_INSTALL_DIR = $(_INSTALLDIR)\doc
+SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\tcl$(DOTVERSION)
+INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include
TCLSHOBJS = \
$(TMP_DIR)\tclAppInit.obj \
+!if $(TCL_USE_STATIC_PACKAGES)
+ $(TMP_DIR)\tclWinReg.obj \
+ $(TMP_DIR)\tclWinDde.obj \
+!endif
$(TMP_DIR)\tclsh.res
TCLTESTOBJS = \
@@ -236,20 +242,18 @@ TCLTESTOBJS = \
$(TMP_DIR)\tclTestProcBodyObj.obj \
$(TMP_DIR)\tclThreadTest.obj \
$(TMP_DIR)\tclWinTest.obj \
-!if !$(STATIC_BUILD)
- $(OUT_DIR)\tommath.lib \
+!if $(TCL_USE_STATIC_PACKAGES)
+ $(TMP_DIR)\tclWinReg.obj \
+ $(TMP_DIR)\tclWinDde.obj \
!endif
- $(TMP_DIR)\testMain.obj \
- $(TMP_DIR)\tcltest.res
+ $(TMP_DIR)\testMain.obj
-COREOBJS = \
+TCLOBJS = \
$(TMP_DIR)\regcomp.obj \
$(TMP_DIR)\regerror.obj \
$(TMP_DIR)\regexec.obj \
$(TMP_DIR)\regfree.obj \
$(TMP_DIR)\tclAlloc.obj \
- $(TMP_DIR)\tclArithSeries.obj \
- $(TMP_DIR)\tclAssembly.obj \
$(TMP_DIR)\tclAsync.obj \
$(TMP_DIR)\tclBasic.obj \
$(TMP_DIR)\tclBinary.obj \
@@ -259,16 +263,12 @@ COREOBJS = \
$(TMP_DIR)\tclCmdIL.obj \
$(TMP_DIR)\tclCmdMZ.obj \
$(TMP_DIR)\tclCompCmds.obj \
- $(TMP_DIR)\tclCompCmdsGR.obj \
- $(TMP_DIR)\tclCompCmdsSZ.obj \
$(TMP_DIR)\tclCompExpr.obj \
$(TMP_DIR)\tclCompile.obj \
$(TMP_DIR)\tclConfig.obj \
$(TMP_DIR)\tclDate.obj \
$(TMP_DIR)\tclDictObj.obj \
- $(TMP_DIR)\tclDisassemble.obj \
$(TMP_DIR)\tclEncoding.obj \
- $(TMP_DIR)\tclEnsemble.obj \
$(TMP_DIR)\tclEnv.obj \
$(TMP_DIR)\tclEvent.obj \
$(TMP_DIR)\tclExecute.obj \
@@ -285,24 +285,14 @@ COREOBJS = \
$(TMP_DIR)\tclIOSock.obj \
$(TMP_DIR)\tclIOUtil.obj \
$(TMP_DIR)\tclIORChan.obj \
- $(TMP_DIR)\tclIORTrans.obj \
$(TMP_DIR)\tclLink.obj \
$(TMP_DIR)\tclListObj.obj \
$(TMP_DIR)\tclLiteral.obj \
$(TMP_DIR)\tclLoad.obj \
- $(TMP_DIR)\tclMainW.obj \
$(TMP_DIR)\tclMain.obj \
$(TMP_DIR)\tclNamesp.obj \
$(TMP_DIR)\tclNotify.obj \
- $(TMP_DIR)\tclOO.obj \
- $(TMP_DIR)\tclOOBasic.obj \
- $(TMP_DIR)\tclOOCall.obj \
- $(TMP_DIR)\tclOODefineCmds.obj \
- $(TMP_DIR)\tclOOInfo.obj \
- $(TMP_DIR)\tclOOMethod.obj \
- $(TMP_DIR)\tclOOStubInit.obj \
$(TMP_DIR)\tclObj.obj \
- $(TMP_DIR)\tclOptimize.obj \
$(TMP_DIR)\tclPanic.obj \
$(TMP_DIR)\tclParse.obj \
$(TMP_DIR)\tclPathObj.obj \
@@ -312,7 +302,6 @@ COREOBJS = \
$(TMP_DIR)\tclPosixStr.obj \
$(TMP_DIR)\tclPreserve.obj \
$(TMP_DIR)\tclProc.obj \
- $(TMP_DIR)\tclProcess.obj \
$(TMP_DIR)\tclRegexp.obj \
$(TMP_DIR)\tclResolve.obj \
$(TMP_DIR)\tclResult.obj \
@@ -320,6 +309,7 @@ COREOBJS = \
$(TMP_DIR)\tclStringObj.obj \
$(TMP_DIR)\tclStrToD.obj \
$(TMP_DIR)\tclStubInit.obj \
+ $(TMP_DIR)\tclStubLib.obj \
$(TMP_DIR)\tclThread.obj \
$(TMP_DIR)\tclThreadAlloc.obj \
$(TMP_DIR)\tclThreadJoin.obj \
@@ -330,28 +320,24 @@ COREOBJS = \
$(TMP_DIR)\tclUtf.obj \
$(TMP_DIR)\tclUtil.obj \
$(TMP_DIR)\tclVar.obj \
- $(TMP_DIR)\tclZipfs.obj \
- $(TMP_DIR)\tclZlib.obj
-
-!if $(STATIC_BUILD)
-ZLIBOBJS = \
- $(TMP_DIR)\adler32.obj \
- $(TMP_DIR)\compress.obj \
- $(TMP_DIR)\crc32.obj \
- $(TMP_DIR)\deflate.obj \
- $(TMP_DIR)\infback.obj \
- $(TMP_DIR)\inffast.obj \
- $(TMP_DIR)\inflate.obj \
- $(TMP_DIR)\inftrees.obj \
- $(TMP_DIR)\trees.obj \
- $(TMP_DIR)\uncompr.obj \
- $(TMP_DIR)\zutil.obj
-!else
-ZLIBOBJS = $(OUT_DIR)\zdll.lib
-!endif
-
-!if $(STATIC_BUILD)
-TOMMATHOBJS = \
+ $(TMP_DIR)\tclWin32Dll.obj \
+ $(TMP_DIR)\tclWinChan.obj \
+ $(TMP_DIR)\tclWinConsole.obj \
+ $(TMP_DIR)\tclWinSerial.obj \
+ $(TMP_DIR)\tclWinError.obj \
+ $(TMP_DIR)\tclWinFCmd.obj \
+ $(TMP_DIR)\tclWinFile.obj \
+ $(TMP_DIR)\tclWinInit.obj \
+ $(TMP_DIR)\tclWinLoad.obj \
+ $(TMP_DIR)\tclWinNotify.obj \
+ $(TMP_DIR)\tclWinPipe.obj \
+ $(TMP_DIR)\tclWinSock.obj \
+ $(TMP_DIR)\tclWinThrd.obj \
+ $(TMP_DIR)\tclWinTime.obj \
+ $(TMP_DIR)\bncore.obj \
+ $(TMP_DIR)\bn_reverse.obj \
+ $(TMP_DIR)\bn_fast_s_mp_mul_digs.obj \
+ $(TMP_DIR)\bn_fast_s_mp_sqr.obj \
$(TMP_DIR)\bn_mp_add.obj \
$(TMP_DIR)\bn_mp_add_d.obj \
$(TMP_DIR)\bn_mp_and.obj \
@@ -370,16 +356,16 @@ TOMMATHOBJS = \
$(TMP_DIR)\bn_mp_div_2d.obj \
$(TMP_DIR)\bn_mp_div_3.obj \
$(TMP_DIR)\bn_mp_exch.obj \
- $(TMP_DIR)\bn_mp_expt_u32.obj \
- $(TMP_DIR)\bn_mp_get_mag_u64.obj \
+ $(TMP_DIR)\bn_mp_expt_d.obj \
$(TMP_DIR)\bn_mp_grow.obj \
$(TMP_DIR)\bn_mp_init.obj \
$(TMP_DIR)\bn_mp_init_copy.obj \
- $(TMP_DIR)\bn_mp_init_i64.obj \
$(TMP_DIR)\bn_mp_init_multi.obj \
$(TMP_DIR)\bn_mp_init_set.obj \
+ $(TMP_DIR)\bn_mp_init_set_int.obj \
$(TMP_DIR)\bn_mp_init_size.obj \
- $(TMP_DIR)\bn_mp_init_u64.obj \
+ $(TMP_DIR)\bn_mp_karatsuba_mul.obj \
+ $(TMP_DIR)\bn_mp_karatsuba_sqr.obj \
$(TMP_DIR)\bn_mp_lshd.obj \
$(TMP_DIR)\bn_mp_mod.obj \
$(TMP_DIR)\bn_mp_mod_2d.obj \
@@ -389,313 +375,256 @@ TOMMATHOBJS = \
$(TMP_DIR)\bn_mp_mul_d.obj \
$(TMP_DIR)\bn_mp_neg.obj \
$(TMP_DIR)\bn_mp_or.obj \
- $(TMP_DIR)\bn_mp_pack.obj \
- $(TMP_DIR)\bn_mp_pack_count.obj \
$(TMP_DIR)\bn_mp_radix_size.obj \
$(TMP_DIR)\bn_mp_radix_smap.obj \
$(TMP_DIR)\bn_mp_read_radix.obj \
$(TMP_DIR)\bn_mp_rshd.obj \
- $(TMP_DIR)\bn_mp_set_i64.obj \
- $(TMP_DIR)\bn_mp_set_u64.obj \
+ $(TMP_DIR)\bn_mp_set.obj \
+ $(TMP_DIR)\bn_mp_set_int.obj \
$(TMP_DIR)\bn_mp_shrink.obj \
$(TMP_DIR)\bn_mp_sqr.obj \
$(TMP_DIR)\bn_mp_sqrt.obj \
$(TMP_DIR)\bn_mp_sub.obj \
$(TMP_DIR)\bn_mp_sub_d.obj \
- $(TMP_DIR)\bn_mp_signed_rsh.obj \
- $(TMP_DIR)\bn_mp_to_ubin.obj \
- $(TMP_DIR)\bn_mp_to_radix.obj \
- $(TMP_DIR)\bn_mp_ubin_size.obj \
- $(TMP_DIR)\bn_mp_unpack.obj \
+ $(TMP_DIR)\bn_mp_to_unsigned_bin.obj \
+ $(TMP_DIR)\bn_mp_to_unsigned_bin_n.obj \
+ $(TMP_DIR)\bn_mp_toom_mul.obj \
+ $(TMP_DIR)\bn_mp_toom_sqr.obj \
+ $(TMP_DIR)\bn_mp_toradix_n.obj \
+ $(TMP_DIR)\bn_mp_unsigned_bin_size.obj \
$(TMP_DIR)\bn_mp_xor.obj \
$(TMP_DIR)\bn_mp_zero.obj \
$(TMP_DIR)\bn_s_mp_add.obj \
- $(TMP_DIR)\bn_s_mp_balance_mul.obj \
- $(TMP_DIR)\bn_s_mp_karatsuba_mul.obj \
- $(TMP_DIR)\bn_s_mp_karatsuba_sqr.obj \
$(TMP_DIR)\bn_s_mp_mul_digs.obj \
- $(TMP_DIR)\bn_s_mp_mul_digs_fast.obj \
- $(TMP_DIR)\bn_s_mp_reverse.obj \
$(TMP_DIR)\bn_s_mp_sqr.obj \
- $(TMP_DIR)\bn_s_mp_sqr_fast.obj \
$(TMP_DIR)\bn_s_mp_sub.obj \
- $(TMP_DIR)\bn_s_mp_toom_sqr.obj \
- $(TMP_DIR)\bn_s_mp_toom_mul.obj
-!else
-TOMMATHOBJS = $(OUT_DIR)\tommath.lib
-!endif
-
-PLATFORMOBJS = \
- $(TMP_DIR)\tclWin32Dll.obj \
- $(TMP_DIR)\tclWinChan.obj \
- $(TMP_DIR)\tclWinConsole.obj \
- $(TMP_DIR)\tclWinError.obj \
- $(TMP_DIR)\tclWinFCmd.obj \
- $(TMP_DIR)\tclWinFile.obj \
- $(TMP_DIR)\tclWinInit.obj \
- $(TMP_DIR)\tclWinLoad.obj \
- $(TMP_DIR)\tclWinNotify.obj \
- $(TMP_DIR)\tclWinPipe.obj \
- $(TMP_DIR)\tclWinSerial.obj \
- $(TMP_DIR)\tclWinSock.obj \
- $(TMP_DIR)\tclWinThrd.obj \
- $(TMP_DIR)\tclWinTime.obj \
-!if $(STATIC_BUILD)
- $(TMP_DIR)\tclWinPanic.obj \
- $(TMP_DIR)\tclWinReg.obj \
- $(TMP_DIR)\tclWinDde.obj \
-!else
+!if !$(STATIC_BUILD)
$(TMP_DIR)\tcl.res
!endif
-TCLOBJS = $(COREOBJS) $(ZLIBOBJS) $(TOMMATHOBJS) $(PLATFORMOBJS)
-
TCLSTUBOBJS = \
- $(TMP_DIR)\tclStubLib.obj \
- $(TMP_DIR)\tclTomMathStubLib.obj \
- $(TMP_DIR)\tclOOStubLib.obj \
- $(TMP_DIR)\tclWinPanic.obj
+ $(TMP_DIR)\tclStubLib.obj
-### The following paths CANNOT have spaces in them as they appear on
-### the left side of implicit rules.
+### The following paths CANNOT have spaces in them.
+COMPATDIR = $(ROOT)\compat
+DOCDIR = $(ROOT)\doc
+GENERICDIR = $(ROOT)\generic
TOMMATHDIR = $(ROOT)\libtommath
-PKGSDIR = $(ROOT)\pkgs
+TOOLSDIR = $(ROOT)\tools
+WINDIR = $(ROOT)\win
-LIBTCLVFS = $(OUT_DIR)\libtcl.vfs
+#---------------------------------------------------------------------
+# Compile flags
+#---------------------------------------------------------------------
-# Additional include and C macro definitions for the implicit rules
-# defined in rules.vc
-PRJ_INCLUDES = -I"$(TOMMATHDIR)"
-PRJ_DEFINES = /DTCL_TOMMATH /DMP_PREC=4 /Dinline=__inline /DHAVE_ZLIB=1 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DMP_FIXED_CUTOFFS
+!if !$(DEBUG)
+!if $(OPTIMIZING)
+### This cranks the optimization level to maximize speed
+cdebug = -O2 $(OPTIMIZATIONS)
+!else
+cdebug =
+!endif
+!if $(SYMBOLS)
+cdebug = $(cdebug) -Zi
+!endif
+!else if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64"
+### Warnings are too many, can't support warnings into errors.
+cdebug = -Zi -Od $(DEBUGFLAGS)
+!else
+cdebug = -Zi -WX $(DEBUGFLAGS)
+!endif
+
+### Declarations common to all compiler options
+cwarn = $(WARNINGS) -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE
+cflags = -nologo -c $(COMPILERFLAGS) $(cwarn) -Fp$(TMP_DIR)^\
+
+!if $(MSVCRT)
+!if $(DEBUG) && !$(UNCHECKED)
+crt = -MDd
+!else
+crt = -MD
+!endif
+!else
+!if $(DEBUG) && !$(UNCHECKED)
+crt = -MTd
+!else
+crt = -MT
+!endif
+!endif
+
+TCL_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" -I"$(TOMMATHDIR)"
+TCL_DEFINES = -DTCL_PIPE_DLL=\"$(TCLPIPEDLLNAME)\" -DTCL_TOMMATH -DMP_PREC=4 -Dinline=__inline
+BASE_CFLAGS = $(cflags) $(cdebug) $(crt) $(TCL_INCLUDES) $(TCL_DEFINES)
+CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE
+TCL_CFLAGS = $(BASE_CFLAGS) $(OPTDEFINES)
+STUB_CFLAGS = $(cflags) $(cdebug) $(OPTDEFINES)
-# Additional Link libraries needed beyond those in rules.vc
-PRJ_LIBS = netapi32.lib user32.lib userenv.lib ws2_32.lib
#---------------------------------------------------------------------
-# TclTest flags
+# Link flags
#---------------------------------------------------------------------
-!if "$(TESTPAT)" != ""
-TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT)
+!if $(DEBUG)
+ldebug = -debug -debugtype:cv
+!else
+ldebug = -release -opt:ref -opt:icf,3
+!if $(SYMBOLS)
+ldebug = $(ldebug) -debug -debugtype:cv
+!endif
!endif
+### Declarations common to all linker options
+lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug)
-#---------------------------------------------------------------------
-# Project specific targets
-# There are 4 primary build configurations to consider from the combination
-# of static/shared and embed/noembed of the library zip. The targets are
-# done in the following order.
-# $(TCLLIB) - this is either the core static .lib or the .dll. The target
-# build does not embed the library zip in the DLL irrespective
-# of the noembed setting. A copy is made as $(TCLLIBRAW)
-# as the $(TCLLIB) binary is potentially modified later.
-# dlls - these are the registry and dde DLL's or static libraries
-# $(TCLSH) - the Tcl shell WITHOUT any embedded zip. This needs $(TCLLIB)
-# to be built first as it links against it. A copy is made
-# as $(TCLSHRAW) as $(TCLSH) binary may be modified later.
-# $(TCLSCRIPTZIP) - the zip file that is to be embedded. Note this also
-# ships separately and needs to be built irrespective of the
-# whether it is embedded or not. All above targets need to
-# be built prior as they are used to build the zip (unlike
-# Unix where the external zip program is used.)
-# core - this virtual target builds the final release ready Tcl
-# library. For shared, embedded builds it appends $(TCLSCRIPTZIP)
-# to the $(TCLLIB). For other build configurations, this
-# is a no-op.
-# shell - this virtual target builds the final release ready tclsh shell.
-# For static, embedded builds it appends $(TCLSCRIPTZIP)
-# to the $(TCLSH). For other build configurations, this
-# is a no-op.
-# release - Everything that builds as part of a release
-#---------------------------------------------------------------------
+!if $(PROFILE)
+lflags = $(lflags) -profile
+!endif
-release: setup libtclzip core dlls shell pkgs
-all: setup libtclzip core dlls shell pkgs
+!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900
+lflags = $(lflags) -nodefaultlib:libucrt.lib
+!endif
-core: setup $(TCLLIB)
-!if $(TCL_EMBED_SCRIPTS) && !$(STATIC_BUILD)
-core: libtclzip
- @$(COPY) /b "$(TCLLIBRAW)"+"$(TCLSCRIPTZIP)" "$(TCLLIB)"
+!if $(ALIGN98_HACK) && !$(STATIC_BUILD)
+### Align sections for PE size savings.
+lflags = $(lflags) -opt:nowin98
+!else if !$(ALIGN98_HACK) && $(STATIC_BUILD)
+### Align sections for speed in loading by choosing the virtual page size.
+lflags = $(lflags) -align:4096
!endif
-shell: setup core $(TCLSH)
-!if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD)
-shell: libtclzip
- @$(COPY) /b "$(TCLSHRAW)"+"$(TCLSCRIPTZIP)" "$(TCLSH)"
+!if $(LOIMPACT)
+lflags = $(lflags) -ws:aggressive
!endif
-dlls: setup $(TCLREGLIB) $(TCLDDELIB) $(OUT_DIR)\zlib1.dll $(OUT_DIR)\libtommath.dll
-libtclzip: $(TCLSCRIPTZIP)
+dlllflags = $(lflags) -dll
+conlflags = $(lflags) -subsystem:console
+guilflags = $(lflags) -subsystem:windows
-tcltest: setup core $(TCLTEST) dlls
-!if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD)
-tcltest: libtclzip
- @$(COPY) /b "$(TCLTESTRAW)"+"$(TCLSCRIPTZIP)" "$(TCLTEST)"
+baselibs = kernel32.lib user32.lib ws2_32.lib
+# Avoid 'unresolved external symbol __security_cookie' errors.
+# c.f. http://support.microsoft.com/?id=894573
+!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64"
+!if $(VCVERSION) > 1399 && $(VCVERSION) < 1500
+baselibs = $(baselibs) bufferoverflowU.lib
+!endif
+!endif
+!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900
+baselibs = $(baselibs) ucrt.lib
!endif
-install: install-binaries install-libraries install-docs install-pkgs
-!if $(SYMBOLS)
-install: install-pdbs
+#---------------------------------------------------------------------
+# TclTest flags
+#---------------------------------------------------------------------
+
+!if "$(TESTPAT)" != ""
+TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT)
!endif
-setup: default-setup
-test: test-core test-pkgs
-test-core: tcltest
- set TCL_LIBRARY=$(TCL_TEST_LIBRARY)
+
+#---------------------------------------------------------------------
+# Project specific targets
+#---------------------------------------------------------------------
+
+release: setup $(TCLSH) $(TCLSTUBLIB) dlls
+core: setup $(TCLLIB) $(TCLSTUBLIB)
+shell: setup $(TCLSH)
+dlls: setup $(TCLPIPEDLL) $(TCLREGLIB) $(TCLDDELIB)
+all: setup $(TCLSH) $(TCLSTUBLIB) dlls $(CAT32)
+tcltest: setup $(TCLTEST) dlls $(CAT32)
+install: install-binaries install-libraries install-docs
+
+test: test-core
+test-core: setup $(TCLTEST) dlls $(CAT32)
+ set TCL_LIBRARY=$(ROOT:\=/)/library
+!if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE"
$(DEBUGGER) $(TCLTEST) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) -loadfile <<
- package ifneeded dde 1.4.5 [list load "$(TCLDDELIB:\=/)"]
- package ifneeded registry 1.3.7 [list load "$(TCLREGLIB:\=/)"]
+ package ifneeded dde 1.3.3 [list load "$(TCLDDELIB:\=/)" dde]
+ package ifneeded registry 1.2.2 [list load "$(TCLREGLIB:\=/)" registry]
+<<
+!else
+ @echo Please wait while the tests are collected...
+ $(TCLTEST) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) -loadfile << > tests.log
+ package ifneeded dde 1.3.3 "$(TCLDDELIB:\=/)" dde]
+ package ifneeded registry 1.2.2 "$(TCLREGLIB:\=/)" registry]
<<
+ type tests.log | more
+!endif
-runtest: setup $(TCLTEST) dlls
- set TCL_LIBRARY=$(TCL_TEST_LIBRARY)
+runtest: setup $(TCLTEST) dlls $(CAT32)
+ set TCL_LIBRARY=$(ROOT:\=/)/library
$(DEBUGGER) $(TCLTEST) $(SCRIPT)
-runshell: setup core shell dlls
- set TCL_LIBRARY=$(TCL_TEST_LIBRARY)
+runshell: setup $(TCLSH) dlls
+ set TCL_LIBRARY=$(ROOT:\=/)/library
$(DEBUGGER) $(TCLSH) $(SCRIPT)
-!if $(STATIC_BUILD)
+setup:
+ @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR)
+ @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR)
+
+!if !$(STATIC_BUILD)
+$(TCLIMPLIB): $(TCLLIB)
+!endif
$(TCLLIB): $(TCLOBJS)
- $(LIBCMD) @<<
+!if $(STATIC_BUILD)
+ $(lib32) -nologo $(LINKERFLAGS) -out:$@ @<<
$**
<<
-
!else
-
-$(TCLLIB): $(TCLOBJS)
- $(DLLCMD) @<<
+ $(link32) $(dlllflags) -base:@$(WINDIR)\coffbase.txt,tcl -out:$@ \
+ $(baselibs) @<<
$**
<<
$(_VC_MANIFEST_EMBED_DLL)
-!if $(TCL_EMBED_SCRIPTS) && !$(STATIC_BUILD)
- $(COPY) $@ $(TCLLIBRAW)
+ -@del $*.exp
!endif
-$(TCLIMPLIB): $(TCLLIB)
-
-!endif # $(STATIC_BUILD)
-
$(TCLSTUBLIB): $(TCLSTUBOBJS)
- $(LIBCMD) -nodefaultlib $(TCLSTUBOBJS)
+ $(lib32) -nologo $(LINKERFLAGS) -nodefaultlib -out:$@ $(TCLSTUBOBJS)
$(TCLSH): $(TCLSHOBJS) $(TCLSTUBLIB) $(TCLIMPLIB)
- $(CONEXECMD) -stack:2300000 $**
- copy $(TMP_DIR)\tclsh.exe.manifest $(TCLSH).manifest
+ $(link32) $(conlflags) -stack:2300000 -out:$@ $(baselibs) $**
$(_VC_MANIFEST_EMBED_EXE)
-!if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD)
- $(COPY) $@ $(TCLSHRAW)
-!endif
-
$(TCLTEST): $(TCLTESTOBJS) $(TCLSTUBLIB) $(TCLIMPLIB)
- $(CONEXECMD) -stack:2300000 $**
- copy $(TMP_DIR)\tclsh.exe.manifest $(TCLTEST).manifest
+ $(link32) $(conlflags) -stack:2300000 -out:$@ $(baselibs) $**
$(_VC_MANIFEST_EMBED_EXE)
-!if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD)
- $(COPY) $@ $(TCLTESTRAW)
-!endif
+
+$(TCLPIPEDLL): $(WINDIR)\stub16.c
+ $(cc32) $(CON_CFLAGS) -Fo$(TMP_DIR)\ $(WINDIR)\stub16.c
+ $(link32) $(conlflags) -out:$@ $(TMP_DIR)\stub16.obj $(baselibs)
+ $(_VC_MANIFEST_EMBED_DLL)
!if $(STATIC_BUILD)
$(TCLDDELIB): $(TMP_DIR)\tclWinDde.obj
- $(LIBCMD) $**
+ $(lib32) -nologo $(LINKERFLAGS) -out:$@ $**
!else
$(TCLDDELIB): $(TMP_DIR)\tclWinDde.obj $(TCLSTUBLIB)
- $(DLLCMD) $**
+ $(link32) $(dlllflags) -base:@$(WINDIR)\coffbase.txt,tcldde -out:$@ \
+ $** $(baselibs)
$(_VC_MANIFEST_EMBED_DLL)
+ -@del $*.exp
+ -@del $*.lib
!endif
!if $(STATIC_BUILD)
$(TCLREGLIB): $(TMP_DIR)\tclWinReg.obj
- $(LIBCMD) $**
+ $(lib32) -nologo $(LINKERFLAGS) -out:$@ $**
!else
$(TCLREGLIB): $(TMP_DIR)\tclWinReg.obj $(TCLSTUBLIB)
- $(DLLCMD) $**
+ $(link32) $(dlllflags) -base:@$(WINDIR)\coffbase.txt,tclreg -out:$@ \
+ $** $(baselibs)
$(_VC_MANIFEST_EMBED_DLL)
+ -@del $*.exp
+ -@del $*.lib
!endif
-!if "$(MACHINE)" == "ARM64"
-$(OUT_DIR)\zlib1.dll: $(COMPATDIR)\zlib\win64-arm\zlib1.dll
- $(COPY) $(COMPATDIR)\zlib\win64-arm\zlib1.dll $(OUT_DIR)\zlib1.dll
-$(OUT_DIR)\zdll.lib: $(COMPATDIR)\zlib\win64-arm\zdll.lib
- $(COPY) $(COMPATDIR)\zlib\win64-arm\zdll.lib $(OUT_DIR)\zdll.lib
-$(OUT_DIR)\libtommath.dll: $(TOMMATHDIR)\win64-arm\libtommath.dll
- $(COPY) $(TOMMATHDIR)\win64-arm\libtommath.dll $(OUT_DIR)\libtommath.dll
-$(OUT_DIR)\tommath.lib: $(TOMMATHDIR)\win64-arm\tommath.lib
- $(COPY) $(TOMMATHDIR)\win64-arm\tommath.lib $(OUT_DIR)\tommath.lib
-!elseif "$(MACHINE)" == "IX86"
-$(OUT_DIR)\zlib1.dll: $(COMPATDIR)\zlib\win32\zlib1.dll
- $(COPY) $(COMPATDIR)\zlib\win32\zlib1.dll $(OUT_DIR)\zlib1.dll
-$(OUT_DIR)\zdll.lib: $(COMPATDIR)\zlib\win32\zdll.lib
- $(COPY) $(COMPATDIR)\zlib\win32\zdll.lib $(OUT_DIR)\zdll.lib
-$(OUT_DIR)\libtommath.dll: $(TOMMATHDIR)\win32\libtommath.dll
- $(COPY) $(TOMMATHDIR)\win32\libtommath.dll $(OUT_DIR)\libtommath.dll
-$(OUT_DIR)\tommath.lib: $(TOMMATHDIR)\win32\tommath.lib
- $(COPY) $(TOMMATHDIR)\win32\tommath.lib $(OUT_DIR)\tommath.lib
-!else
-$(OUT_DIR)\zlib1.dll: $(COMPATDIR)\zlib\win64\zlib1.dll
- $(COPY) $(COMPATDIR)\zlib\win64\zlib1.dll $(OUT_DIR)\zlib1.dll
-$(OUT_DIR)\zdll.lib: $(COMPATDIR)\zlib\win64\zdll.lib
- $(COPY) $(COMPATDIR)\zlib\win64\zdll.lib $(OUT_DIR)\zdll.lib
-$(OUT_DIR)\libtommath.dll: $(TOMMATHDIR)\win64\libtommath.dll
- $(COPY) $(TOMMATHDIR)\win64\libtommath.dll $(OUT_DIR)\libtommath.dll
-$(OUT_DIR)\tommath.lib: $(TOMMATHDIR)\win64\tommath.lib
- $(COPY) $(TOMMATHDIR)\win64\tommath.lib $(OUT_DIR)\tommath.lib
-!endif
-
-$(TCLSCRIPTZIP): $(TCLLIB) $(TCLSH) dlls
- @echo Building Tcl library zip file $(TCLSCRIPTZIP)
- @set TCL_LIBRARY=$(ROOT:\=/)/library
- @if exist "$(LIBTCLVFS)" $(RMDIR) "$(LIBTCLVFS)"
- @$(MKDIR) "$(LIBTCLVFS)"
- @$(CPYDIR) $(LIBDIR) "$(LIBTCLVFS)\tcl_library"
- @move /y "$(LIBTCLVFS)\tcl_library\manifest.txt" "$(LIBTCLVFS)\tcl_library\pkgIndex.tcl" > NUL
-!if $(STATIC_BUILD)
-# Remove the registry and dde directories as the DLLS are still external
- @del "$(LIBTCLVFS)\tcl_library\registry\pkgIndex.tcl"
- @rmdir "$(LIBTCLVFS)\tcl_library\registry"
- @del "$(LIBTCLVFS)\tcl_library\dde\pkgIndex.tcl"
- @rmdir "$(LIBTCLVFS)\tcl_library\dde"
-!else
- @$(COPY) $(TCLDDELIB) "$(LIBTCLVFS)\tcl_library\dde
- @$(COPY) $(TCLREGLIB) "$(LIBTCLVFS)\tcl_library\registry
-!endif
- @echo file delete -force {$@} > "$(OUT_DIR)\zipper.tcl"
- @echo zipfs mkzip {$@} {$(LIBTCLVFS)} {$(LIBTCLVFS)} >> "$(OUT_DIR)\zipper.tcl"
- @cd "$(OUT_DIR)" && $(TCLSH_NATIVE) zipper.tcl
-
-pkgs:
- @for /d %d in ($(PKGSDIR)\*) do \
- @if exist "%~fd\win\makefile.vc" ( \
- pushd "%~fd\win" & \
- $(MAKE) -$(MAKEFLAGS) -f makefile.vc TCLDIR=$(ROOT) &\
- popd \
- )
-
-test-pkgs:
- @for /d %d in ($(PKGSDIR)\*) do \
- @if exist "%~fd\win\makefile.vc" ( \
- pushd "%~fd\win" & \
- $(MAKE) -$(MAKEFLAGS) -f makefile.vc TCLDIR=$(ROOT) test &\
- popd \
- )
-
-install-pkgs:
- @for /d %d in ($(PKGSDIR)\*) do \
- @if exist "%~fd\win\makefile.vc" ( \
- pushd "%~fd\win" & \
- $(MAKE) -$(MAKEFLAGS) -f makefile.vc TCLDIR=$(ROOT) install &\
- popd \
- )
-
-clean-pkgs:
- @for /d %d in ($(PKGSDIR)\*) do \
- @if exist "%~fd\win\makefile.vc" ( \
- pushd "%~fd\win" & \
- $(MAKE) -$(MAKEFLAGS) -f makefile.vc TCLDIR=$(ROOT) clean &\
- popd \
- )
+$(CAT32): $(WINDIR)\cat.c
+ $(cc32) $(CON_CFLAGS) -Fo$(TMP_DIR)\ $?
+ $(link32) $(conlflags) -out:$@ -stack:16384 $(TMP_DIR)\cat.obj \
+ $(baselibs)
+ $(_VC_MANIFEST_EMBED_EXE)
#---------------------------------------------------------------------
# Regenerate the stubs files. [Development use only]
@@ -708,22 +637,33 @@ genstubs:
$(TCLSH) $(TOOLSDIR:\=/)/genStubs.tcl $(GENERICDIR:\=/) \
$(GENERICDIR:\=/)/tcl.decls $(GENERICDIR:\=/)/tclInt.decls \
$(GENERICDIR:\=/)/tclTomMath.decls
- $(TCLSH) $(TOOLSDIR:\=/)/genStubs.tcl $(GENERICDIR:\=/) \
- $(GENERICDIR:\=/)/tclOO.decls
+!endif
+
+
+#----------------------------------------------------------------------
+# The following target generates the file generic/tclTomMath.h.
+# It needs to be run (and the results checked) after updating
+# to a new release of libtommath.
+#----------------------------------------------------------------------
+
+gentommath_h:
+!if !exist($(TCLSH))
+ @echo Build tclsh first!
+!else
+ $(TCLSH) "$(TOOLSDIR:\=/)/fix_tommath_h.tcl" \
+ "$(TOMMATHDIR:\=/)/tommath.h" \
+ > "$(GENERICDIR)\tclTomMath.h"
!endif
#---------------------------------------------------------------------
# Build the Windows HTML help file.
#---------------------------------------------------------------------
-# NOTE: you can define HHC on the command-line to override this.
-# nmake does not set macro values if already set on the command line.
-!if defined(PROCESSOR_ARCHITECTURE) && "$(PROCESSOR_ARCHITECTURE)" == "AMD64"
-HHC="%ProgramFiles(x86)%\HTML Help Workshop\hhc.exe"
-!else
-HHC="%ProgramFiles%\HTML Help Workshop\hhc.exe"
+# NOTE: you can define HHC on the command-line to override this
+!ifndef HHC
+HHC=""%ProgramFiles%\HTML Help Workshop\hhc.exe""
!endif
-HTMLDIR=$(OUT_DIR)\html
+HTMLDIR=$(ROOT)\html
HTMLBASE=TclTk$(VERSION)
HHPFILE=$(HTMLDIR)\$(HTMLBASE).hhp
CHMFILE=$(HTMLDIR)\$(HTMLBASE).chm
@@ -731,51 +671,100 @@ CHMFILE=$(HTMLDIR)\$(HTMLBASE).chm
htmlhelp: chmsetup $(CHMFILE)
$(CHMFILE): $(DOCDIR)\*
- @$(TCLSH) -encoding utf-8 $(TOOLSDIR)\tcltk-man2html.tcl "--htmldir=$(HTMLDIR)"
+ @$(TCLSH) $(TOOLSDIR)\tcltk-man2html.tcl
@echo Compiling HTML help project
- -"$(HHC)" <<$(HHPFILE) >NUL
+ @$(HHC) <<$(HHPFILE) >NUL
[OPTIONS]
Compatibility=1.1 or later
Compiled file=$(HTMLBASE).chm
-Default topic=contents.htm
Display compile progress=no
Error log file=$(HTMLBASE).log
-Full-text search=Yes
Language=0x409 English (United States)
-Title=Tcl/Tk $(DOTVERSION) Help
+Title=Tcl/Tk $(DOT_VERSION) Help
[FILES]
contents.htm
docs.css
-Keywords\*.htm
-TclCmd\*.htm
-TclLib\*.htm
-TkCmd\*.htm
-TkLib\*.htm
-UserCmd\*.htm
+Keywords
+TclCmd
+TclLib
+TkCmd
+TkLib
+UserCmd
<<
chmsetup:
@if not exist $(HTMLDIR)\nul mkdir $(HTMLDIR)
+#-------------------------------------------------------------------------
+# Build the old-style Windows .hlp file
+#-------------------------------------------------------------------------
+
+TCLHLPBASE = $(PROJECT)$(VERSION)
+HELPFILE = $(OUT_DIR)\$(TCLHLPBASE).hlp
+HELPCNT = $(OUT_DIR)\$(TCLHLPBASE).cnt
+DOCTMP_DIR = $(OUT_DIR)\$(PROJECT)_docs
+HELPRTF = $(DOCTMP_DIR)\$(PROJECT).rtf
+MAN2HELP = $(DOCTMP_DIR)\man2help.tcl
+MAN2HELP2 = $(DOCTMP_DIR)\man2help2.tcl
+INDEX = $(DOCTMP_DIR)\index.tcl
+BMP = $(DOCTMP_DIR)\feather.bmp
+BMP_NOPATH = feather.bmp
+MAN2TCL = $(DOCTMP_DIR)\man2tcl.exe
+
+winhelp: docsetup $(HELPFILE)
+
+docsetup:
+ @if not exist $(DOCTMP_DIR)\nul mkdir $(DOCTMP_DIR)
+
+$(MAN2HELP) $(MAN2HELP2) $(INDEX) $(BMP): $(TOOLSDIR)\$$(@F)
+ @$(CPY) $(TOOLSDIR)\$(@F) $(@D)
+
+$(HELPFILE): $(HELPRTF) $(BMP)
+ cd $(DOCTMP_DIR)
+ start /wait hcrtf.exe -x <<$(PROJECT).hpj
+[OPTIONS]
+COMPRESS=12 Hall Zeck
+LCID=0x409 0x0 0x0 ; English (United States)
+TITLE=Tcl/Tk Reference Manual
+BMROOT=.
+CNT=$(@B).cnt
+HLP=$(@B).hlp
+
+[FILES]
+$(PROJECT).rtf
+
+[WINDOWS]
+main="Tcl/Tk Reference Manual",,27648,(r15263976),(r65535)
+
+[CONFIG]
+BrowseButtons()
+CreateButton(1, "Web", ExecFile("http://www.tcl.tk"))
+CreateButton(2, "SF", ExecFile("http://sf.net/projects/tcl"))
+CreateButton(3, "Wiki", ExecFile("http://wiki.tcl.tk"))
+CreateButton(4, "FAQ", ExecFile("http://www.purl.org/NET/Tcl-FAQ/"))
+<<
+ cd $(MAKEDIR)
+ @$(CPY) "$(DOCTMP_DIR)\$(@B).hlp" "$(OUT_DIR)"
+ @$(CPY) "$(DOCTMP_DIR)\$(@B).cnt" "$(OUT_DIR)"
+
+$(MAN2TCL): $(TOOLSDIR)\$$(@B).c
+ $(cc32) $(TCL_CFLAGS) -Fo$(@D)\ $(TOOLSDIR)\$(@B).c
+ $(link32) $(conlflags) -out:$@ -stack:16384 $(@D)\man2tcl.obj
+ $(_VC_MANIFEST_EMBED_EXE)
+
+$(HELPRTF): $(MAN2TCL) $(MAN2HELP) $(MAN2HELP2) $(INDEX) $(DOCDIR)\*
+ $(TCLSH) $(MAN2HELP) -bitmap $(BMP_NOPATH) $(PROJECT) $(VERSION) $(DOCDIR:\=/)
+
install-docs:
!if exist("$(CHMFILE)")
@echo Installing compiled HTML help
@$(CPY) "$(CHMFILE)" "$(DOC_INSTALL_DIR)\"
!endif
-
-# "emacs font-lock highlighting fix
-
-#---------------------------------------------------------------------
-# Generate the tcl.nmake file which contains the options used to build
-# Tcl itself. This is used when building extensions.
-#---------------------------------------------------------------------
-tcl-nmake: $(OUT_DIR)\tcl.nmake
-$(OUT_DIR)\tcl.nmake:
- @type << >$@
-CORE_MACHINE = $(MACHINE)
-CORE_DEBUG = $(DEBUG)
-CORE_USE_THREAD_ALLOC = $(USE_THREAD_ALLOC)
-<<
+!if exist("$(HELPFILE)")
+ @echo Installing Windows help
+ @$(CPY) "$(HELPFILE)" "$(DOC_INSTALL_DIR)\"
+ @$(CPY) "$(HELPCNT)" "$(DOC_INSTALL_DIR)\"
+!endif
#---------------------------------------------------------------------
# Build tclConfig.sh for the TEA build system.
@@ -783,8 +772,7 @@ CORE_USE_THREAD_ALLOC = $(USE_THREAD_ALLOC)
tclConfig: $(OUT_DIR)\tclConfig.sh
-# TBD - is this tclConfig.sh file ever used? The values are incorrect!
-$(OUT_DIR)\tclConfig.sh: $(WIN_DIR)\tclConfig.sh.in
+$(OUT_DIR)\tclConfig.sh: $(WINDIR)\tclConfig.sh.in
@echo Creating tclConfig.sh
@nmakehlp -s << $** >$@
@TCL_DLL_FILE@ $(TCLLIBNAME)
@@ -793,13 +781,15 @@ $(OUT_DIR)\tclConfig.sh: $(WIN_DIR)\tclConfig.sh.in
@TCL_MINOR_VERSION@ $(TCL_MINOR_VERSION)
@TCL_PATCH_LEVEL@ $(TCL_PATCH_LEVEL)
@CC@ $(CC)
-@DEFS@ $(pkgcflags)
+@DEFS@ $(TCL_CFLAGS)
@CFLAGS_DEBUG@ -nologo -c -W3 -YX -Fp$(TMP_DIR)\ -MDd
@CFLAGS_OPTIMIZE@ -nologo -c -W3 -YX -Fp$(TMP_DIR)\ -MD
@LDFLAGS_DEBUG@ -nologo -machine:$(MACHINE) -debug -debugtype:cv
@LDFLAGS_OPTIMIZE@ -nologo -machine:$(MACHINE) -release -opt:ref -opt:icf,3
+@TCL_DBGX@ $(SUFX)
@TCL_LIB_FILE@ $(PROJECT)$(VERSION)$(SUFX).lib
-@LIBS@ $(baselibs) $(PRJ_LIBS)
+@TCL_NEEDS_EXP_FILE@
+@LIBS@ $(baselibs)
@prefix@ $(_INSTALLDIR)
@exec_prefix@ $(BIN_INSTALL_DIR)
@SHLIB_CFLAGS@
@@ -808,26 +798,28 @@ $(OUT_DIR)\tclConfig.sh: $(WIN_DIR)\tclConfig.sh.in
@EXTRA_CFLAGS@ -YX
@SHLIB_LD@ $(link32) $(dlllflags)
@STLIB_LD@ $(lib32) -nologo
-@SHLIB_LD_LIBS@ $(baselibs) $(PRJ_LIBS)
+@SHLIB_LD_LIBS@ $(baselibs)
@SHLIB_SUFFIX@ .dll
@DL_LIBS@
@LDFLAGS@
-@TCL_CC_SEARCH_FLAGS@
@TCL_LD_SEARCH_FLAGS@
@LIBOBJS@
@RANLIB@
-@TCL_LIB_FLAG@ $(PROJECT)$(VERSION)$(SUFX).lib
-@TCL_BUILD_LIB_SPEC@ $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
+@TCL_LIB_FLAG@
+@TCL_BUILD_LIB_SPEC@
@TCL_LIB_SPEC@ $(LIB_INSTALL_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
@TCL_INCLUDE_SPEC@ -I$(INCLUDE_INSTALL_DIR)
+@TCL_LIB_VERSIONS_OK@
@TCL_SRC_DIR@ $(ROOT)
-@TCL_PACKAGE_PATH@ $(LIB_INSTALL_DIR)
+@TCL_PACKAGE_PATH@
@TCL_STUB_LIB_FILE@ $(TCLSTUBLIBNAME)
@TCL_STUB_LIB_FLAG@ $(TCLSTUBLIBNAME)
@TCL_STUB_LIB_SPEC@ -L$(LIB_INSTALL_DIR) $(TCLSTUBLIBNAME)
+@TCL_THREADS@ $(TCL_THREADS)
@TCL_BUILD_STUB_LIB_SPEC@ -L$(OUT_DIR) $(TCLSTUBLIBNAME)
@TCL_BUILD_STUB_LIB_PATH@ $(TCLSTUBLIB)
@TCL_STUB_LIB_PATH@ $(LIB_INSTALL_DIR)\$(TCLSTUBLIBNAME)
+@CFG_TCL_EXPORT_FILE_SUFFIX@ $(VERSION)$(SUFX).lib
@CFG_TCL_SHARED_LIB_SUFFIX@ $(VERSION)$(SUFX).dll
@CFG_TCL_UNSHARED_LIB_SUFFIX@ $(VERSION)$(SUFX).lib
!if $(STATIC_BUILD)
@@ -835,8 +827,6 @@ $(OUT_DIR)\tclConfig.sh: $(WIN_DIR)\tclConfig.sh.in
!else
@TCL_SHARED_BUILD@ 1
!endif
-@TCL_ZLIB_LIB_NAME@ zdll.lib
-@TCL_TOMMATH_LIB_NAME@ tommath.lib
<<
@@ -857,83 +847,56 @@ gendate:
# Special case object file targets
#---------------------------------------------------------------------
-$(TMP_DIR)\testMain.obj: $(WIN_DIR)\tclAppInit.c
- $(cc32) $(appcflags) /DTCL_TEST /DUNICODE /D_UNICODE \
+$(TMP_DIR)\testMain.obj: $(WINDIR)\tclAppInit.c
+ $(cc32) $(TCL_CFLAGS) -DTCL_TEST \
+ -DTCL_USE_STATIC_PACKAGES=$(TCL_USE_STATIC_PACKAGES) \
-Fo$@ $?
-$(TMP_DIR)\tclMainW.obj: $(GENERICDIR)\tclMain.c
- $(cc32) $(pkgcflags) /DUNICODE /D_UNICODE \
- -Fo$@ $?
-
-$(ROOT)\manifest.uuid:
- copy $(WIN_DIR)\gitmanifest.in $(ROOT)\manifest.uuid
- git rev-parse HEAD >>$(ROOT)\manifest.uuid
-
-$(TMP_DIR)\tclUuid.h: $(ROOT)\manifest.uuid
- copy $(WIN_DIR)\tclUuid.h.in+$(ROOT)\manifest.uuid $(TMP_DIR)\tclUuid.h
-
-$(TMP_DIR)\tclEvent.obj: $(GENERICDIR)\tclEvent.c $(TMP_DIR)\tclUuid.h
- $(cc32) $(pkgcflags) -I$(TMP_DIR) \
- -Fo$@ $(GENERICDIR)\tclEvent.c
-
-$(TMP_DIR)\tclTest.obj: $(GENERICDIR)\tclTest.c $(TMP_DIR)\tclUuid.h
- $(cc32) $(appcflags) -I$(TMP_DIR) \
- -Fo$@ $(GENERICDIR)\tclTest.c
+$(TMP_DIR)\tclTest.obj: $(GENERICDIR)\tclTest.c
+ $(cc32) $(TCL_CFLAGS) -Fo$@ $?
$(TMP_DIR)\tclTestObj.obj: $(GENERICDIR)\tclTestObj.c
- $(cc32) $(appcflags) -Fo$@ $?
-
-$(TMP_DIR)\tclWinTest.obj: $(WIN_DIR)\tclWinTest.c
- $(CCAPPCMD) $?
+ $(cc32) $(TCL_CFLAGS) -Fo$@ $?
-$(TMP_DIR)\tclZipfs.obj: $(GENERICDIR)\tclZipfs.c
- $(cc32) $(pkgcflags) \
- -I$(COMPATDIR)\zlib -I$(COMPATDIR)\zlib\contrib\minizip \
- -Fo$@ $?
+$(TMP_DIR)\tclWinTest.obj: $(WINDIR)\tclWinTest.c
+ $(cc32) $(TCL_CFLAGS) -Fo$@ $?
-$(TMP_DIR)\tclZlib.obj: $(GENERICDIR)\tclZlib.c
- $(cc32) $(pkgcflags) -I$(COMPATDIR)\zlib -Fo$@ $?
-
-# Following the lead of the autoconf based make, we define the
-# CFG_RUNTIME_*DIR flags specifically for tclPkgConfig
-# and not as part of the global defines. These are all defined
-# as empty strings because they are intended to represent paths
-# at *runtime*, not build time. This may make sense on Unix systems
-# where end-user does configure and make on the target system. It
-# makes no sense on Windows where binary distributions may be installed
-# anywhere. Storing build time paths as runtime paths is misleading
-# at best and inefficient at worst as the code goes looking for
-# files and directories that do not exist.
-# Note: the same is true for the other CFG_RUNTIME* and CFG_INSTALL*
-# settings as well but they are historical and I do not want to change
-# them.
$(TMP_DIR)\tclPkgConfig.obj: $(GENERICDIR)\tclPkgConfig.c
- $(cc32) $(pkgcflags) \
- /DCFG_INSTALL_LIBDIR="\"$(LIB_INSTALL_DIR:\=\\)\"" \
- /DCFG_INSTALL_BINDIR="\"$(BIN_INSTALL_DIR:\=\\)\"" \
- /DCFG_INSTALL_SCRDIR="\"$(SCRIPT_INSTALL_DIR:\=\\)\"" \
- /DCFG_INSTALL_INCDIR="\"$(INCLUDE_INSTALL_DIR:\=\\)\"" \
- /DCFG_INSTALL_DOCDIR="\"$(DOC_INSTALL_DIR:\=\\)\"" \
- /DCFG_RUNTIME_LIBDIR="\"$(LIB_INSTALL_DIR:\=\\)\"" \
- /DCFG_RUNTIME_BINDIR="\"$(BIN_INSTALL_DIR:\=\\)\"" \
- /DCFG_RUNTIME_SCRDIR="\"$(SCRIPT_INSTALL_DIR:\=\\)\"" \
- /DCFG_RUNTIME_INCDIR="\"$(INCLUDE_INSTALL_DIR:\=\\)\"" \
- /DCFG_RUNTIME_DOCDIR="\"$(DOC_INSTALL_DIR:\=\\)\"" \
- /DCFG_RUNTIME_DLLFILE="\"$(TCL_LIB_FILE)\"" \
+ $(cc32) -DBUILD_tcl $(TCL_CFLAGS) \
+ -DCFG_INSTALL_LIBDIR="\"$(LIB_INSTALL_DIR:\=\\)\"" \
+ -DCFG_INSTALL_BINDIR="\"$(BIN_INSTALL_DIR:\=\\)\"" \
+ -DCFG_INSTALL_SCRDIR="\"$(SCRIPT_INSTALL_DIR:\=\\)\"" \
+ -DCFG_INSTALL_INCDIR="\"$(INCLUDE_INSTALL_DIR:\=\\)\"" \
+ -DCFG_INSTALL_DOCDIR="\"$(DOC_INSTALL_DIR:\=\\)\"" \
+ -DCFG_RUNTIME_LIBDIR="\"$(LIB_INSTALL_DIR:\=\\)\"" \
+ -DCFG_RUNTIME_BINDIR="\"$(BIN_INSTALL_DIR:\=\\)\"" \
+ -DCFG_RUNTIME_SCRDIR="\"$(SCRIPT_INSTALL_DIR:\=\\)\"" \
+ -DCFG_RUNTIME_INCDIR="\"$(INCLUDE_INSTALL_DIR:\=\\)\"" \
+ -DCFG_RUNTIME_DOCDIR="\"$(DOC_INSTALL_DIR:\=\\)\"" \
-Fo$@ $?
-$(TMP_DIR)\tclAppInit.obj: $(WIN_DIR)\tclAppInit.c
- $(cc32) $(appcflags) /DUNICODE /D_UNICODE \
+$(TMP_DIR)\tclAppInit.obj: $(WINDIR)\tclAppInit.c
+ $(cc32) $(TCL_CFLAGS) \
+ -DTCL_USE_STATIC_PACKAGES=$(TCL_USE_STATIC_PACKAGES) \
-Fo$@ $?
### The following objects should be built using the stub interfaces
+### *ALL* extensions need to built with -DTCL_THREADS=1
-$(TMP_DIR)\tclWinReg.obj: $(WIN_DIR)\tclWinReg.c
- $(cc32) $(appcflags) /DUSE_TCL_STUBS -Fo$@ $?
+$(TMP_DIR)\tclWinReg.obj: $(WINDIR)\tclWinReg.c
+!if $(STATIC_BUILD)
+ $(cc32) $(TCL_CFLAGS) -DTCL_THREADS=1 -DSTATIC_BUILD -Fo$@ $?
+!else
+ $(cc32) $(TCL_CFLAGS) -DTCL_THREADS=1 -DUSE_TCL_STUBS -Fo$@ $?
+!endif
-$(TMP_DIR)\tclWinDde.obj: $(WIN_DIR)\tclWinDde.c
- $(cc32) $(appcflags) /DUSE_TCL_STUBS -Fo$@ $?
+$(TMP_DIR)\tclWinDde.obj: $(WINDIR)\tclWinDde.c
+!if $(STATIC_BUILD)
+ $(cc32) $(TCL_CFLAGS) -DTCL_THREADS=1 -DSTATIC_BUILD -Fo$@ $?
+!else
+ $(cc32) $(TCL_CFLAGS) -DTCL_THREADS=1 -DUSE_TCL_STUBS -Fo$@ $?
+!endif
### The following objects are part of the stub library and should not
@@ -941,18 +904,9 @@ $(TMP_DIR)\tclWinDde.obj: $(WIN_DIR)\tclWinDde.c
### specific C run-time.
$(TMP_DIR)\tclStubLib.obj: $(GENERICDIR)\tclStubLib.c
- $(cc32) $(stubscflags) -Fo$@ $?
-
-$(TMP_DIR)\tclTomMathStubLib.obj: $(GENERICDIR)\tclTomMathStubLib.c
- $(cc32) $(stubscflags) -Fo$@ $?
+ $(cc32) $(STUB_CFLAGS) -Zl -DSTATIC_BUILD $(TCL_INCLUDES) -Fo$@ $?
-$(TMP_DIR)\tclOOStubLib.obj: $(GENERICDIR)\tclOOStubLib.c
- $(cc32) $(stubscflags) -Fo$@ $?
-
-$(TMP_DIR)\tclWinPanic.obj: $(WIN_DIR)\tclWinPanic.c
- $(cc32) $(stubscflags) -Fo$@ $?
-
-$(TMP_DIR)\tclsh.exe.manifest: $(WIN_DIR)\tclsh.exe.manifest.in
+$(TMP_DIR)\tclsh.exe.manifest: $(WINDIR)\tclsh.exe.manifest.in
@nmakehlp -s << $** >$@
@MACHINE@ $(MACHINE:IX86=X86)
@TCL_WIN_VERSION@ $(DOTVERSION).0.0
@@ -971,8 +925,8 @@ depend:
@echo Build tclsh first!
!else
$(TCLSH) $(TOOLSDIR:\=/)/mkdepend.tcl -vc32 -out:"$(OUT_DIR)\depend.mk" \
- -passthru:"/DBUILD_tcl $(TCL_INCLUDES) $(PRJ_INCLUDES)" $(GENERICDIR),$$(GENERICDIR) \
- $(COMPATDIR),$$(COMPATDIR) $(TOMMATHDIR),$$(TOMMATHDIR) $(WIN_DIR),$$(WIN_DIR) @<<
+ -passthru:"-DBUILD_tcl $(TCL_INCLUDES)" $(GENERICDIR),$$(GENERICDIR) \
+ $(COMPATDIR),$$(COMPATDIR) $(TOMMATHDIR),$$(TOMMATHDIR) $(WINDIR),$$(WINDIR) @<<
$(TCLOBJS)
<<
!endif
@@ -993,25 +947,41 @@ $(TCLOBJS)
#---------------------------------------------------------------------
-# Implicit rules that are not covered by the common ones defined in
-# rules.vc. A limitation exists with nmake that requires that
-# source directory can not contain spaces in the path. This an
-# absolute.
+# Implicit rules
#---------------------------------------------------------------------
+{$(WINDIR)}.c{$(TMP_DIR)}.obj::
+ $(cc32) $(TCL_CFLAGS) -DBUILD_tcl -Fo$(TMP_DIR)\ @<<
+$<
+<<
+
{$(TOMMATHDIR)}.c{$(TMP_DIR)}.obj::
- $(cc32) $(pkgcflags) -Fo$(TMP_DIR)\ @<<
+ $(cc32) $(TCL_CFLAGS) -DBUILD_tcl -Fo$(TMP_DIR)\ @<<
+$<
+<<
+
+{$(GENERICDIR)}.c{$(TMP_DIR)}.obj::
+ $(cc32) $(TCL_CFLAGS) -DBUILD_tcl -Fo$(TMP_DIR)\ @<<
$<
<<
-{$(COMPATDIR)\zlib}.c{$(TMP_DIR)}.obj::
- $(cc32) $(pkgcflags) -Fo$(TMP_DIR)\ @<<
+{$(COMPATDIR)}.c{$(TMP_DIR)}.obj::
+ $(cc32) $(TCL_CFLAGS) -DBUILD_tcl -Fo$(TMP_DIR)\ @<<
$<
<<
-$(TMP_DIR)\tclsh.res: $(TMP_DIR)\tclsh.exe.manifest $(WIN_DIR)\tclsh.rc
+{$(WINDIR)}.rc{$(TMP_DIR)}.res:
+ $(rc32) -fo $@ -r -i "$(GENERICDIR)" -i "$(TMP_DIR)" \
+ -d DEBUG=$(DEBUG) -d UNCHECKED=$(UNCHECKED) \
+ -d TCL_THREADS=$(TCL_THREADS) \
+ -d STATIC_BUILD=$(STATIC_BUILD) \
+ $<
+
+$(TMP_DIR)\tclsh.res: $(TMP_DIR)\tclsh.exe.manifest
+
+.SUFFIXES:
+.SUFFIXES:.c .rc
-$(TMP_DIR)\tcltest.res: $(TMP_DIR)\tclsh.exe.manifest $(WIN_DIR)\tcltest.rc
#---------------------------------------------------------------------
# Installation.
@@ -1024,35 +994,39 @@ install-binaries:
@$(CPY) "$(TCLLIB)" "$(BIN_INSTALL_DIR)\"
!endif
@$(CPY) "$(TCLIMPLIB)" "$(LIB_INSTALL_DIR)\"
- @$(CPY) "$(OUT_DIR)\zlib1.dll" "$(BIN_INSTALL_DIR)\"
- @$(CPY) "$(OUT_DIR)\libtommath.dll" "$(BIN_INSTALL_DIR)\"
-!if !$(STATIC_BUILD)
- @$(CPY) "$(OUT_DIR)\zdll.lib" "$(LIB_INSTALL_DIR)\"
- @$(CPY) "$(OUT_DIR)\tommath.lib" "$(LIB_INSTALL_DIR)\"
-!endif
!if exist($(TCLSH))
@echo Installing $(TCLSHNAME)
@$(CPY) "$(TCLSH)" "$(BIN_INSTALL_DIR)\"
!endif
+!if exist($(TCLPIPEDLL))
+ @echo Installing $(TCLPIPEDLLNAME)
+ @$(CPY) "$(TCLPIPEDLL)" "$(BIN_INSTALL_DIR)\"
+!endif
@echo Installing $(TCLSTUBLIBNAME)
@$(CPY) "$(TCLSTUBLIB)" "$(LIB_INSTALL_DIR)\"
-install-libraries: tclConfig tcl-nmake install-msgs install-tzdata
- @if not exist "$(LIB_INSTALL_DIR)\nmake" \
- $(MKDIR) "$(LIB_INSTALL_DIR)\nmake"
+#" emacs fix
+
+install-libraries: tclConfig install-msgs install-tzdata
+ @if not exist "$(SCRIPT_INSTALL_DIR)$(NULL)" \
+ $(MKDIR) "$(SCRIPT_INSTALL_DIR)"
+ @if not exist "$(SCRIPT_INSTALL_DIR)\..\tcl8$(NULL)" \
+ $(MKDIR) "$(SCRIPT_INSTALL_DIR)\..\tcl8"
+ @if not exist "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.4$(NULL)" \
+ $(MKDIR) "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.4"
+ @if not exist "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.4\platform$(NULL)" \
+ $(MKDIR) "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.4\platform"
+ @if not exist "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.5$(NULL)" \
+ $(MKDIR) "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.5"
@echo Installing header files
@$(CPY) "$(GENERICDIR)\tcl.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclDecls.h" "$(INCLUDE_INSTALL_DIR)\"
- @$(CPY) "$(GENERICDIR)\tclOO.h" "$(INCLUDE_INSTALL_DIR)\"
- @$(CPY) "$(GENERICDIR)\tclOODecls.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclPlatDecls.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclTomMath.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclTomMathDecls.h" "$(INCLUDE_INSTALL_DIR)\"
- @$(CPY) "$(TOMMATHDIR)\tommath.h" "$(INCLUDE_INSTALL_DIR)\"
-!if !$(TCL_EMBED_SCRIPTS)
+ @$(CPY) "$(TOMMATHDIR)\tommath_class.h" "$(INCLUDE_INSTALL_DIR)\"
+ @$(CPY) "$(TOMMATHDIR)\tommath_superclass.h" "$(INCLUDE_INSTALL_DIR)\"
@echo Installing library files to $(SCRIPT_INSTALL_DIR)
- @if not exist "$(SCRIPT_INSTALL_DIR)" \
- $(MKDIR) "$(SCRIPT_INSTALL_DIR)"
@$(CPY) "$(ROOT)\library\history.tcl" "$(SCRIPT_INSTALL_DIR)\"
@$(CPY) "$(ROOT)\library\init.tcl" "$(SCRIPT_INSTALL_DIR)\"
@$(CPY) "$(ROOT)\library\clock.tcl" "$(SCRIPT_INSTALL_DIR)\"
@@ -1063,95 +1037,65 @@ install-libraries: tclConfig tcl-nmake install-msgs install-tzdata
@$(CPY) "$(ROOT)\library\package.tcl" "$(SCRIPT_INSTALL_DIR)\"
@$(CPY) "$(ROOT)\library\word.tcl" "$(SCRIPT_INSTALL_DIR)\"
@$(CPY) "$(ROOT)\library\auto.tcl" "$(SCRIPT_INSTALL_DIR)\"
-!endif
@$(CPY) "$(OUT_DIR)\tclConfig.sh" "$(LIB_INSTALL_DIR)\"
- @$(CPY) "$(WIN_DIR)\tclooConfig.sh" "$(LIB_INSTALL_DIR)\"
- @$(CPY) "$(TCLSCRIPTZIP)" "$(LIB_INSTALL_DIR)\"
- @$(CPY) "$(WIN_DIR)\rules.vc" "$(LIB_INSTALL_DIR)\nmake\"
- @$(CPY) "$(WIN_DIR)\targets.vc" "$(LIB_INSTALL_DIR)\nmake\"
- @$(CPY) "$(WIN_DIR)\nmakehlp.c" "$(LIB_INSTALL_DIR)\nmake\"
- @$(CPY) "$(WIN_DIR)\x86_64-w64-mingw32-nmakehlp.exe" "$(LIB_INSTALL_DIR)\nmake\"
- @$(CPY) "$(OUT_DIR)\tcl.nmake" "$(LIB_INSTALL_DIR)\nmake\"
-!if !$(TCL_EMBED_SCRIPTS)
- @echo Installing package cookiejar $(PKG_COOKIEJAR_VER)
- @if not exist "$(SCRIPT_INSTALL_DIR)\cookiejar0.2" \
- $(MKDIR) "$(SCRIPT_INSTALL_DIR)\cookiejar0.2"
- @$(CPY) "$(ROOT)\library\cookiejar\*.tcl" \
- "$(SCRIPT_INSTALL_DIR)\cookiejar0.2\"
- @$(CPY) "$(ROOT)\library\cookiejar\*.gz" \
- "$(SCRIPT_INSTALL_DIR)\cookiejar0.2\"
- @echo Installing package opt $(PKG_OPT_VER)
- @if not exist "$(SCRIPT_INSTALL_DIR)\opt0.4" \
- $(MKDIR) "$(SCRIPT_INSTALL_DIR)\opt0.4"
+ @echo Installing library http1.0 directory
+ @$(CPY) "$(ROOT)\library\http1.0\*.tcl" \
+ "$(SCRIPT_INSTALL_DIR)\http1.0\"
+ @echo Installing library opt0.4 directory
@$(CPY) "$(ROOT)\library\opt\*.tcl" \
"$(SCRIPT_INSTALL_DIR)\opt0.4\"
- @if not exist "$(MODULE_INSTALL_DIR)" \
- $(MKDIR) "$(MODULE_INSTALL_DIR)"
@echo Installing package http $(PKG_HTTP_VER) as a Tcl Module
- @if not exist "$(MODULE_INSTALL_DIR)\8.6" \
- $(MKDIR) "$(MODULE_INSTALL_DIR)\8.6"
@$(COPY) "$(ROOT)\library\http\http.tcl" \
- "$(MODULE_INSTALL_DIR)\8.6\http-$(PKG_HTTP_VER).tm"
+ "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.4\http-$(PKG_HTTP_VER).tm"
@echo Installing package msgcat $(PKG_MSGCAT_VER) as a Tcl Module
- @if not exist "$(MODULE_INSTALL_DIR)\8.7" \
- $(MKDIR) "$(MODULE_INSTALL_DIR)\8.7"
@$(COPY) "$(ROOT)\library\msgcat\msgcat.tcl" \
- "$(MODULE_INSTALL_DIR)\8.7\msgcat-$(PKG_MSGCAT_VER).tm"
+ "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.5\msgcat-$(PKG_MSGCAT_VER).tm"
@echo Installing package tcltest $(PKG_TCLTEST_VER) as a Tcl Module
- @if not exist "$(MODULE_INSTALL_DIR)\8.5" \
- $(MKDIR) "$(MODULE_INSTALL_DIR)\8.5"
@$(COPY) "$(ROOT)\library\tcltest\tcltest.tcl" \
- "$(MODULE_INSTALL_DIR)\8.5\tcltest-$(PKG_TCLTEST_VER).tm"
+ "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.5\tcltest-$(PKG_TCLTEST_VER).tm"
@echo Installing package platform $(PKG_PLATFORM_VER) as a Tcl Module
- @if not exist "$(MODULE_INSTALL_DIR)\8.4" \
- $(MKDIR) "$(MODULE_INSTALL_DIR)\8.4"
- @if not exist "$(MODULE_INSTALL_DIR)\8.4\platform" \
- $(MKDIR) "$(MODULE_INSTALL_DIR)\8.4\platform"
@$(COPY) "$(ROOT)\library\platform\platform.tcl" \
- "$(MODULE_INSTALL_DIR)\8.4\platform-$(PKG_PLATFORM_VER).tm"
+ "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.4\platform-$(PKG_PLATFORM_VER).tm"
@echo Installing package platform::shell $(PKG_SHELL_VER) as a Tcl Module
@$(COPY) "$(ROOT)\library\platform\shell.tcl" \
- "$(MODULE_INSTALL_DIR)\8.4\platform\shell-$(PKG_SHELL_VER).tm"
-!endif
+ "$(SCRIPT_INSTALL_DIR)\..\tcl8\8.4\platform\shell-$(PKG_SHELL_VER).tm"
@echo Installing $(TCLDDELIBNAME)
-!if !$(STATIC_BUILD)
+!if $(STATIC_BUILD)
+!if !$(TCL_USE_STATIC_PACKAGES)
+ @$(CPY) "$(TCLDDELIB)" "$(LIB_INSTALL_DIR)\"
+!endif
+!else
@$(CPY) "$(TCLDDELIB)" "$(LIB_INSTALL_DIR)\dde$(DDEDOTVERSION)\"
@$(CPY) "$(ROOT)\library\dde\pkgIndex.tcl" \
"$(LIB_INSTALL_DIR)\dde$(DDEDOTVERSION)\"
!endif
@echo Installing $(TCLREGLIBNAME)
-!if !$(STATIC_BUILD)
- @$(CPY) "$(TCLREGLIB)" "$(LIB_INSTALL_DIR)\registry$(REGDOTVERSION)\"
- @$(CPY) "$(ROOT)\library\registry\pkgIndex.tcl" \
- "$(LIB_INSTALL_DIR)\registry$(REGDOTVERSION)\"
+!if $(STATIC_BUILD)
+!if !$(TCL_USE_STATIC_PACKAGES)
+ @$(CPY) "$(TCLREGLIB)" "$(LIB_INSTALL_DIR)\"
+!endif
+!else
+ @$(CPY) "$(TCLREGLIB)" "$(LIB_INSTALL_DIR)\reg$(REGDOTVERSION)\"
+ @$(CPY) "$(ROOT)\library\reg\pkgIndex.tcl" \
+ "$(LIB_INSTALL_DIR)\reg$(REGDOTVERSION)\"
!endif
-!if !$(TCL_EMBED_SCRIPTS)
@echo Installing encodings
@$(CPY) "$(ROOT)\library\encoding\*.enc" \
"$(SCRIPT_INSTALL_DIR)\encoding\"
-!endif
-# "emacs font-lock highlighting fix
+
+#" emacs fix
install-tzdata:
-!if !$(TCL_EMBED_SCRIPTS)
@echo Installing time zone data
@set TCL_LIBRARY=$(ROOT:\=/)/library
@$(TCLSH_NATIVE) "$(ROOT:\=/)/tools/installData.tcl" \
"$(ROOT:\=/)/library/tzdata" "$(SCRIPT_INSTALL_DIR)/tzdata"
-!endif
install-msgs:
-!if !$(TCL_EMBED_SCRIPTS)
@echo Installing message catalogs
@set TCL_LIBRARY=$(ROOT:\=/)/library
@$(TCLSH_NATIVE) "$(ROOT:\=/)/tools/installData.tcl" \
"$(ROOT:\=/)/library/msgs" "$(SCRIPT_INSTALL_DIR)/msgs"
-!endif
-
-install-pdbs:
- @echo Installing debug symbols
- @$(CPY) "$(OUT_DIR)\*.pdb" "$(BIN_INSTALL_DIR)\"
-# "emacs font-lock highlighting fix
#---------------------------------------------------------------------
# Clean up
@@ -1173,11 +1117,24 @@ tidy:
@echo Removing $(TCLREGLIB) ...
@if exist $(TCLREGLIB) del $(TCLREGLIB)
-clean: default-clean clean-pkgs
-hose: default-hose
+clean:
+ @echo Cleaning $(TMP_DIR)\* ...
+ @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR)
+ @echo Cleaning $(WINDIR)\nmakehlp.obj ...
+ @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj
+ @echo Cleaning $(WINDIR)\nmakehlp.exe ...
+ @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe
+ @echo Cleaning $(WINDIR)\_junk.pch ...
+ @if exist $(WINDIR)\_junk.pch del $(WINDIR)\_junk.pch
+ @echo Cleaning $(WINDIR)\vercl.x ...
+ @if exist $(WINDIR)\vercl.x del $(WINDIR)\vercl.x
+ @echo Cleaning $(WINDIR)\vercl.i ...
+ @if exist $(WINDIR)\vercl.i del $(WINDIR)\vercl.i
+ @echo Cleaning $(WINDIR)\versions.vc ...
+ @if exist $(WINDIR)\versions.vc del $(WINDIR)\versions.vc
+
realclean: hose
-.PHONY:
-# Local Variables:
-# mode: makefile
-# End:
+hose:
+ @echo Hosing $(OUT_DIR)\* ...
+ @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR)
diff --git a/win/nmakehlp.c b/win/nmakehlp.c
index b0799f8..84cf75c 100644
--- a/win/nmakehlp.c
+++ b/win/nmakehlp.c
@@ -4,8 +4,8 @@
*
* This is used to fix limitations within nmake and the environment.
*
- * Copyright (c) 2002 David Gravereaux.
- * Copyright (c) 2006 Pat Thoyts
+ * Copyright (c) 2002 by David Gravereaux.
+ * Copyright (c) 2006 by Pat Thoyts
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -14,11 +14,15 @@
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
-#ifdef _MSC_VER
+#define NO_SHLWAPI_GDI
+#define NO_SHLWAPI_STREAM
+#define NO_SHLWAPI_REG
+#include <shlwapi.h>
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "kernel32.lib")
-#endif
+#pragma comment (lib, "shlwapi.lib")
#include <stdio.h>
+#include <math.h>
/*
* This library is required for x64 builds with _some_ versions of MSVC
@@ -30,19 +34,19 @@
#endif
/* ISO hack for dumb VC++ */
-#if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1900
+#ifdef _MSC_VER
#define snprintf _snprintf
#endif
+
/* protos */
static int CheckForCompilerFeature(const char *option);
-static int CheckForLinkerFeature(char **options, int count);
+static int CheckForLinkerFeature(const char *option);
static int IsIn(const char *string, const char *substring);
static int SubstituteFile(const char *substs, const char *filename);
static int QualifyPath(const char *path);
-static int LocateDependency(const char *keyfile);
static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
static DWORD WINAPI ReadFromPipe(LPVOID args);
@@ -55,8 +59,8 @@ typedef struct {
char buffer[STATICBUFFERSIZE];
} pipeinfo;
-pipeinfo Out = {INVALID_HANDLE_VALUE, ""};
-pipeinfo Err = {INVALID_HANDLE_VALUE, ""};
+pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'};
+pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'};
/*
* exitcodes: 0 == no, 1 == yes, 2 == error
@@ -70,7 +74,6 @@ main(
char msg[300];
DWORD dwWritten;
int chars;
- const char *s;
/*
* Make sure children (cl.exe and link.exe) are kept quiet.
@@ -99,16 +102,16 @@ main(
}
return CheckForCompilerFeature(argv[2]);
case 'l':
- if (argc < 3) {
+ if (argc != 3) {
chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -l <linker option> ?<mandatory option> ...?\n"
+ "usage: %s -l <linker option>\n"
"Tests for whether link.exe supports an option\n"
"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
&dwWritten, NULL);
return 2;
}
- return CheckForLinkerFeature(&argv[2], argc-2);
+ return CheckForLinkerFeature(argv[2]);
case 'f':
if (argc == 2) {
chars = snprintf(msg, sizeof(msg) - 1,
@@ -150,13 +153,8 @@ main(
&dwWritten, NULL);
return 0;
}
- s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0');
- if (s && *s) {
- printf("%s\n", s);
- return 0;
- } else
- return 1; /* Version not found. Return non-0 exit code */
-
+ printf("%s\n", GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0'));
+ return 0;
case 'Q':
if (argc != 3) {
chars = snprintf(msg, sizeof(msg) - 1,
@@ -168,18 +166,6 @@ main(
return 2;
}
return QualifyPath(argv[2]);
-
- case 'L':
- if (argc != 3) {
- chars = snprintf(msg, sizeof(msg) - 1,
- "usage: %s -L keypath\n"
- "Emit the fully qualified path of directory containing keypath\n"
- "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]);
- WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
- &dwWritten, NULL);
- return 2;
- }
- return LocateDependency(argv[2]);
}
}
chars = snprintf(msg, sizeof(msg) - 1,
@@ -206,25 +192,25 @@ CheckForCompilerFeature(
hProcess = GetCurrentProcess();
- memset(&pi, 0, sizeof(PROCESS_INFORMATION));
- memset(&si, 0, sizeof(STARTUPINFO));
+ ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+ ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = INVALID_HANDLE_VALUE;
- memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
+ ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
/*
- * Create a non-inheritable pipe.
+ * Create a non-inheritible pipe.
*/
CreatePipe(&Out.pipe, &h, &sa, 0);
/*
- * Dupe the write side, make it inheritable, and close the original.
+ * Dupe the write side, make it inheritible, and close the original.
*/
DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
@@ -271,10 +257,10 @@ CheckForCompilerFeature(
if (!ok) {
DWORD err = GetLastError();
int chars = snprintf(msg, sizeof(msg) - 1,
- "Tried to launch: \"%s\", but got error [%lu]: ", cmdline, err);
+ "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
- FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
+ FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
(300-chars), 0);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
return 2;
@@ -327,8 +313,7 @@ CheckForCompilerFeature(
static int
CheckForLinkerFeature(
- char **options,
- int count)
+ const char *option)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
@@ -337,18 +322,17 @@ CheckForLinkerFeature(
char msg[300];
BOOL ok;
HANDLE hProcess, h, pipeThreads[2];
- int i;
- char cmdline[255];
+ char cmdline[100];
hProcess = GetCurrentProcess();
- memset(&pi, 0, sizeof(PROCESS_INFORMATION));
- memset(&si, 0, sizeof(STARTUPINFO));
+ ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+ ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = INVALID_HANDLE_VALUE;
- memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
+ ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
@@ -360,7 +344,7 @@ CheckForLinkerFeature(
CreatePipe(&Out.pipe, &h, &sa, 0);
/*
- * Dupe the write side, make it inheritable, and close the original.
+ * Dupe the write side, make it inheritible, and close the original.
*/
DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
@@ -384,11 +368,7 @@ CheckForLinkerFeature(
* Append our option for testing.
*/
- for (i = 0; i < count; i++) {
- lstrcat(cmdline, " \"");
- lstrcat(cmdline, options[i]);
- lstrcat(cmdline, "\"");
- }
+ lstrcat(cmdline, option);
ok = CreateProcess(
NULL, /* Module name. */
@@ -405,10 +385,10 @@ CheckForLinkerFeature(
if (!ok) {
DWORD err = GetLastError();
int chars = snprintf(msg, sizeof(msg) - 1,
- "Tried to launch: \"%s\", but got error [%lu]: ", cmdline, err);
+ "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
- FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
+ FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
(300-chars), 0);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
return 2;
@@ -453,9 +433,7 @@ CheckForLinkerFeature(
return !(strstr(Out.buffer, "LNK1117") != NULL ||
strstr(Err.buffer, "LNK1117") != NULL ||
strstr(Out.buffer, "LNK4044") != NULL ||
- strstr(Err.buffer, "LNK4044") != NULL ||
- strstr(Out.buffer, "LNK4224") != NULL ||
- strstr(Err.buffer, "LNK4224") != NULL);
+ strstr(Err.buffer, "LNK4044") != NULL);
}
static DWORD WINAPI
@@ -504,6 +482,7 @@ GetVersionFromFile(
const char *match,
int numdots)
{
+ size_t cbBuffer = 100;
static char szBuffer[100];
char *szResult = NULL;
FILE *fp = fopen(filename, "rt");
@@ -513,7 +492,7 @@ GetVersionFromFile(
* Read data until we see our match string.
*/
- while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
+ while (fgets(szBuffer, cbBuffer, fp) != NULL) {
LPSTR p, q;
p = strstr(szBuffer, match);
@@ -523,7 +502,7 @@ GetVersionFromFile(
*/
p += strlen(match);
- while (*p && !isdigit((unsigned char)*p)) {
+ while (*p && !isdigit(*p)) {
++p;
}
@@ -532,13 +511,14 @@ GetVersionFromFile(
*/
q = p;
- while (*q && (strchr("0123456789.ab", *q)) && (((!strchr(".ab", *q)
- && !strchr("ab", q[-1])) || --numdots))) {
+ while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q)
+ && (!strchr("ab", q[-1])) || --numdots))) {
++q;
}
- *q = 0;
- szResult = p;
+ memcpy(szBuffer, p, q - p);
+ szBuffer[q-p] = 0;
+ szResult = szBuffer;
break;
}
}
@@ -561,7 +541,7 @@ typedef struct list_item_t {
static list_item_t *
list_insert(list_item_t **listPtrPtr, const char *key, const char *value)
{
- list_item_t *itemPtr = (list_item_t *)malloc(sizeof(list_item_t));
+ list_item_t *itemPtr = malloc(sizeof(list_item_t));
if (itemPtr) {
itemPtr->key = strdup(key);
itemPtr->value = strdup(value);
@@ -592,7 +572,7 @@ list_free(list_item_t **listPtrPtr)
* SubstituteFile --
* As windows doesn't provide anything useful like sed and it's unreliable
* to use the tclsh you are building against (consider x-platform builds -
- * e.g. compiling AMD64 target from IX86) we provide a simple substitution
+ * eg compiling AMD64 target from IX86) we provide a simple substitution
* option here to handle autoconf style substitutions.
* The substitution file is whitespace and line delimited. The file should
* consist of lines matching the regular expression:
@@ -610,7 +590,9 @@ SubstituteFile(
const char *substitutions,
const char *filename)
{
+ size_t cbBuffer = 1024;
static char szBuffer[1024], szCopy[1024];
+ char *szResult = NULL;
list_item_t *substPtr = NULL;
FILE *fp, *sp;
@@ -618,12 +600,12 @@ SubstituteFile(
if (fp != NULL) {
/*
- * Build a list of substitutions from the first filename
+ * Build a list of substutitions from the first filename
*/
sp = fopen(substitutions, "rt");
if (sp != NULL) {
- while (fgets(szBuffer, sizeof(szBuffer), sp) != NULL) {
+ while (fgets(szBuffer, cbBuffer, sp) != NULL) {
unsigned char *ks, *ke, *vs, *ve;
ks = (unsigned char*)szBuffer;
while (ks && *ks && isspace(*ks)) ++ks;
@@ -640,7 +622,7 @@ SubstituteFile(
}
/* debug: dump the list */
-#ifndef NDEBUG
+#ifdef _DEBUG
{
int n = 0;
list_item_t *p = NULL;
@@ -654,7 +636,7 @@ SubstituteFile(
* Run the substitutions over each line of the input
*/
- while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
+ while (fgets(szBuffer, cbBuffer, fp) != NULL) {
list_item_t *p = NULL;
for (p = substPtr; p != NULL; p = p->nextPtr) {
char *m = strstr(szBuffer, p->key);
@@ -671,7 +653,7 @@ SubstituteFile(
memcpy(szBuffer, szCopy, sizeof(szCopy));
}
}
- printf("%s", szBuffer);
+ printf(szBuffer);
}
list_free(&substPtr);
@@ -680,17 +662,6 @@ SubstituteFile(
return 0;
}
-BOOL FileExists(LPCTSTR szPath)
-{
-#ifndef INVALID_FILE_ATTRIBUTES
- #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
-#endif
- DWORD pathAttr = GetFileAttributes(szPath);
- return (pathAttr != INVALID_FILE_ATTRIBUTES &&
- !(pathAttr & FILE_ATTRIBUTE_DIRECTORY));
-}
-
-
/*
* QualifyPath --
*
@@ -704,109 +675,18 @@ QualifyPath(
const char *szPath)
{
char szCwd[MAX_PATH + 1];
-
- GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL);
+ char szTmp[MAX_PATH + 1];
+ char *p;
+ GetCurrentDirectory(MAX_PATH, szCwd);
+ while ((p = strchr(szPath, '/')) && *p)
+ *p = '\\';
+ PathCombine(szTmp, szCwd, szPath);
+ PathCanonicalize(szCwd, szTmp);
printf("%s\n", szCwd);
return 0;
}
/*
- * Implements LocateDependency for a single directory. See that command
- * for an explanation.
- * Returns 0 if found after printing the directory.
- * Returns 1 if not found but no errors.
- * Returns 2 on any kind of error
- * Basically, these are used as exit codes for the process.
- */
-static int LocateDependencyHelper(const char *dir, const char *keypath)
-{
- HANDLE hSearch;
- char path[MAX_PATH+1];
- size_t dirlen;
- int keylen, ret;
- WIN32_FIND_DATA finfo;
-
- if (dir == NULL || keypath == NULL) {
- return 2; /* Have no real error reporting mechanism into nmake */
- }
- dirlen = strlen(dir);
- if (dirlen > sizeof(path) - 3) {
- return 2;
- }
- strncpy(path, dir, dirlen);
- strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */
- keylen = strlen(keypath);
-
-#if 0 /* This function is not available in Visual C++ 6 */
- /*
- * Use numerics 0 -> FindExInfoStandard,
- * 1 -> FindExSearchLimitToDirectories,
- * as these are not defined in Visual C++ 6
- */
- hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
-#else
- hSearch = FindFirstFile(path, &finfo);
-#endif
- if (hSearch == INVALID_HANDLE_VALUE)
- return 1; /* Not found */
-
- /* Loop through all subdirs checking if the keypath is under there */
- ret = 1; /* Assume not found */
- do {
- int sublen;
- /*
- * We need to check it is a directory despite the
- * FindExSearchLimitToDirectories in the above call. See SDK docs
- */
- if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
- continue;
- sublen = strlen(finfo.cFileName);
- if ((dirlen+1+sublen+1+keylen+1) > sizeof(path))
- continue; /* Path does not fit, assume not matched */
- strncpy(path+dirlen+1, finfo.cFileName, sublen);
- path[dirlen+1+sublen] = '\\';
- strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
- if (FileExists(path)) {
- /* Found a match, print to stdout */
- path[dirlen+1+sublen] = '\0';
- QualifyPath(path);
- ret = 0;
- break;
- }
- } while (FindNextFile(hSearch, &finfo));
- FindClose(hSearch);
- return ret;
-}
-
-/*
- * LocateDependency --
- *
- * Locates a dependency for a package.
- * keypath - a relative path within the package directory
- * that is used to confirm it is the correct directory.
- * The search path for the package directory is currently only
- * the parent and grandparent of the current working directory.
- * If found, the command prints
- * name_DIRPATH=<full path of located directory>
- * and returns 0. If not found, does not print anything and returns 1.
- */
-static int LocateDependency(const char *keypath)
-{
- size_t i;
- int ret;
- static const char *paths[] = {"..", "..\\..", "..\\..\\.."};
-
- for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) {
- ret = LocateDependencyHelper(paths[i], keypath);
- if (ret == 0) {
- return ret;
- }
- }
- return ret;
-}
-
-
-/*
* Local variables:
* mode: c
* c-basic-offset: 4
diff --git a/win/rules-ext.vc b/win/rules-ext.vc
deleted file mode 100644
index 6d31a03..0000000
--- a/win/rules-ext.vc
+++ /dev/null
@@ -1,123 +0,0 @@
-# This file should only be included in makefiles for Tcl extensions,
-# NOT in the makefile for Tcl itself.
-
-!ifndef _RULES_EXT_VC
-
-# We need to run from the directory the parent makefile is located in.
-# nmake does not tell us what makefile was used to invoke it so parent
-# makefile has to set the MAKEFILEVC macro or we just make a guess and
-# warn if we think that is not the case.
-!if "$(MAKEFILEVC)" == ""
-
-!if exist("$(PROJECT).vc")
-MAKEFILEVC = $(PROJECT).vc
-!elseif exist("makefile.vc")
-MAKEFILEVC = makefile.vc
-!endif
-!endif # "$(MAKEFILEVC)" == ""
-
-!if !exist("$(MAKEFILEVC)")
-MSG = ^
-You must run nmake from the directory containing the project makefile.^
-If you are doing that and getting this message, set the MAKEFILEVC^
-macro to the name of the project makefile.
-!message WARNING: $(MSG)
-!endif
-
-!if "$(PROJECT)" == "tcl"
-!error The rules-ext.vc file is not intended for Tcl itself.
-!endif
-
-# We extract version numbers using the nmakehlp program. For now use
-# the local copy of nmakehlp. Once we locate Tcl, we will use that
-# one if it is newer.
-!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)"
-!if [$(CC) -nologo -DNDEBUG "nmakehlp.c" -link -subsystem:console > nul]
-!endif
-!else
-!if [copy x86_64-w64-mingw32-nmakehlp.exe nmakehlp.exe >NUL]
-!endif
-!endif
-
-# First locate the Tcl directory that we are working with.
-!if "$(TCLDIR)" != ""
-
-_RULESDIR = $(TCLDIR:/=\)
-
-!else
-
-# If an installation path is specified, that is also the Tcl directory.
-# Also Tk never builds against an installed Tcl, it needs Tcl sources
-!if defined(INSTALLDIR) && "$(PROJECT)" != "tk"
-_RULESDIR=$(INSTALLDIR:/=\)
-!else
-# Locate Tcl sources
-!if [echo _RULESDIR = \> nmakehlp.out] \
- || [nmakehlp -L generic\tcl.h >> nmakehlp.out]
-_RULESDIR = ..\..\tcl
-!else
-!include nmakehlp.out
-!endif
-
-!endif # defined(INSTALLDIR)....
-
-!endif # ifndef TCLDIR
-
-# Now look for the targets.vc file under the Tcl root. Note we check this
-# file and not rules.vc because the latter also exists on older systems.
-!if exist("$(_RULESDIR)\lib\nmake\targets.vc") # Building against installed Tcl
-_RULESDIR = $(_RULESDIR)\lib\nmake
-!elseif exist("$(_RULESDIR)\win\targets.vc") # Building against Tcl sources
-_RULESDIR = $(_RULESDIR)\win
-!else
-# If we have not located Tcl's targets file, most likely we are compiling
-# against an older version of Tcl and so must use our own support files.
-_RULESDIR = .
-!endif
-
-!if "$(_RULESDIR)" != "."
-# Potentially using Tcl's support files. If this extension has its own
-# nmake support files, need to compare the versions and pick newer.
-
-!if exist("rules.vc") # The extension has its own copy
-
-!if [echo TCL_RULES_MAJOR = \> versions.vc] \
- && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MAJOR >> versions.vc]
-!endif
-!if [echo TCL_RULES_MINOR = \>> versions.vc] \
- && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MINOR >> versions.vc]
-!endif
-
-!if [echo OUR_RULES_MAJOR = \>> versions.vc] \
- && [nmakehlp -V "rules.vc" RULES_VERSION_MAJOR >> versions.vc]
-!endif
-!if [echo OUR_RULES_MINOR = \>> versions.vc] \
- && [nmakehlp -V "rules.vc" RULES_VERSION_MINOR >> versions.vc]
-!endif
-!include versions.vc
-# We have a newer version of the support files, use them
-!if ($(TCL_RULES_MAJOR) != $(OUR_RULES_MAJOR)) || ($(TCL_RULES_MINOR) < $(OUR_RULES_MINOR))
-_RULESDIR = .
-!endif
-
-!endif # if exist("rules.vc")
-
-!endif # if $(_RULESDIR) != "."
-
-# Let rules.vc know what copy of nmakehlp.c to use.
-NMAKEHLPC = $(_RULESDIR)\nmakehlp.c
-
-# Get rid of our internal defines before calling rules.vc
-!undef TCL_RULES_MAJOR
-!undef TCL_RULES_MINOR
-!undef OUR_RULES_MAJOR
-!undef OUR_RULES_MINOR
-
-!if exist("$(_RULESDIR)\rules.vc")
-!message *** Using $(_RULESDIR)\rules.vc
-!include "$(_RULESDIR)\rules.vc"
-!else
-!error *** Could not locate rules.vc in $(_RULESDIR)
-!endif
-
-!endif # _RULES_EXT_VC \ No newline at end of file
diff --git a/win/rules.vc b/win/rules.vc
index 143ea9e..78a167a 100644
--- a/win/rules.vc
+++ b/win/rules.vc
@@ -1,431 +1,60 @@
-#------------------------------------------------------------- -*- makefile -*-
+#------------------------------------------------------------------------------
# rules.vc --
#
-# Part of the nmake based build system for Tcl and its extensions.
-# This file does all the hard work in terms of parsing build options,
-# compiler switches, defining common targets and macros. The Tcl makefile
-# directly includes this. Extensions include it via "rules-ext.vc".
-#
-# See TIP 477 (https://core.tcl-lang.org/tips/doc/main/tip/477.md) for
-# detailed documentation.
+# Microsoft Visual C++ makefile include for decoding the commandline
+# macros. This file does not need editing to build Tcl.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# Copyright (c) 2001-2003 David Gravereaux.
# Copyright (c) 2003-2008 Patrick Thoyts
-# Copyright (c) 2017 Ashok P. Nadkarni
#------------------------------------------------------------------------------
!ifndef _RULES_VC
_RULES_VC = 1
-# The following macros define the version of the rules.vc nmake build system
-# For modifications that are not backward-compatible, you *must* change
-# the major version.
-RULES_VERSION_MAJOR = 1
-RULES_VERSION_MINOR = 11
-
-# The PROJECT macro must be defined by parent makefile.
-!if "$(PROJECT)" == ""
-!error *** Error: Macro PROJECT not defined! Please define it before including rules.vc
-!endif
-
-!if "$(PRJ_PACKAGE_TCLNAME)" == ""
-PRJ_PACKAGE_TCLNAME = $(PROJECT)
-!endif
-
-# Also special case Tcl and Tk to save some typing later
-DOING_TCL = 0
-DOING_TK = 0
-!if "$(PROJECT)" == "tcl"
-DOING_TCL = 1
-!elseif "$(PROJECT)" == "tk"
-DOING_TK = 1
-!endif
-
-!ifndef NEED_TK
-# Backwards compatibility
-!ifdef PROJECT_REQUIRES_TK
-NEED_TK = $(PROJECT_REQUIRES_TK)
-!else
-NEED_TK = 0
-!endif
-!endif
-
-!ifndef NEED_TCL_SOURCE
-NEED_TCL_SOURCE = 0
-!endif
+cc32 = $(CC) # built-in default.
+link32 = link
+lib32 = lib
+rc32 = $(RC) # built-in default.
-!ifdef NEED_TK_SOURCE
-!if $(NEED_TK_SOURCE)
-NEED_TK = 1
-!endif
+!ifndef INSTALLDIR
+### Assume the normal default.
+_INSTALLDIR = C:\Program Files\Tcl
!else
-NEED_TK_SOURCE = 0
-!endif
-
-################################################################
-# Nmake is a pretty weak environment in syntax and capabilities
-# so this file is necessarily verbose. It's broken down into
-# the following parts.
-#
-# 0. Sanity check that compiler environment is set up and initialize
-# any built-in settings from the parent makefile
-# 1. First define the external tools used for compiling, copying etc.
-# as this is independent of everything else.
-# 2. Figure out our build structure in terms of the directory, whether
-# we are building Tcl or an extension, etc.
-# 3. Determine the compiler and linker versions
-# 4. Build the nmakehlp helper application
-# 5. Determine the supported compiler options and features
-# 6. Extract Tcl, Tk, and possibly extensions, version numbers from the
-# headers
-# 7. Parse the OPTS macro value for user-specified build configuration
-# 8. Parse the STATS macro value for statistics instrumentation
-# 9. Parse the CHECKS macro for additional compilation checks
-# 10. Based on this selected configuration, construct the output
-# directory and file paths
-# 11. Construct the paths where the package is to be installed
-# 12. Set up the actual options passed to compiler and linker based
-# on the information gathered above.
-# 13. Define some standard build targets and implicit rules. These may
-# be optionally disabled by the parent makefile.
-# 14. (For extensions only.) Compare the configuration of the target
-# Tcl and the extensions and warn against discrepancies.
-#
-# One final note about the macro names used. They are as they are
-# for historical reasons. We would like legacy extensions to
-# continue to work with this make include file so be wary of
-# changing them for consistency or clarity.
-
-# 0. Sanity check compiler environment
-
-# Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or
-# VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir)
-
-!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR)
-MSG = ^
-Visual C++ compiler environment not initialized.
-!error $(MSG)
-!endif
-
-# We need to run from the directory the parent makefile is located in.
-# nmake does not tell us what makefile was used to invoke it so parent
-# makefile has to set the MAKEFILEVC macro or we just make a guess and
-# warn if we think that is not the case.
-!if "$(MAKEFILEVC)" == ""
-
-!if exist("$(PROJECT).vc")
-MAKEFILEVC = $(PROJECT).vc
-!elseif exist("makefile.vc")
-MAKEFILEVC = makefile.vc
-!endif
-!endif # "$(MAKEFILEVC)" == ""
-
-!if !exist("$(MAKEFILEVC)")
-MSG = ^
-You must run nmake from the directory containing the project makefile.^
-If you are doing that and getting this message, set the MAKEFILEVC^
-macro to the name of the project makefile.
-!message WARNING: $(MSG)
+### Fix the path separators.
+_INSTALLDIR = $(INSTALLDIR:/=\)
!endif
-
-################################################################
-# 1. Define external programs being used
-
#----------------------------------------------------------
# Set the proper copy method to avoid overwrite questions
# to the user when copying files and selecting the right
# "delete all" method.
#----------------------------------------------------------
+!if "$(OS)" == "Windows_NT"
RMDIR = rmdir /S /Q
+ERRNULL = 2>NUL
+!if ![ver | find "4.0" > nul]
+CPY = echo y | xcopy /i >NUL
+COPY = copy >NUL
+!else
CPY = xcopy /i /y >NUL
-CPYDIR = xcopy /e /i /y >NUL
COPY = copy /y >NUL
-MKDIR = mkdir
-
-######################################################################
-# 2. Figure out our build environment in terms of what we're building.
-#
-# (a) Tcl itself
-# (b) Tk
-# (c) a Tcl extension using libraries/includes from an *installed* Tcl
-# (d) a Tcl extension using libraries/includes from Tcl source directory
-#
-# This last is needed because some extensions still need
-# some Tcl interfaces that are not publicly exposed.
-#
-# The fragment will set the following macros:
-# ROOT - root of this module sources
-# COMPATDIR - source directory that holds compatibility sources
-# DOCDIR - source directory containing documentation files
-# GENERICDIR - platform-independent source directory
-# WIN_DIR - Windows-specific source directory
-# TESTDIR - directory containing test files
-# TOOLSDIR - directory containing build tools
-# _TCLDIR - root of the Tcl installation OR the Tcl sources. Not set
-# when building Tcl itself.
-# _INSTALLDIR - native form of the installation path. For Tcl
-# this will be the root of the Tcl installation. For extensions
-# this will be the lib directory under the root.
-# TCLINSTALL - set to 1 if _TCLDIR refers to
-# headers and libraries from an installed Tcl, and 0 if built against
-# Tcl sources. Not set when building Tcl itself. Yes, not very well
-# named.
-# _TCL_H - native path to the tcl.h file
-#
-# If Tk is involved, also sets the following
-# _TKDIR - native form Tk installation OR Tk source. Not set if building
-# Tk itself.
-# TKINSTALL - set 1 if _TKDIR refers to installed Tk and 0 if Tk sources
-# _TK_H - native path to the tk.h file
-
-# Root directory for sources and assumed subdirectories
-ROOT = $(MAKEDIR)\..
-# The following paths CANNOT have spaces in them as they appear on the
-# left side of implicit rules.
-!ifndef COMPATDIR
-COMPATDIR = $(ROOT)\compat
-!endif
-!ifndef DOCDIR
-DOCDIR = $(ROOT)\doc
-!endif
-!ifndef GENERICDIR
-GENERICDIR = $(ROOT)\generic
-!endif
-!ifndef TOOLSDIR
-TOOLSDIR = $(ROOT)\tools
-!endif
-!ifndef TESTDIR
-TESTDIR = $(ROOT)\tests
-!endif
-!ifndef LIBDIR
-!if exist("$(ROOT)\library")
-LIBDIR = $(ROOT)\library
-!else
-LIBDIR = $(ROOT)\lib
!endif
+!else # "$(OS)" != "Windows_NT"
+CPY = xcopy /i >_JUNK.OUT # On Win98 NUL does not work here.
+COPY = copy >_JUNK.OUT # On Win98 NUL does not work here.
+RMDIR = deltree /Y
+NULL = \NUL # Used in testing directory existence
+ERRNULL = >NUL # Win9x shell cannot redirect stderr
!endif
-!ifndef DEMODIR
-!if exist("$(LIBDIR)\demos")
-DEMODIR = $(LIBDIR)\demos
-!else
-DEMODIR = $(ROOT)\demos
-!endif
-!endif # ifndef DEMODIR
-# Do NOT use WINDIR because it is Windows internal environment
-# variable to point to c:\windows!
-WIN_DIR = $(ROOT)\win
-
-!ifndef RCDIR
-!if exist("$(WIN_DIR)\rc")
-RCDIR = $(WIN_DIR)\rc
-!else
-RCDIR = $(WIN_DIR)
-!endif
-!endif
-RCDIR = $(RCDIR:/=\)
-
-# The target directory where the built packages and binaries will be installed.
-# INSTALLDIR is the (optional) path specified by the user.
-# _INSTALLDIR is INSTALLDIR using the backslash separator syntax
-!ifdef INSTALLDIR
-### Fix the path separators.
-_INSTALLDIR = $(INSTALLDIR:/=\)
-!else
-### Assume the normal default.
-_INSTALLDIR = $(HOMEDRIVE)\Tcl
-!endif
-
-!if $(DOING_TCL)
-
-# BEGIN Case 2(a) - Building Tcl itself
-
-# Only need to define _TCL_H
-_TCL_H = ..\generic\tcl.h
-
-# END Case 2(a) - Building Tcl itself
-
-!elseif $(DOING_TK)
-
-# BEGIN Case 2(b) - Building Tk
-
-TCLINSTALL = 0 # Tk always builds against Tcl source, not an installed Tcl
-!if "$(TCLDIR)" == ""
-!if [echo TCLDIR = \> nmakehlp.out] \
- || [nmakehlp -L generic\tcl.h >> nmakehlp.out]
-!error *** Could not locate Tcl source directory.
-!endif
-!include nmakehlp.out
-!endif # TCLDIR == ""
-
-_TCLDIR = $(TCLDIR:/=\)
-_TCL_H = $(_TCLDIR)\generic\tcl.h
-!if !exist("$(_TCL_H)")
-!error Could not locate tcl.h. Please set the TCLDIR macro to point to the Tcl *source* directory.
-!endif
-
-_TK_H = ..\generic\tk.h
-
-# END Case 2(b) - Building Tk
-
-!else
-
-# BEGIN Case 2(c) or (d) - Building an extension other than Tk
-
-# If command line has specified Tcl location through TCLDIR, use it
-# else default to the INSTALLDIR setting
-!if "$(TCLDIR)" != ""
-
-_TCLDIR = $(TCLDIR:/=\)
-!if exist("$(_TCLDIR)\include\tcl.h") # Case 2(c) with TCLDIR defined
-TCLINSTALL = 1
-_TCL_H = $(_TCLDIR)\include\tcl.h
-!elseif exist("$(_TCLDIR)\generic\tcl.h") # Case 2(d) with TCLDIR defined
-TCLINSTALL = 0
-_TCL_H = $(_TCLDIR)\generic\tcl.h
-!endif
-
-!else # # Case 2(c) for extensions with TCLDIR undefined
-
-# Need to locate Tcl depending on whether it needs Tcl source or not.
-# If we don't, check the INSTALLDIR for an installed Tcl first
-
-!if exist("$(_INSTALLDIR)\include\tcl.h") && !$(NEED_TCL_SOURCE)
-
-TCLINSTALL = 1
-TCLDIR = $(_INSTALLDIR)\..
-# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions
-# later so the \.. accounts for the /lib
-_TCLDIR = $(_INSTALLDIR)\..
-_TCL_H = $(_TCLDIR)\include\tcl.h
-
-!else # exist(...) && !$(NEED_TCL_SOURCE)
-
-!if [echo _TCLDIR = \> nmakehlp.out] \
- || [nmakehlp -L generic\tcl.h >> nmakehlp.out]
-!error *** Could not locate Tcl source directory.
-!endif
-!include nmakehlp.out
-TCLINSTALL = 0
-TCLDIR = $(_TCLDIR)
-_TCL_H = $(_TCLDIR)\generic\tcl.h
-
-!endif # exist(...) && !$(NEED_TCL_SOURCE)
-
-!endif # TCLDIR
-
-!ifndef _TCL_H
-MSG =^
-Failed to find tcl.h. The TCLDIR macro is set incorrectly or is not set and default path does not contain tcl.h.
-!error $(MSG)
-!endif
-
-# Now do the same to locate Tk headers and libs if project requires Tk
-!if $(NEED_TK)
-
-!if "$(TKDIR)" != ""
-
-_TKDIR = $(TKDIR:/=\)
-!if exist("$(_TKDIR)\include\tk.h")
-TKINSTALL = 1
-_TK_H = $(_TKDIR)\include\tk.h
-!elseif exist("$(_TKDIR)\generic\tk.h")
-TKINSTALL = 0
-_TK_H = $(_TKDIR)\generic\tk.h
-!endif
-
-!else # TKDIR not defined
-
-# Need to locate Tcl depending on whether it needs Tcl source or not.
-# If we don't, check the INSTALLDIR for an installed Tcl first
-
-!if exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE)
-
-TKINSTALL = 1
-# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions
-# later so the \.. accounts for the /lib
-_TKDIR = $(_INSTALLDIR)\..
-_TK_H = $(_TKDIR)\include\tk.h
-TKDIR = $(_TKDIR)
-
-!else # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE)
-
-!if [echo _TKDIR = \> nmakehlp.out] \
- || [nmakehlp -L generic\tk.h >> nmakehlp.out]
-!error *** Could not locate Tk source directory.
-!endif
-!include nmakehlp.out
-TKINSTALL = 0
-TKDIR = $(_TKDIR)
-_TK_H = $(_TKDIR)\generic\tk.h
-
-!endif # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE)
-
-!endif # TKDIR
-
-!ifndef _TK_H
-MSG =^
-Failed to find tk.h. The TKDIR macro is set incorrectly or is not set and default path does not contain tk.h.
-!error $(MSG)
-!endif
-
-!endif # NEED_TK
-
-!if $(NEED_TCL_SOURCE) && $(TCLINSTALL)
-MSG = ^
-*** Warning: This extension requires the source distribution of Tcl.^
-*** Please set the TCLDIR macro to point to the Tcl sources.
-!error $(MSG)
-!endif
-
-!if $(NEED_TK_SOURCE)
-!if $(TKINSTALL)
-MSG = ^
-*** Warning: This extension requires the source distribution of Tk.^
-*** Please set the TKDIR macro to point to the Tk sources.
-!error $(MSG)
-!endif
-!endif
-
-
-# If INSTALLDIR set to Tcl installation root dir then reset to the
-# lib dir for installing extensions
-!if exist("$(_INSTALLDIR)\include\tcl.h")
-_INSTALLDIR=$(_INSTALLDIR)\lib
-!endif
-
-# END Case 2(c) or (d) - Building an extension
-!endif # if $(DOING_TCL)
-
-################################################################
-# 3. Determine compiler version and architecture
-# In this section, we figure out the compiler version and the
-# architecture for which we are building. This sets the
-# following macros:
-# VCVERSION - the internal compiler version as 1200, 1400, 1910 etc.
-# This is also printed by the compiler in dotted form 19.10 etc.
-# VCVER - the "marketing version", for example Visual C++ 6 for internal
-# compiler version 1200. This is kept only for legacy reasons as it
-# does not make sense for recent Microsoft compilers. Only used for
-# output directory names.
-# ARCH - set to IX86, ARM64 or AMD64 depending on 32- or 64-bit target
-# NATIVE_ARCH - set to IX86, ARM64 or AMD64 for the host machine
-# MACHINE - same as $(ARCH) - legacy
-# _VC_MANIFEST_EMBED_{DLL,EXE} - commands for embedding a manifest if needed
-
-cc32 = $(CC) # built-in default.
-link32 = link
-lib32 = lib
-rc32 = $(RC) # built-in default.
+MKDIR = mkdir
-#----------------------------------------------------------------
-# Figure out the compiler architecture and version by writing
-# the C macros to a file, preprocessing them with the C
-# preprocessor and reading back the created file
+#------------------------------------------------------------------------------
+# Determine the host and target architectures and compiler version.
+#------------------------------------------------------------------------------
_HASH=^#
_VC_MANIFEST_EMBED_EXE=
@@ -436,70 +65,19 @@ VCVER=0
&& ![echo ARCH=IX86 >> vercl.x] \
&& ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \
&& ![echo ARCH=AMD64 >> vercl.x] \
- && ![echo $(_HASH)elif defined(_M_ARM64) >> vercl.x] \
- && ![echo ARCH=ARM64 >> vercl.x] \
&& ![echo $(_HASH)endif >> vercl.x] \
- && ![$(cc32) -nologo -TC -P vercl.x 2>NUL]
+ && ![cl -nologo -TC -P vercl.x $(ERRNULL)]
!include vercl.i
-!if $(VCVERSION) < 1900
!if ![echo VCVER= ^\> vercl.vc] \
&& ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc]
!include vercl.vc
!endif
-!else
-# The simple calculation above does not apply to new Visual Studio releases
-# Keep the compiler version in its native form.
-VCVER = $(VCVERSION)
-!endif
-!endif
-
-!if ![del 2>NUL /q/f vercl.x vercl.i vercl.vc]
-!endif
-
-#----------------------------------------------------------------
-# The MACHINE macro is used by legacy makefiles so set it as well
-!ifdef MACHINE
-!if "$(MACHINE)" == "x86"
-!undef MACHINE
-MACHINE = IX86
-!elseif "$(MACHINE)" == "arm64"
-!undef MACHINE
-MACHINE = ARM64
-!elseif "$(MACHINE)" == "x64"
-!undef MACHINE
-MACHINE = AMD64
-!endif
-!if "$(MACHINE)" != "$(ARCH)"
-!error Specified MACHINE macro $(MACHINE) does not match detected target architecture $(ARCH).
-!endif
-!else
-MACHINE=$(ARCH)
-!endif
-
-#---------------------------------------------------------------
-# The PLATFORM_IDENTIFY macro matches the values returned by
-# the Tcl platform::identify command
-!if "$(MACHINE)" == "AMD64"
-PLATFORM_IDENTIFY = win32-x86_64
-!elseif "$(MACHINE)" == "ARM64"
-PLATFORM_IDENTIFY = win32-arm
-!else
-PLATFORM_IDENTIFY = win32-ix86
!endif
-
-# The MULTIPLATFORM macro controls whether binary extensions are installed
-# in platform-specific directories. Intended to be set/used by extensions.
-!ifndef MULTIPLATFORM_INSTALL
-MULTIPLATFORM_INSTALL = 0
+!if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc]
!endif
-#------------------------------------------------------------
-# Figure out the *host* architecture by reading the registry
-
!if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86]
NATIVE_ARCH=IX86
-!elseif ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i ARM | findstr /i 64-bit]
-NATIVE_ARCH=ARM64
!else
NATIVE_ARCH=AMD64
!endif
@@ -510,408 +88,190 @@ _VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -ou
_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2
!endif
-################################################################
-# 4. Build the nmakehlp program
-# This is a helper app we need to overcome nmake's limiting
-# environment. We will call out to it to get various bits of
-# information about supported compiler options etc.
-#
-# Tcl itself will always use the nmakehlp.c program which is
-# in its own source. It will be kept updated there.
-#
-# Extensions built against an installed Tcl will use the installed
-# copy of Tcl's nmakehlp.c if there is one and their own version
-# otherwise. In the latter case, they would also be using their own
-# rules.vc. Note that older versions of Tcl do not install nmakehlp.c
-# or rules.vc.
-#
-# Extensions built against Tcl sources will use the one from the Tcl source.
-#
-# When building an extension using a sufficiently new version of Tcl,
-# rules-ext.vc will define NMAKEHLPC appropriately to point to the
-# copy of nmakehlp.c to be used.
+!ifndef MACHINE
+MACHINE=$(ARCH)
+!endif
-!ifndef NMAKEHLPC
-# Default to the one in the current directory (the extension's own nmakehlp.c)
-NMAKEHLPC = nmakehlp.c
+!ifndef CFG_ENCODING
+CFG_ENCODING = \"cp1252\"
+!endif
-!if !$(DOING_TCL)
-!if $(TCLINSTALL)
-!if exist("$(_TCLDIR)\lib\nmake\nmakehlp.c")
-NMAKEHLPC = $(_TCLDIR)\lib\nmake\nmakehlp.c
+!message ===============================================================================
+
+#----------------------------------------------------------
+# build the helper app we need to overcome nmake's limiting
+# environment.
+#----------------------------------------------------------
+
+!if !exist(nmakehlp.exe)
+!if [$(cc32) -nologo nmakehlp.c -link -subsystem:console > nul]
!endif
-!else # !$(TCLINSTALL)
-!if exist("$(_TCLDIR)\win\nmakehlp.c")
-NMAKEHLPC = $(_TCLDIR)\win\nmakehlp.c
!endif
-!endif # $(TCLINSTALL)
-!endif # !$(DOING_TCL)
-!endif # NMAKEHLPC
+#----------------------------------------------------------
+# Test for compiler features
+#----------------------------------------------------------
-# We always build nmakehlp even if it exists since we do not know
-# what source it was built from.
-!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)"
-!if [$(cc32) -nologo "$(NMAKEHLPC)" -link -subsystem:console > nul]
-!endif
+### test for optimizations
+!if [nmakehlp -c -Ot]
+!message *** Compiler has 'Optimizations'
+OPTIMIZING = 1
!else
-!if [copy $(NMAKEHLPC:nmakehlp.c=x86_64-w64-mingw32-nmakehlp.exe) nmakehlp.exe >NUL]
-!endif
+!message *** Compiler does not have 'Optimizations'
+OPTIMIZING = 0
!endif
-################################################################
-# 5. Test for compiler features
-# Visual C++ compiler options have changed over the years. Check
-# which options are supported by the compiler in use.
-#
-# The following macros are set:
-# OPTIMIZATIONS - the compiler flags to be used for optimized builds
-# DEBUGFLAGS - the compiler flags to be used for debug builds
-# LINKERFLAGS - Flags passed to the linker
-#
-# Note that these are the compiler settings *available*, not those
-# that will be *used*. The latter depends on the OPTS macro settings
-# which we have not yet parsed.
-#
-# Also note that some of the flags in OPTIMIZATIONS are not really
-# related to optimization. They are placed there only for legacy reasons
-# as some extensions expect them to be included in that macro.
+OPTIMIZATIONS =
-# -Op improves float consistency. Note only needed for older compilers
-# Newer compilers do not need or support this option.
-!if [nmakehlp -c -Op]
-FPOPTS = -Op
+!if [nmakehlp -c -Ot]
+OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot
!endif
-# Strict floating point semantics - present in newer compilers in lieu of -Op
-!if [nmakehlp -c -fp:strict]
-FPOPTS = $(FPOPTS) -fp:strict
+!if [nmakehlp -c -Oi]
+OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi
!endif
-!if "$(MACHINE)" == "IX86"
-### test for pentium errata
-!if [nmakehlp -c -QI0f]
-!message *** Compiler has 'Pentium 0x0f fix'
-FPOPTS = $(FPOPTS) -QI0f
-!else
-!message *** Compiler does not have 'Pentium 0x0f fix'
+!if [nmakehlp -c -Op]
+OPTIMIZATIONS = $(OPTIMIZATIONS) -Op
!endif
+
+!if [nmakehlp -c -fp:strict]
+OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:strict
!endif
-### test for optimizations
-# /O2 optimization includes /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy as per
-# documentation. Note we do NOT want /Gs as that inserts a _chkstk
-# stack probe at *every* function entry, not just those with more than
-# a page of stack allocation resulting in a performance hit. However,
-# /O2 documentation is misleading as its stack probes are simply the
-# default page size locals allocation probes and not what is implied
-# by an explicit /Gs option.
-
-OPTIMIZATIONS = $(FPOPTS)
-
-!if [nmakehlp -c -O2]
-OPTIMIZING = 1
-OPTIMIZATIONS = $(OPTIMIZATIONS) -O2
-!else
-# Legacy, really. All modern compilers support this
-!message *** Compiler does not have 'Optimizations'
-OPTIMIZING = 0
+!if [nmakehlp -c -Gs]
+OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs
!endif
-# Checks for buffer overflows in local arrays
!if [nmakehlp -c -GS]
OPTIMIZATIONS = $(OPTIMIZATIONS) -GS
!endif
-# Link time optimization. Note that this option (potentially) makes
-# generated libraries only usable by the specific VC++ version that
-# created it. Requires /LTCG linker option
!if [nmakehlp -c -GL]
OPTIMIZATIONS = $(OPTIMIZATIONS) -GL
-CC_GL_OPT_ENABLED = 1
-!else
-# In newer compilers -GL and -YX are incompatible.
-!if [nmakehlp -c -YX]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -YX
!endif
-!endif # [nmakehlp -c -GL]
-DEBUGFLAGS = $(FPOPTS)
+DEBUGFLAGS =
-# Run time error checks. Not available or valid in a release, non-debug build
-# RTC is for modern compilers, -GZ is legacy
!if [nmakehlp -c -RTC1]
DEBUGFLAGS = $(DEBUGFLAGS) -RTC1
!elseif [nmakehlp -c -GZ]
DEBUGFLAGS = $(DEBUGFLAGS) -GZ
!endif
-#----------------------------------------------------------------
-# Linker flags
+COMPILERFLAGS =-W3
-# LINKER_TESTFLAGS are for internal use when we call nmakehlp to test
-# if the linker supports a specific option. Without these flags link will
-# return "LNK1561: entry point must be defined" error compiling from VS-IDE:
-# They are not passed through to the actual application / extension
-# link rules.
-!ifndef LINKER_TESTFLAGS
-LINKER_TESTFLAGS = /DLL /NOENTRY /OUT:nmakehlp.out
-!endif
-
-LINKERFLAGS =
-
-# If compiler has enabled link time optimization, linker must too with -ltcg
-!ifdef CC_GL_OPT_ENABLED
-!if [nmakehlp -l -ltcg $(LINKER_TESTFLAGS)]
-LINKERFLAGS = $(LINKERFLAGS) -ltcg
-!endif
-!endif
-
-
-################################################################
-# 6. Extract various version numbers from headers
-# For Tcl and Tk, version numbers are extracted from tcl.h and tk.h
-# respectively. For extensions, versions are extracted from the
-# configure.in or configure.ac from the TEA configuration if it
-# exists, and unset otherwise.
-# Sets the following macros:
-# TCL_MAJOR_VERSION
-# TCL_MINOR_VERSION
-# TCL_RELEASE_SERIAL
-# TCL_PATCH_LEVEL
-# TCL_PATCH_LETTER
-# TCL_VERSION
-# TK_MAJOR_VERSION
-# TK_MINOR_VERSION
-# TK_RELEASE_SERIAL
-# TK_PATCH_LEVEL
-# TK_PATCH_LETTER
-# TK_VERSION
-# DOTVERSION - set as (for example) 2.5
-# VERSION - set as (for example 25)
-#--------------------------------------------------------------
-
-!if [echo REM = This file is generated from rules.vc > versions.vc]
-!endif
-!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" "define TCL_MAJOR_VERSION" >> versions.vc]
-!endif
-!if [echo TCL_MINOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc]
+# In v13 -GL and -YX are incompatible.
+!if [nmakehlp -c -YX]
+!if ![nmakehlp -c -GL]
+OPTIMIZATIONS = $(OPTIMIZATIONS) -YX
!endif
-!if [echo TCL_RELEASE_SERIAL = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" TCL_RELEASE_SERIAL >> versions.vc]
-!endif
-!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc]
!endif
-!if defined(_TK_H)
-!if [echo TK_MAJOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V $(_TK_H) "define TK_MAJOR_VERSION" >> versions.vc]
-!endif
-!if [echo TK_MINOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc]
-!endif
-!if [echo TK_RELEASE_SERIAL = \>> versions.vc] \
- && [nmakehlp -V "$(_TK_H)" TK_RELEASE_SERIAL >> versions.vc]
+!if "$(MACHINE)" == "IX86"
+### test for pentium errata
+!if [nmakehlp -c -QI0f]
+!message *** Compiler has 'Pentium 0x0f fix'
+COMPILERFLAGS = $(COMPILERFLAGS) -QI0f
+!else
+!message *** Compiler does not have 'Pentium 0x0f fix'
!endif
-!if [echo TK_PATCH_LEVEL = \>> versions.vc] \
- && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc]
!endif
-!endif # _TK_H
-!include versions.vc
-
-TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION)
-TCL_DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)
-!if [nmakehlp -f $(TCL_PATCH_LEVEL) "a"]
-TCL_PATCH_LETTER = a
-!elseif [nmakehlp -f $(TCL_PATCH_LEVEL) "b"]
-TCL_PATCH_LETTER = b
+!if "$(MACHINE)" == "IA64"
+### test for Itanium errata
+!if [nmakehlp -c -QIA64_Bx]
+!message *** Compiler has 'B-stepping errata workarounds'
+COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx
!else
-TCL_PATCH_LETTER = .
+!message *** Compiler does not have 'B-stepping errata workarounds'
+!endif
!endif
-!if defined(_TK_H)
-
-TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION)
-TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)
-!if [nmakehlp -f $(TK_PATCH_LEVEL) "a"]
-TK_PATCH_LETTER = a
-!elseif [nmakehlp -f $(TK_PATCH_LEVEL) "b"]
-TK_PATCH_LETTER = b
+!if "$(MACHINE)" == "IX86"
+### test for -align:4096, when align:512 will do.
+!if [nmakehlp -l -opt:nowin98]
+!message *** Linker has 'Win98 alignment problem'
+ALIGN98_HACK = 1
!else
-TK_PATCH_LETTER = .
+!message *** Linker does not have 'Win98 alignment problem'
+ALIGN98_HACK = 0
!endif
-
+!else
+ALIGN98_HACK = 0
!endif
-# Set DOTVERSION and VERSION
-!if $(DOING_TCL)
-
-DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)
-VERSION = $(TCL_VERSION)
-
-!elseif $(DOING_TK)
-
-DOTVERSION = $(TK_DOTVERSION)
-VERSION = $(TK_VERSION)
-
-!else # Doing a non-Tk extension
+LINKERFLAGS =
-# If parent makefile has not defined DOTVERSION, try to get it from TEA
-# first from a configure.in file, and then from configure.ac
-!ifndef DOTVERSION
-!if [echo DOTVERSION = \> versions.vc] \
- || [nmakehlp -V $(ROOT)\configure.in ^[$(PROJECT)^] >> versions.vc]
-!if [echo DOTVERSION = \> versions.vc] \
- || [nmakehlp -V $(ROOT)\configure.ac ^[$(PROJECT)^] >> versions.vc]
-!error *** Could not figure out extension version. Please define DOTVERSION in parent makefile before including rules.vc.
-!endif
+!if [nmakehlp -l -ltcg]
+LINKERFLAGS =-ltcg
!endif
-!include versions.vc
-!endif # DOTVERSION
-VERSION = $(DOTVERSION:.=)
-
-!endif # $(DOING_TCL) ... etc.
-
-# Windows RC files have 3 version components. Ensure this irrespective
-# of how many components the package has specified. Basically, ensure
-# minimum 4 components by appending 4 0's and then pick out the first 4.
-# Also take care of the fact that DOTVERSION may have "a" or "b" instead
-# of "." separating the version components.
-DOTSEPARATED=$(DOTVERSION:a=.)
-DOTSEPARATED=$(DOTSEPARATED:b=.)
-!if [echo RCCOMMAVERSION = \> versions.vc] \
- || [for /f "tokens=1,2,3,4,5* delims=." %a in ("$(DOTSEPARATED).0.0.0.0") do echo %a,%b,%c,%d >> versions.vc]
-!error *** Could not generate RCCOMMAVERSION ***
-!endif
-!include versions.vc
-########################################################################
-# 7. Parse the OPTS macro to work out the requested build configuration.
-# Based on this, we will construct the actual switches to be passed to the
-# compiler and linker using the macros defined in the previous section.
-# The following macros are defined by this section based on OPTS
-# STATIC_BUILD - 0 -> Tcl is to be built as a shared library
-# 1 -> build as a static library and shell
-# TCL_THREADS - legacy but always 1 on Windows since winsock requires it.
-# DEBUG - 1 -> debug build, 0 -> release builds
-# SYMBOLS - 1 -> generate PDB's, 0 -> no PDB's
-# PROFILE - 1 -> generate profiling info, 0 -> no profiling
-# PGO - 1 -> profile based optimization, 0 -> no
-# MSVCRT - 1 -> link to dynamic C runtime even when building static Tcl build
-# 0 -> link to static C runtime for static Tcl build.
-# Does not impact shared Tcl builds (STATIC_BUILD == 0)
-# Default: 1 for Tcl 8.7 and up, 0 otherwise.
-# TCL_USE_STATIC_PACKAGES - 1 -> statically link the registry and dde extensions
-# in the Tcl and Wish shell. 0 -> keep them as shared libraries. Does
-# not impact shared Tcl builds. Implied by STATIC_BUILD since Tcl 8.7.
-# USE_THREAD_ALLOC - 1 -> Use a shared global free pool for allocation.
-# 0 -> Use the non-thread allocator.
-# UNCHECKED - 1 -> when doing a debug build with symbols, use the release
-# C runtime, 0 -> use the debug C runtime.
-# USE_STUBS - 1 -> compile to use stubs interfaces, 0 -> direct linking
-# CONFIG_CHECK - 1 -> check current build configuration against Tcl
-# configuration (ignored for Tcl itself)
-# _USE_64BIT_TIME_T - forces a build using 64-bit time_t for 32-bit build
-# (CRT library should support this, not needed for Tcl 9.x)
-# Further, LINKERFLAGS are modified based on above.
-
-# Default values for all the above
+#----------------------------------------------------------
+# Decode the options requested.
+#----------------------------------------------------------
+
+!if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"]
STATIC_BUILD = 0
-TCL_THREADS = 1
+TCL_THREADS = 0
DEBUG = 0
SYMBOLS = 0
PROFILE = 0
PGO = 0
MSVCRT = 1
+LOIMPACT = 0
TCL_USE_STATIC_PACKAGES = 0
-USE_THREAD_ALLOC = 1
+USE_THREAD_ALLOC = 0
UNCHECKED = 0
-CONFIG_CHECK = 1
-!if $(DOING_TCL)
-USE_STUBS = 0
!else
-USE_STUBS = 1
-!endif
-
-# If OPTS is not empty AND does not contain "none" which turns off all OPTS
-# set the above macros based on OPTS content
-!if "$(OPTS)" != "" && ![nmakehlp -f "$(OPTS)" "none"]
-
-# OPTS are specified, parse them
-
!if [nmakehlp -f $(OPTS) "static"]
!message *** Doing static
STATIC_BUILD = 1
-!endif
-
-!if [nmakehlp -f $(OPTS) "nostubs"]
-!message *** Not using stubs
-USE_STUBS = 0
-!endif
-
-!if [nmakehlp -f $(OPTS) "nomsvcrt"]
-!message *** Doing nomsvcrt
-MSVCRT = 0
!else
+STATIC_BUILD = 0
+!endif
!if [nmakehlp -f $(OPTS) "msvcrt"]
!message *** Doing msvcrt
+MSVCRT = 1
+!else
+!if !$(STATIC_BUILD)
+MSVCRT = 1
!else
-!if $(TCL_MAJOR_VERSION) == 8 && $(TCL_MINOR_VERSION) < 7 && $(STATIC_BUILD)
MSVCRT = 0
!endif
!endif
-!endif # [nmakehlp -f $(OPTS) "nomsvcrt"]
-
!if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD)
!message *** Doing staticpkg
TCL_USE_STATIC_PACKAGES = 1
+!else
+TCL_USE_STATIC_PACKAGES = 0
!endif
-
-!if [nmakehlp -f $(OPTS) "nothreads"]
-!message *** Compile explicitly for non-threaded tcl
-TCL_THREADS = 0
-USE_THREAD_ALLOC= 0
-!endif
-
-!if [nmakehlp -f $(OPTS) "tcl8"]
-!message *** Build for Tcl8
-TCL_BUILD_FOR = 8
-!endif
-
-!if $(TCL_MAJOR_VERSION) == 8
-!if [nmakehlp -f $(OPTS) "time64bit"]
-!message *** Force 64-bit time_t
-_USE_64BIT_TIME_T = 1
-!endif
+!if [nmakehlp -f $(OPTS) "threads"]
+!message *** Doing threads
+TCL_THREADS = 1
+USE_THREAD_ALLOC = 1
+!else
+TCL_THREADS = 0
+USE_THREAD_ALLOC = 0
!endif
-
-# Yes, it's weird that the "symbols" option controls DEBUG and
-# the "pdbs" option controls SYMBOLS. That's historical.
!if [nmakehlp -f $(OPTS) "symbols"]
!message *** Doing symbols
DEBUG = 1
!else
DEBUG = 0
!endif
-
!if [nmakehlp -f $(OPTS) "pdbs"]
!message *** Doing pdbs
SYMBOLS = 1
!else
SYMBOLS = 0
!endif
-
!if [nmakehlp -f $(OPTS) "profile"]
!message *** Doing profile
PROFILE = 1
!else
PROFILE = 0
!endif
-
!if [nmakehlp -f $(OPTS) "pgi"]
!message *** Doing profile guided optimization instrumentation
PGO = 1
@@ -921,149 +281,44 @@ PGO = 2
!else
PGO = 0
!endif
-
!if [nmakehlp -f $(OPTS) "loimpact"]
-!message *** Warning: ignoring option "loimpact" - deprecated on modern Windows.
+!message *** Doing loimpact
+LOIMPACT = 1
+!else
+LOIMPACT = 0
!endif
-
-# TBD - should get rid of this option
!if [nmakehlp -f $(OPTS) "thrdalloc"]
!message *** Doing thrdalloc
USE_THREAD_ALLOC = 1
!endif
-
!if [nmakehlp -f $(OPTS) "tclalloc"]
+!message *** Doing tclalloc
USE_THREAD_ALLOC = 0
!endif
-
!if [nmakehlp -f $(OPTS) "unchecked"]
!message *** Doing unchecked
UNCHECKED = 1
!else
UNCHECKED = 0
!endif
-
-!if [nmakehlp -f $(OPTS) "noconfigcheck"]
-CONFIG_CHECK = 1
-!else
-CONFIG_CHECK = 0
-!endif
-
-!endif # "$(OPTS)" != "" && ... parsing of OPTS
-
-# Set linker flags based on above
-
-!if $(PGO) > 1
-!if [nmakehlp -l -ltcg:pgoptimize $(LINKER_TESTFLAGS)]
-LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize
-!else
-MSG=^
-This compiler does not support profile guided optimization.
-!error $(MSG)
-!endif
-!elseif $(PGO) > 0
-!if [nmakehlp -l -ltcg:pginstrument $(LINKER_TESTFLAGS)]
-LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument
-!else
-MSG=^
-This compiler does not support profile guided optimization.
-!error $(MSG)
-!endif
!endif
-################################################################
-# 8. Parse the STATS macro to configure code instrumentation
-# The following macros are set by this section:
-# TCL_MEM_DEBUG - 1 -> enables memory allocation instrumentation
-# 0 -> disables
-# TCL_COMPILE_DEBUG - 1 -> enables byte compiler logging
-# 0 -> disables
-
-# Default both are off
-TCL_MEM_DEBUG = 0
-TCL_COMPILE_DEBUG = 0
-
-!if "$(STATS)" != "" && ![nmakehlp -f "$(STATS)" "none"]
-
-!if [nmakehlp -f $(STATS) "memdbg"]
-!message *** Doing memdbg
-TCL_MEM_DEBUG = 1
-!else
-TCL_MEM_DEBUG = 0
-!endif
-
-!if [nmakehlp -f $(STATS) "compdbg"]
-!message *** Doing compdbg
-TCL_COMPILE_DEBUG = 1
-!else
-TCL_COMPILE_DEBUG = 0
-!endif
-
-!endif
-
-####################################################################
-# 9. Parse the CHECKS macro to configure additional compiler checks
-# The following macros are set by this section:
-# WARNINGS - compiler switches that control the warnings level
-# TCL_NO_DEPRECATED - 1 -> disable support for deprecated functions
-# 0 -> enable deprecated functions
-
-# Defaults - Permit deprecated functions and warning level 3
-TCL_NO_DEPRECATED = 0
-WARNINGS = -W3
-
-!if "$(CHECKS)" != "" && ![nmakehlp -f "$(CHECKS)" "none"]
-
-!if [nmakehlp -f $(CHECKS) "nodep"]
-!message *** Doing nodep check
-TCL_NO_DEPRECATED = 1
-!endif
-
-!if [nmakehlp -f $(CHECKS) "fullwarn"]
-!message *** Doing full warnings check
-WARNINGS = -W4
-!if [nmakehlp -l -warn:3 $(LINKER_TESTFLAGS)]
-LINKERFLAGS = $(LINKERFLAGS) -warn:3
-!endif
-!endif
-
-!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64]
-!message *** Doing 64bit portability warnings
-WARNINGS = $(WARNINGS) -Wp64
-!endif
-
-!endif
-
-
-################################################################
-# 10. Construct output directory and file paths
+#----------------------------------------------------------
# Figure-out how to name our intermediate and output directories.
-# In order to avoid inadvertent mixing of object files built using
-# different compilers, build configurations etc.,
-#
-# Naming convention (suffixes):
-# t = full thread support. (Not used for Tcl >= 8.7)
-# s = static library (as opposed to an import library)
-# g = linked to the debug enabled C run-time.
-# x = special static build when it links to the dynamic C run-time.
-#
-# The following macros are set in this section:
-# SUFX - the suffix to use for binaries based on above naming convention
-# BUILDDIRTOP - the toplevel default output directory
-# is of the form {Release,Debug}[_AMD64][_COMPILERVERSION]
-# TMP_DIR - directory where object files are created
-# OUT_DIR - directory where output executables are created
-# Both TMP_DIR and OUT_DIR are defaulted only if not defined by the
-# parent makefile (or command line). The default values are
-# based on BUILDDIRTOP.
-# STUBPREFIX - name of the stubs library for this project
-# PRJIMPLIB - output path of the generated project import library
-# PRJLIBNAME - name of generated project library
-# PRJLIB - output path of generated project library
-# PRJSTUBLIBNAME - name of the generated project stubs library
-# PRJSTUBLIB - output path of the generated project stubs library
-# RESFILE - output resource file (only if not static build)
+# We wouldn't want different builds to use the same .obj files
+# by accident.
+#----------------------------------------------------------
+#----------------------------------------
+# Naming convention:
+# t = full thread support.
+# s = static library (as opposed to an
+# import library)
+# g = linked to the debug enabled C
+# run-time.
+# x = special static build when it
+# links to the dynamic C run-time.
+#----------------------------------------
SUFX = tsgx
!if $(DEBUG)
@@ -1079,7 +334,7 @@ BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE)
BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER)
!endif
-!if !$(DEBUG) || $(TCL_VERSION) > 86 || $(DEBUG) && $(UNCHECKED)
+!if !$(DEBUG) || $(DEBUG) && $(UNCHECKED)
SUFX = $(SUFX:g=)
!endif
@@ -1094,13 +349,13 @@ SUFX = $(SUFX:x=)
!else
TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=)
EXT = lib
-!if $(MSVCRT) && $(TCL_VERSION) > 86 || !$(MSVCRT) && $(TCL_VERSION) < 87
+!if !$(MSVCRT)
TMP_DIRFULL = $(TMP_DIRFULL:X=)
SUFX = $(SUFX:x=)
!endif
!endif
-!if !$(TCL_THREADS) || $(TCL_VERSION) > 86
+!if !$(TCL_THREADS)
TMP_DIRFULL = $(TMP_DIRFULL:Threaded=)
SUFX = $(SUFX:t=)
!endif
@@ -1116,800 +371,328 @@ OUT_DIR = $(TMP_DIR)
!endif
!endif
-# Relative paths -> absolute
-!if [echo OUT_DIR = \> nmakehlp.out] \
- || [nmakehlp -Q "$(OUT_DIR)" >> nmakehlp.out]
-!error *** Could not fully qualify path OUT_DIR=$(OUT_DIR)
-!endif
-!if [echo TMP_DIR = \>> nmakehlp.out] \
- || [nmakehlp -Q "$(TMP_DIR)" >> nmakehlp.out]
-!error *** Could not fully qualify path TMP_DIR=$(TMP_DIR)
-!endif
-!include nmakehlp.out
-
-# The name of the stubs library for the project being built
-STUBPREFIX = $(PROJECT)stub
-#
-# Set up paths to various Tcl executables and libraries needed by extensions
-#
-
-# TIP 430. Unused for 8.6 but no harm defining it to allow a common rules.vc
-TCLSCRIPTZIPNAME = libtcl$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)$(TCL_PATCH_LETTER)$(TCL_RELEASE_SERIAL).zip
-TKSCRIPTZIPNAME = libtk$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)$(TK_PATCH_LETTER)$(TK_RELEASE_SERIAL).zip
-
-!if $(DOING_TCL)
-TCLSHNAME = $(PROJECT)sh$(VERSION)$(SUFX).exe
-TCLSH = $(OUT_DIR)\$(TCLSHNAME)
-TCLIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
-TCLLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT)
-TCLLIB = $(OUT_DIR)\$(TCLLIBNAME)
-TCLSCRIPTZIP = $(OUT_DIR)\$(TCLSCRIPTZIPNAME)
+#----------------------------------------------------------
+# Decode the statistics requested.
+#----------------------------------------------------------
-!if $(TCL_MAJOR_VERSION) == 8
-TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib
+!if "$(STATS)" == "" || [nmakehlp -f "$(STATS)" "none"]
+TCL_MEM_DEBUG = 0
+TCL_COMPILE_DEBUG = 0
!else
-TCLSTUBLIBNAME = $(STUBPREFIX).lib
-!endif
-TCLSTUBLIB = $(OUT_DIR)\$(TCLSTUBLIBNAME)
-TCL_INCLUDES = -I"$(WIN_DIR)" -I"$(GENERICDIR)"
-
-!else # !$(DOING_TCL)
-
-!if $(TCLINSTALL) # Building against an installed Tcl
-
-# When building extensions, we need to locate tclsh. Depending on version
-# of Tcl we are building against, this may or may not have a "t" suffix.
-# Try various possibilities in turn.
-TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe
-!if !exist("$(TCLSH)")
-TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX:t=).exe
-!endif
-
-!if $(TCL_MAJOR_VERSION) == 8
-TCLSTUBLIB = $(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib
+!if [nmakehlp -f $(STATS) "memdbg"]
+!message *** Doing memdbg
+TCL_MEM_DEBUG = 1
!else
-TCLSTUBLIB = $(_TCLDIR)\lib\tclstub.lib
-!endif
-TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX:t=).lib
-# When building extensions, may be linking against Tcl that does not add
-# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
-!if !exist("$(TCLIMPLIB)")
-TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)t$(SUFX:t=).lib
-!endif
-TCL_LIBRARY = $(_TCLDIR)\lib
-TCLREGLIB = $(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib
-TCLDDELIB = $(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib
-TCLSCRIPTZIP = $(_TCLDIR)\lib\$(TCLSCRIPTZIPNAME)
-TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target
-TCL_INCLUDES = -I"$(_TCLDIR)\include"
-
-!else # Building against Tcl sources
-
-TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX:t=).exe
-!if !exist($(TCLSH))
-TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX:t=).exe
+TCL_MEM_DEBUG = 0
!endif
-!if $(TCL_MAJOR_VERSION) == 8
-TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib
+!if [nmakehlp -f $(STATS) "compdbg"]
+!message *** Doing compdbg
+TCL_COMPILE_DEBUG = 1
!else
-TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub.lib
+TCL_COMPILE_DEBUG = 0
!endif
-TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX:t=).lib
-# When building extensions, may be linking against Tcl that does not add
-# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
-!if !exist("$(TCLIMPLIB)")
-TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)t$(SUFX:t=).lib
!endif
-TCL_LIBRARY = $(_TCLDIR)\library
-TCLREGLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib
-TCLDDELIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib
-TCLSCRIPTZIP = $(_TCLDIR)\win\$(BUILDDIRTOP)\$(TCLSCRIPTZIPNAME)
-TCLTOOLSDIR = $(_TCLDIR)\tools
-TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win"
-!endif # TCLINSTALL
-!if !$(STATIC_BUILD) && "$(TCL_BUILD_FOR)" == "8"
-tcllibs = "$(TCLSTUBLIB)"
-!else
-tcllibs = "$(TCLSTUBLIB)" "$(TCLIMPLIB)"
-!endif
-
-!endif # $(DOING_TCL)
+#----------------------------------------------------------
+# Decode the checks requested.
+#----------------------------------------------------------
-# We need a tclsh that will run on the host machine as part of the build.
-# IX86 runs on all architectures.
-!ifndef TCLSH_NATIVE
-!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)"
-TCLSH_NATIVE = $(TCLSH)
+!if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"]
+TCL_NO_DEPRECATED = 0
+WARNINGS = -W3
!else
-!error You must explicitly set TCLSH_NATIVE for cross-compilation
-!endif
-!endif
-
-# Do the same for Tk and Tk extensions that require the Tk libraries
-!if $(DOING_TK) || $(NEED_TK)
-WISHNAMEPREFIX = wish
-WISHNAME = $(WISHNAMEPREFIX)$(TK_VERSION)$(SUFX).exe
-TKLIBNAME8 = tk$(TK_VERSION)$(SUFX).$(EXT)
-TKLIBNAME9 = tcl9tk$(TK_VERSION)$(SUFX).$(EXT)
-!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8"
-TKLIBNAME = tk$(TK_VERSION)$(SUFX).$(EXT)
-TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX).lib
+!if [nmakehlp -f $(CHECKS) "nodep"]
+!message *** Doing nodep check
+TCL_NO_DEPRECATED = 1
!else
-TKLIBNAME = tcl9tk$(TK_VERSION)$(SUFX).$(EXT)
-TKIMPLIBNAME = tcl9tk$(TK_VERSION)$(SUFX).lib
+TCL_NO_DEPRECATED = 0
!endif
-!if $(TK_MAJOR_VERSION) == 8
-TKSTUBLIBNAME = tkstub$(TK_VERSION).lib
-!else
-TKSTUBLIBNAME = tkstub.lib
+!if [nmakehlp -f $(CHECKS) "fullwarn"]
+!message *** Doing full warnings check
+WARNINGS = -W4
+!if [nmakehlp -l -warn:3]
+LINKERFLAGS = $(LINKERFLAGS) -warn:3
!endif
-
-!if $(DOING_TK)
-WISH = $(OUT_DIR)\$(WISHNAME)
-TKSTUBLIB = $(OUT_DIR)\$(TKSTUBLIBNAME)
-TKIMPLIB = $(OUT_DIR)\$(TKIMPLIBNAME)
-TKLIB = $(OUT_DIR)\$(TKLIBNAME)
-TK_INCLUDES = -I"$(WIN_DIR)" -I"$(GENERICDIR)"
-TKSCRIPTZIP = $(OUT_DIR)\$(TKSCRIPTZIPNAME)
-
-!else # effectively NEED_TK
-
-!if $(TKINSTALL) # Building against installed Tk
-WISH = $(_TKDIR)\bin\$(WISHNAME)
-TKSTUBLIB = $(_TKDIR)\lib\$(TKSTUBLIBNAME)
-TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME)
-# When building extensions, may be linking against Tk that does not add
-# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
-!if !exist("$(TKIMPLIB)")
-TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib
-TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME)
+!else
+WARNINGS = -W3
!endif
-TK_INCLUDES = -I"$(_TKDIR)\include"
-TKSCRIPTZIP = $(_TKDIR)\lib\$(TKSCRIPTZIPNAME)
-
-!else # Building against Tk sources
-
-WISH = $(_TKDIR)\win\$(BUILDDIRTOP)\$(WISHNAME)
-TKSTUBLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKSTUBLIBNAME)
-TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME)
-# When building extensions, may be linking against Tk that does not add
-# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
-!if !exist("$(TKIMPLIB)")
-TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib
-TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME)
+!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64]
+!message *** Doing 64bit portability warnings
+WARNINGS = $(WARNINGS) -Wp64
!endif
-TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib"
-TKSCRIPTZIP = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKSCRIPTZIPNAME)
-
-!endif # TKINSTALL
-
-tklibs = "$(TKSTUBLIB)" "$(TKIMPLIB)"
-
-!endif # $(DOING_TK)
-!endif # $(DOING_TK) || $(NEED_TK)
-
-# Various output paths
-PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
-PRJLIBNAME8 = $(PROJECT)$(VERSION)$(SUFX).$(EXT)
-PRJLIBNAME9 = tcl9$(PROJECT)$(VERSION)$(SUFX).$(EXT)
-!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8"
-PRJLIBNAME = $(PRJLIBNAME8)
-!else
-PRJLIBNAME = $(PRJLIBNAME9)
!endif
-PRJLIB = $(OUT_DIR)\$(PRJLIBNAME)
-!if $(TCL_MAJOR_VERSION) == 8
-PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib
+!if $(PGO) > 1
+!if [nmakehlp -l -ltcg:pgoptimize]
+LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize
!else
-PRJSTUBLIBNAME = $(STUBPREFIX).lib
+MSG=^
+This compiler does not support profile guided optimization.
+!error $(MSG)
!endif
-PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME)
-
-# If extension parent makefile has not defined a resource definition file,
-# we will generate one from standard template.
-!if !$(DOING_TCL) && !$(DOING_TK) && !$(STATIC_BUILD)
-!ifdef RCFILE
-RESFILE = $(TMP_DIR)\$(RCFILE:.rc=.res)
-!else
-RESFILE = $(TMP_DIR)\$(PROJECT).res
-!endif
-!endif
-
-###################################################################
-# 11. Construct the paths for the installation directories
-# The following macros get defined in this section:
-# LIB_INSTALL_DIR - where libraries should be installed
-# BIN_INSTALL_DIR - where the executables should be installed
-# DOC_INSTALL_DIR - where documentation should be installed
-# SCRIPT_INSTALL_DIR - where scripts should be installed
-# INCLUDE_INSTALL_DIR - where C include files should be installed
-# DEMO_INSTALL_DIR - where demos should be installed
-# PRJ_INSTALL_DIR - where package will be installed (not set for Tcl and Tk)
-
-!if $(DOING_TCL) || $(DOING_TK)
-LIB_INSTALL_DIR = $(_INSTALLDIR)\lib
-BIN_INSTALL_DIR = $(_INSTALLDIR)\bin
-DOC_INSTALL_DIR = $(_INSTALLDIR)\doc
-!if $(DOING_TCL)
-SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)
-MODULE_INSTALL_DIR = $(_INSTALLDIR)\lib\tcl$(TCL_MAJOR_VERSION)
-!else # DOING_TK
-SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)
-!endif
-DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos
-INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include
-
-!else # extension other than Tk
-
-PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION)
-!if $(MULTIPLATFORM_INSTALL)
-LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY)
-BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY)
-!else
-LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-!endif
-DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos
-INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\..\include
-
-!endif
-
-###################################################################
-# 12. Set up actual options to be passed to the compiler and linker
-# Now we have all the information we need, set up the actual flags and
-# options that we will pass to the compiler and linker. The main
-# makefile should use these in combination with whatever other flags
-# and switches are specific to it.
-# The following macros are defined, names are for historical compatibility:
-# OPTDEFINES - /Dxxx C macro flags based on user-specified OPTS
-# COMPILERFLAGS - /Dxxx C macro flags independent of any configuration options
-# crt - Compiler switch that selects the appropriate C runtime
-# cdebug - Compiler switches related to debug AND optimizations
-# cwarn - Compiler switches that set warning levels
-# cflags - complete compiler switches (subsumes cdebug and cwarn)
-# ldebug - Linker switches controlling debug information and optimization
-# lflags - complete linker switches (subsumes ldebug) except subsystem type
-# dlllflags - complete linker switches to build DLLs (subsumes lflags)
-# conlflags - complete linker switches for console program (subsumes lflags)
-# guilflags - complete linker switches for GUI program (subsumes lflags)
-# baselibs - minimum Windows libraries required. Parent makefile can
-# define PRJ_LIBS before including rules.rc if additional libs are needed
-
-OPTDEFINES = /DSTDC_HEADERS /DUSE_NMAKE=1
-!if $(VCVERSION) > 1600
-OPTDEFINES = $(OPTDEFINES) /DHAVE_STDINT_H=1
+!elseif $(PGO) > 0
+!if [nmakehlp -l -ltcg:pginstrument]
+LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument
!else
-OPTDEFINES = $(OPTDEFINES) /DMP_NO_STDINT=1
+MSG=^
+This compiler does not support profile guided optimization.
+!error $(MSG)
!endif
-!if $(VCVERSION) >= 1800
-OPTDEFINES = $(OPTDEFINES) /DHAVE_INTTYPES_H=1 /DHAVE_STDBOOL_H=1
!endif
+#----------------------------------------------------------
+# Set our defines now armed with our options.
+#----------------------------------------------------------
+
+OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) -DSTDC_HEADERS
+
!if $(TCL_MEM_DEBUG)
-OPTDEFINES = $(OPTDEFINES) /DTCL_MEM_DEBUG
+OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG
!endif
!if $(TCL_COMPILE_DEBUG)
-OPTDEFINES = $(OPTDEFINES) /DTCL_COMPILE_DEBUG /DTCL_COMPILE_STATS
+OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS
!endif
-!if $(TCL_THREADS) && $(TCL_VERSION) < 87
-OPTDEFINES = $(OPTDEFINES) /DTCL_THREADS=1
-!if $(USE_THREAD_ALLOC) && $(TCL_VERSION) < 87
-OPTDEFINES = $(OPTDEFINES) /DUSE_THREAD_ALLOC=1
+!if $(TCL_THREADS)
+OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1
+!if $(USE_THREAD_ALLOC)
+OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1
!endif
!endif
!if $(STATIC_BUILD)
-OPTDEFINES = $(OPTDEFINES) /DSTATIC_BUILD
-!elseif $(TCL_VERSION) > 86
-OPTDEFINES = $(OPTDEFINES) /DTCL_WITH_EXTERNAL_TOMMATH
-!if "$(MACHINE)" == "AMD64" || "$(MACHINE)" == "ARM64"
-OPTDEFINES = $(OPTDEFINES) /DMP_64BIT
-!endif
+OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD
!endif
!if $(TCL_NO_DEPRECATED)
-OPTDEFINES = $(OPTDEFINES) /DTCL_NO_DEPRECATED
-!endif
-
-!if $(USE_STUBS)
-# Note we do not define USE_TCL_STUBS even when building tk since some
-# test targets in tk do not use stubs
-!if !$(DOING_TCL)
-USE_STUBS_DEFS = /DUSE_TCL_STUBS /DUSE_TCLOO_STUBS
-!if $(NEED_TK)
-USE_STUBS_DEFS = $(USE_STUBS_DEFS) /DUSE_TK_STUBS
-!endif
+OPTDEFINES = $(OPTDEFINES) -DTCL_NO_DEPRECATED
!endif
-!endif # USE_STUBS
!if !$(DEBUG)
-OPTDEFINES = $(OPTDEFINES) /DNDEBUG
+OPTDEFINES = $(OPTDEFINES) -DNDEBUG
!if $(OPTIMIZING)
-OPTDEFINES = $(OPTDEFINES) /DTCL_CFG_OPTIMIZED
+OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED
!endif
!endif
!if $(PROFILE)
-OPTDEFINES = $(OPTDEFINES) /DTCL_CFG_PROFILED
+OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED
!endif
-!if "$(MACHINE)" == "AMD64" || "$(MACHINE)" == "ARM64"
-OPTDEFINES = $(OPTDEFINES) /DTCL_CFG_DO64BIT
+!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64"
+OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT
!endif
!if $(VCVERSION) < 1300
-OPTDEFINES = $(OPTDEFINES) /DNO_STRTOI64=1
+OPTDEFINES = $(OPTDEFINES) -DNO_STRTOI64
!endif
-!if $(TCL_MAJOR_VERSION) == 8
-!if "$(_USE_64BIT_TIME_T)" == "1"
-OPTDEFINES = $(OPTDEFINES) /D_USE_64BIT_TIME_T=1
-!endif
+#----------------------------------------------------------
+# Locate the Tcl headers to build against
+#----------------------------------------------------------
-# _ATL_XP_TARGETING - Newer SDK's need this to build for XP
-COMPILERFLAGS = /D_ATL_XP_TARGETING
-!endif
-!if "$(TCL_BUILD_FOR)" == "8"
-OPTDEFINES = $(OPTDEFINES) /DTCL_MAJOR_VERSION=8
-!endif
+!if "$(PROJECT)" == "tcl"
+
+_TCL_H = ..\generic\tcl.h
+
+!else
-# Like the TEA system only set this non empty for non-Tk extensions
-# Note: some extensions use PACKAGE_NAME and others use PACKAGE_TCLNAME
-# so we pass both
-!if !$(DOING_TCL) && !$(DOING_TK)
-PKGNAMEFLAGS = /DPACKAGE_NAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \
- /DPACKAGE_TCLNAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \
- /DPACKAGE_VERSION="\"$(DOTVERSION)\"" \
- /DMODULE_SCOPE=extern
+# If INSTALLDIR set to tcl root dir then reset to the lib dir.
+!if exist("$(_INSTALLDIR)\include\tcl.h")
+_INSTALLDIR=$(_INSTALLDIR)\lib
!endif
-# crt picks the C run time based on selected OPTS
-!if $(MSVCRT)
-!if $(DEBUG) && !$(UNCHECKED)
-crt = -MDd
+!if !defined(TCLDIR)
+!if exist("$(_INSTALLDIR)\..\include\tcl.h")
+TCLINSTALL = 1
+_TCLDIR = $(_INSTALLDIR)\..
+_TCL_H = $(_INSTALLDIR)\..\include\tcl.h
+TCLDIR = $(_INSTALLDIR)\..
!else
-crt = -MD
+MSG=^
+Failed to find tcl.h. Set the TCLDIR macro.
+!error $(MSG)
!endif
!else
-!if $(DEBUG) && !$(UNCHECKED)
-crt = -MTd
+_TCLDIR = $(TCLDIR:/=\)
+!if exist("$(_TCLDIR)\include\tcl.h")
+TCLINSTALL = 1
+_TCL_H = $(_TCLDIR)\include\tcl.h
+!elseif exist("$(_TCLDIR)\generic\tcl.h")
+TCLINSTALL = 0
+_TCL_H = $(_TCLDIR)\generic\tcl.h
!else
-crt = -MT
+MSG =^
+Failed to find tcl.h. The TCLDIR macro does not appear correct.
+!error $(MSG)
!endif
!endif
-
-# cdebug includes compiler options for debugging as well as optimization.
-!if $(DEBUG)
-
-# In debugging mode, optimizations need to be disabled
-cdebug = -Zi -Od $(DEBUGFLAGS)
-
-!else
-
-cdebug = $(OPTIMIZATIONS)
-!if $(SYMBOLS)
-cdebug = $(cdebug) -Zi
!endif
-!endif # $(DEBUG)
-
-# cwarn includes default warning levels, also C4090 (buggy) and C4146 is useless.
-cwarn = $(WARNINGS) -wd4090 -wd4146
+#--------------------------------------------------------------
+# Extract various version numbers from tcl headers
+# The generated file is then included in the makefile.
+#--------------------------------------------------------------
-!if "$(MACHINE)" == "AMD64" || "$(MACHINE)" == "ARM64"
-# Disable pointer<->int warnings related to cast between different sizes
-# There are a gadzillion of these due to use of ClientData and
-# clutter up compiler
-# output increasing chance of a real warning getting lost. So disable them.
-# Eventually some day, Tcl will be 64-bit clean.
-cwarn = $(cwarn) -wd4311 -wd4312
+!if [echo REM = This file is generated from rules.vc > versions.vc]
!endif
-
-### Common compiler options that are architecture specific
-!if "$(MACHINE)" == "ARM"
-carch = /D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
-!else
-carch =
+!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \
+ && [nmakehlp -V "$(_TCL_H)" TCL_MAJOR_VERSION >> versions.vc]
!endif
-
-# cpuid is only available on intel machines
-!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "AMD64"
-carch = $(carch) /DHAVE_CPUID=1
+!if [echo TCL_MINOR_VERSION = \>> versions.vc] \
+ && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc]
!endif
-
-!if $(DEBUG)
-# Turn warnings into errors
-cwarn = $(cwarn) -WX
+!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \
+ && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc]
!endif
-INCLUDES = $(TCL_INCLUDES) $(TK_INCLUDES) $(PRJ_INCLUDES)
-!if !$(DOING_TCL) && !$(DOING_TK)
-INCLUDES = $(INCLUDES) -I"$(GENERICDIR)" -I"$(WIN_DIR)" -I"$(COMPATDIR)"
+# If building the tcl core then we need additional package versions
+!if "$(PROJECT)" == "tcl"
+!if [echo PKG_HTTP_VER = \>> versions.vc] \
+ && [nmakehlp -V ..\library\http\pkgIndex.tcl http >> versions.vc]
!endif
-
-# These flags are defined roughly in the order of the pre-reform
-# rules.vc/makefile.vc to help visually compare that the pre- and
-# post-reform build logs
-
-# cflags contains generic flags used for building practically all object files
-cflags = -nologo -c $(COMPILERFLAGS) $(carch) $(cwarn) -Fp$(TMP_DIR)^\ $(cdebug)
-
-!if $(TCL_MAJOR_VERSION) == 8 && $(TCL_MINOR_VERSION) < 7
-cflags = $(cflags) -DTcl_Size=int
+!if [echo PKG_TCLTEST_VER = \>> versions.vc] \
+ && [nmakehlp -V ..\library\tcltest\pkgIndex.tcl tcltest >> versions.vc]
!endif
-
-# appcflags contains $(cflags) and flags for building the application
-# object files (e.g. tclsh, or wish) pkgcflags contains $(cflags) plus
-# flags used for building shared object files The two differ in the
-# BUILD_$(PROJECT) macro which should be defined only for the shared
-# library *implementation* and not for its caller interface
-
-appcflags_nostubs = $(cflags) $(crt) $(INCLUDES) $(TCL_DEFINES) $(PRJ_DEFINES) $(OPTDEFINES)
-appcflags = $(appcflags_nostubs) $(USE_STUBS_DEFS)
-pkgcflags = $(appcflags) $(PKGNAMEFLAGS) /DBUILD_$(PROJECT)
-pkgcflags_nostubs = $(appcflags_nostubs) $(PKGNAMEFLAGS) /DBUILD_$(PROJECT)
-
-# stubscflags contains $(cflags) plus flags used for building a stubs
-# library for the package. Note: /DSTATIC_BUILD is defined in
-# $(OPTDEFINES) only if the OPTS configuration indicates a static
-# library. However the stubs library is ALWAYS static hence included
-# here irrespective of the OPTS setting.
-#
-# TBD - tclvfs has a comment that stubs libs should not be compiled with -GL
-# without stating why. Tcl itself compiled stubs libs with this flag.
-# so we do not remove it from cflags. -GL may prevent extensions
-# compiled with one VC version to fail to link against stubs library
-# compiled with another VC version. Check for this and fix accordingly.
-stubscflags = $(cflags) $(PKGNAMEFLAGS) $(PRJ_DEFINES) $(OPTDEFINES) /Zl /GL- /DSTATIC_BUILD $(INCLUDES) $(USE_STUBS_DEFS)
-
-# Link flags
-
-!if $(DEBUG)
-ldebug = -debug -debugtype:cv
-!else
-ldebug = -release -opt:ref -opt:icf,3
-!if $(SYMBOLS)
-ldebug = $(ldebug) -debug -debugtype:cv
+!if [echo PKG_MSGCAT_VER = \>> versions.vc] \
+ && [nmakehlp -V ..\library\msgcat\pkgIndex.tcl msgcat >> versions.vc]
!endif
+!if [echo PKG_PLATFORM_VER = \>> versions.vc] \
+ && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform " >> versions.vc]
+!endif
+!if [echo PKG_SHELL_VER = \>> versions.vc] \
+ && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform::shell" >> versions.vc]
+!endif
+!if [echo PKG_DDE_VER = \>> versions.vc] \
+ && [nmakehlp -V ..\library\dde\pkgIndex.tcl "dde " >> versions.vc]
+!endif
+!if [echo PKG_REG_VER =\>> versions.vc] \
+ && [nmakehlp -V ..\library\reg\pkgIndex.tcl registry >> versions.vc]
!endif
-
-# Note: Profiling is currently only possible with the Visual Studio Enterprise
-!if $(PROFILE)
-ldebug= $(ldebug) -profile
!endif
-### Declarations common to all linker versions
-lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug)
+!include versions.vc
-!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900
-lflags = $(lflags) -nodefaultlib:libucrt.lib
-!endif
+#--------------------------------------------------------------
+# Setup tcl version dependent stuff headers
+#--------------------------------------------------------------
-dlllflags = $(lflags) -dll
-conlflags = $(lflags) -subsystem:console
-guilflags = $(lflags) -subsystem:windows
+!if "$(PROJECT)" != "tcl"
-# Libraries that are required for every image.
-# Extensions should define any additional libraries with $(PRJ_LIBS)
-winlibs = kernel32.lib advapi32.lib
+TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION)
-!if $(NEED_TK)
-winlibs = $(winlibs) gdi32.lib user32.lib uxtheme.lib
+!if $(TCLINSTALL)
+TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe"
+!if !exist($(TCLSH)) && $(TCL_THREADS)
+TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX).exe"
!endif
-
-# Avoid 'unresolved external symbol __security_cookie' errors.
-# c.f. http://support.microsoft.com/?id=894573
-!if "$(MACHINE)" == "AMD64"
-!if $(VCVERSION) > 1399 && $(VCVERSION) < 1500
-winlibs = $(winlibs) bufferoverflowU.lib
+TCLSTUBLIB = "$(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib"
+TCLIMPLIB = "$(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib"
+TCL_LIBRARY = $(_TCLDIR)\lib
+TCLREGLIB = "$(_TCLDIR)\lib\tclreg12$(SUFX:t=).lib"
+TCLDDELIB = "$(_TCLDIR)\lib\tcldde13$(SUFX:t=).lib"
+COFFBASE = \must\have\tcl\sources\to\build\this\target
+TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target
+TCL_INCLUDES = -I"$(_TCLDIR)\include"
+!else
+TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe"
+!if !exist($(TCLSH)) && $(TCL_THREADS)
+TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX).exe"
!endif
+TCLSTUBLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib"
+TCLIMPLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib"
+TCL_LIBRARY = $(_TCLDIR)\library
+TCLREGLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg12$(SUFX:t=).lib"
+TCLDDELIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde13$(SUFX:t=).lib"
+COFFBASE = "$(_TCLDIR)\win\coffbase.txt"
+TCLTOOLSDIR = $(_TCLDIR)\tools
+TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win"
!endif
-baselibs = $(winlibs) $(PRJ_LIBS)
-
-!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900
-baselibs = $(baselibs) ucrt.lib
!endif
-################################################################
-# 13. Define standard commands, common make targets and implicit rules
+#-------------------------------------------------------------------------
+# Locate the Tk headers to build against
+#-------------------------------------------------------------------------
-CCPKGCMD = $(cc32) $(pkgcflags) -Fo$(TMP_DIR)^\
-CCAPPCMD = $(cc32) $(appcflags) -Fo$(TMP_DIR)^\
-CCSTUBSCMD = $(cc32) $(stubscflags) -Fo$(TMP_DIR)^\
-
-LIBCMD = $(lib32) -nologo $(LINKERFLAGS) -out:$@
-DLLCMD = $(link32) $(dlllflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs)
-
-CONEXECMD = $(link32) $(conlflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs)
-GUIEXECMD = $(link32) $(guilflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs)
-RESCMD = $(rc32) -fo $@ -r -i "$(GENERICDIR)" -i "$(TMP_DIR)" \
- $(TCL_INCLUDES) /DSTATIC_BUILD=$(STATIC_BUILD) \
- /DDEBUG=$(DEBUG) -d UNCHECKED=$(UNCHECKED) \
- /DCOMMAVERSION=$(RCCOMMAVERSION) \
- /DDOTVERSION=\"$(DOTVERSION)\" \
- /DVERSION=\"$(VERSION)\" \
- /DSUFX=\"$(SUFX)\" \
- /DPROJECT=\"$(PROJECT)\" \
- /DPRJLIBNAME=\"$(PRJLIBNAME)\"
-
-!ifndef DEFAULT_BUILD_TARGET
-DEFAULT_BUILD_TARGET = $(PROJECT)
+!if "$(PROJECT)" == "tk"
+_TK_H = ..\generic\tk.h
+_INSTALLDIR = $(_INSTALLDIR)\..
!endif
-default-target: $(DEFAULT_BUILD_TARGET)
-
-!if $(MULTIPLATFORM_INSTALL)
-default-pkgindex:
- @echo if {[package vsatisfies [package provide Tcl] 9.0-]} { > $(OUT_DIR)\pkgIndex.tcl
- @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
- [list load [file join $$dir $(PLATFORM_IDENTIFY) $(PRJLIBNAME9)]] >> $(OUT_DIR)\pkgIndex.tcl
- @echo } else { >> $(OUT_DIR)\pkgIndex.tcl
- @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
- [list load [file join $$dir $(PLATFORM_IDENTIFY) $(PRJLIBNAME8)]] >> $(OUT_DIR)\pkgIndex.tcl
- @echo } >> $(OUT_DIR)\pkgIndex.tcl
+!ifdef PROJECT_REQUIRES_TK
+!if !defined(TKDIR)
+!if exist("$(_INSTALLDIR)\..\include\tk.h")
+TKINSTALL = 1
+_TKDIR = $(_INSTALLDIR)\..
+_TK_H = $(_TKDIR)\include\tk.h
+TKDIR = $(_TKDIR)
+!elseif exist("$(_TCLDIR)\include\tk.h")
+TKINSTALL = 1
+_TKDIR = $(_TCLDIR)
+_TK_H = $(_TKDIR)\include\tk.h
+TKDIR = $(_TKDIR)
+!endif
!else
-default-pkgindex:
- @echo if {[package vsatisfies [package provide Tcl] 9.0-]} { > $(OUT_DIR)\pkgIndex.tcl
- @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
- [list load [file join $$dir $(PRJLIBNAME9)]] >> $(OUT_DIR)\pkgIndex.tcl
- @echo } else { >> $(OUT_DIR)\pkgIndex.tcl
- @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
- [list load [file join $$dir $(PRJLIBNAME8)]] >> $(OUT_DIR)\pkgIndex.tcl
- @echo } >> $(OUT_DIR)\pkgIndex.tcl
-!endif
-
-default-pkgindex-tea:
- @if exist $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $(ROOT)\pkgIndex.tcl.in > $(OUT_DIR)\pkgIndex.tcl
-@PACKAGE_VERSION@ $(DOTVERSION)
-@PACKAGE_NAME@ $(PRJ_PACKAGE_TCLNAME)
-@PACKAGE_TCLNAME@ $(PRJ_PACKAGE_TCLNAME)
-@PKG_LIB_FILE@ $(PRJLIBNAME)
-@PKG_LIB_FILE8@ $(PRJLIBNAME8)
-@PKG_LIB_FILE9@ $(PRJLIBNAME9)
-<<
-
-default-install: default-install-binaries default-install-libraries
-!if $(SYMBOLS)
-default-install: default-install-pdbs
-!endif
-
-# Again to deal with historical brokenness, there is some confusion
-# in terminlogy. For extensions, the "install-binaries" was used to
-# locate target directory for *binary shared libraries* and thus
-# the appropriate macro is LIB_INSTALL_DIR since BIN_INSTALL_DIR is
-# for executables (exes). On the other hand the "install-libraries"
-# target is for *scripts* and should have been called "install-scripts".
-default-install-binaries: $(PRJLIB)
- @echo Installing binaries to '$(LIB_INSTALL_DIR)'
- @if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)"
- @$(CPY) $(PRJLIB) "$(LIB_INSTALL_DIR)" >NUL
-
-# Alias for default-install-scripts
-default-install-libraries: default-install-scripts
-
-default-install-scripts: $(OUT_DIR)\pkgIndex.tcl
- @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)'
- @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)"
- @echo Installing package index in '$(SCRIPT_INSTALL_DIR)'
- @$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR)
-
-default-install-stubs:
- @echo Installing stubs library to '$(SCRIPT_INSTALL_DIR)'
- @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
- @$(CPY) $(PRJSTUBLIB) "$(SCRIPT_INSTALL_DIR)" >NUL
-
-default-install-pdbs:
- @echo Installing PDBs to '$(LIB_INSTALL_DIR)'
- @if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)"
- @$(CPY) "$(OUT_DIR)\*.pdb" "$(LIB_INSTALL_DIR)\"
-
-# "emacs font-lock highlighting fix
-
-default-install-docs-html:
- @echo Installing documentation files to '$(DOC_INSTALL_DIR)'
- @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)"
- @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.html" "$(DOCDIR)\*.css" "$(DOCDIR)\*.png") do @$(COPY) %f "$(DOC_INSTALL_DIR)"
-
-default-install-docs-n:
- @echo Installing documentation files to '$(DOC_INSTALL_DIR)'
- @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)"
- @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.n") do @$(COPY) %f "$(DOC_INSTALL_DIR)"
-
-default-install-demos:
- @echo Installing demos to '$(DEMO_INSTALL_DIR)'
- @if not exist "$(DEMO_INSTALL_DIR)" mkdir "$(DEMO_INSTALL_DIR)"
- @if exist $(DEMODIR) $(CPYDIR) "$(DEMODIR)" "$(DEMO_INSTALL_DIR)"
-
-default-clean:
- @echo Cleaning $(TMP_DIR)\* ...
- @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR)
- @echo Cleaning $(WIN_DIR)\nmakehlp.obj, nmakehlp.exe ...
- @if exist $(WIN_DIR)\nmakehlp.obj del $(WIN_DIR)\nmakehlp.obj
- @if exist $(WIN_DIR)\nmakehlp.exe del $(WIN_DIR)\nmakehlp.exe
- @if exist $(WIN_DIR)\nmakehlp.out del $(WIN_DIR)\nmakehlp.out
- @echo Cleaning $(WIN_DIR)\nmhlp-out.txt ...
- @if exist $(WIN_DIR)\nmhlp-out.txt del $(WIN_DIR)\nmhlp-out.txt
- @echo Cleaning $(WIN_DIR)\_junk.pch ...
- @if exist $(WIN_DIR)\_junk.pch del $(WIN_DIR)\_junk.pch
- @echo Cleaning $(WIN_DIR)\vercl.x, vercl.i ...
- @if exist $(WIN_DIR)\vercl.x del $(WIN_DIR)\vercl.x
- @if exist $(WIN_DIR)\vercl.i del $(WIN_DIR)\vercl.i
- @echo Cleaning $(WIN_DIR)\versions.vc, version.vc ...
- @if exist $(WIN_DIR)\versions.vc del $(WIN_DIR)\versions.vc
- @if exist $(WIN_DIR)\version.vc del $(WIN_DIR)\version.vc
-
-default-hose: default-clean
- @echo Hosing $(OUT_DIR)\* ...
- @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR)
-
-# Only for backward compatibility
-default-distclean: default-hose
-
-default-setup:
- @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR)
- @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR)
-
-!if "$(TESTPAT)" != ""
-TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT)
-!endif
-
-default-test: default-setup $(PROJECT)
- @set TCLLIBPATH=$(OUT_DIR:\=/)
- @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)"
- cd "$(TESTDIR)" && $(DEBUGGER) $(TCLSH) all.tcl $(TESTFLAGS)
-
-default-shell: default-setup $(PROJECT)
- @set TCLLIBPATH=$(OUT_DIR:\=/)
- @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)"
- $(DEBUGGER) $(TCLSH)
-
-# Generation of Windows version resource
-!ifdef RCFILE
-
-# Note: don't use $** in below rule because there may be other dependencies
-# and only the "main" rc must be passed to the resource compiler
-$(TMP_DIR)\$(PROJECT).res: $(RCDIR)\$(PROJECT).rc
- $(RESCMD) $(RCDIR)\$(PROJECT).rc
-
+_TKDIR = $(TKDIR:/=\)
+!if exist("$(_TKDIR)\include\tk.h")
+TKINSTALL = 1
+_TK_H = $(_TKDIR)\include\tk.h
+!elseif exist("$(_TKDIR)\generic\tk.h")
+TKINSTALL = 0
+_TK_H = $(_TKDIR)\generic\tk.h
!else
-
-# If parent makefile has not defined a resource definition file,
-# we will generate one from standard template.
-$(TMP_DIR)\$(PROJECT).res: $(TMP_DIR)\$(PROJECT).rc
-
-$(TMP_DIR)\$(PROJECT).rc:
- @$(COPY) << $(TMP_DIR)\$(PROJECT).rc
-#include <winver.h>
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION COMMAVERSION
- PRODUCTVERSION COMMAVERSION
- FILEFLAGSMASK 0x3fL
-#ifdef DEBUG
- FILEFLAGS VS_FF_DEBUG
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS VOS_NT_WINDOWS32
- FILETYPE VFT_DLL
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "FileDescription", "Tcl extension " PROJECT
- VALUE "OriginalFilename", PRJLIBNAME
- VALUE "FileVersion", DOTVERSION
- VALUE "ProductName", "Package " PROJECT " for Tcl"
- VALUE "ProductVersion", DOTVERSION
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-<<
-
-!endif # ifdef RCFILE
-
-!ifndef DISABLE_IMPLICIT_RULES
-DISABLE_IMPLICIT_RULES = 0
+MSG =^
+Failed to find tk.h. The TKDIR macro does not appear correct.
+!error $(MSG)
+!endif
+!endif
!endif
-!if !$(DISABLE_IMPLICIT_RULES)
-# Implicit rule definitions - only for building library objects. For stubs and
-# main application, the makefile should define explicit rules.
-
-{$(ROOT)}.c{$(TMP_DIR)}.obj::
- $(CCPKGCMD) @<<
-$<
-<<
-
-{$(WIN_DIR)}.c{$(TMP_DIR)}.obj::
- $(CCPKGCMD) @<<
-$<
-<<
-
-{$(GENERICDIR)}.c{$(TMP_DIR)}.obj::
- $(CCPKGCMD) @<<
-$<
-<<
-
-{$(COMPATDIR)}.c{$(TMP_DIR)}.obj::
- $(CCPKGCMD) @<<
-$<
-<<
-
-{$(RCDIR)}.rc{$(TMP_DIR)}.res:
- $(RESCMD) $<
-
-{$(WIN_DIR)}.rc{$(TMP_DIR)}.res:
- $(RESCMD) $<
-
-{$(TMP_DIR)}.rc{$(TMP_DIR)}.res:
- $(RESCMD) $<
+#-------------------------------------------------------------------------
+# Extract Tk version numbers
+#-------------------------------------------------------------------------
-.SUFFIXES:
-.SUFFIXES:.c .rc
+!if defined(PROJECT_REQUIRES_TK) || "$(PROJECT)" == "tk"
+!if [echo TK_MAJOR_VERSION = \>> versions.vc] \
+ && [nmakehlp -V $(_TK_H) TK_MAJOR_VERSION >> versions.vc]
!endif
-
-################################################################
-# 14. Sanity check selected options against Tcl build options
-# When building an extension, certain configuration options should
-# match the ones used when Tcl was built. Here we check and
-# warn on a mismatch.
-!if !$(DOING_TCL)
-
-!if $(TCLINSTALL) # Building against an installed Tcl
-!if exist("$(_TCLDIR)\lib\nmake\tcl.nmake")
-TCLNMAKECONFIG = "$(_TCLDIR)\lib\nmake\tcl.nmake"
+!if [echo TK_MINOR_VERSION = \>> versions.vc] \
+ && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc]
!endif
-!else # !$(TCLINSTALL) - building against Tcl source
-!if exist("$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl.nmake")
-TCLNMAKECONFIG = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl.nmake"
+!if [echo TK_PATCH_LEVEL = \>> versions.vc] \
+ && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc]
!endif
-!endif # TCLINSTALL
-!if $(CONFIG_CHECK)
-!ifdef TCLNMAKECONFIG
-!include $(TCLNMAKECONFIG)
+!include versions.vc
-!if defined(CORE_MACHINE) && "$(CORE_MACHINE)" != "$(MACHINE)"
-!error ERROR: Build target ($(MACHINE)) does not match the Tcl library architecture ($(CORE_MACHINE)).
-!endif
-!if $(TCL_VERSION) < 87 && defined(CORE_USE_THREAD_ALLOC) && $(CORE_USE_THREAD_ALLOC) != $(USE_THREAD_ALLOC)
-!message WARNING: Value of USE_THREAD_ALLOC ($(USE_THREAD_ALLOC)) does not match its Tcl core value ($(CORE_USE_THREAD_ALLOC)).
-!endif
-!if defined(CORE_DEBUG) && $(CORE_DEBUG) != $(DEBUG)
-!message WARNING: Value of DEBUG ($(DEBUG)) does not match its Tcl library configuration ($(DEBUG)).
+TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)
+TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION)
+
+!if "$(PROJECT)" != "tk"
+!if $(TKINSTALL)
+WISH = "$(_TKDIR)\bin\wish$(TK_VERSION)$(SUFX).exe"
+TKSTUBLIB = "$(_TKDIR)\lib\tkstub$(TK_VERSION).lib"
+TKIMPLIB = "$(_TKDIR)\lib\tk$(TK_VERSION)$(SUFX).lib"
+TK_INCLUDES = -I"$(_TKDIR)\include"
+!else
+WISH = "$(_TKDIR)\win\$(BUILDDIRTOP)\wish$(TCL_VERSION)$(SUFX).exe"
+TKSTUBLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tkstub$(TCL_VERSION).lib"
+TKIMPLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tk$(TCL_VERSION)$(SUFX).lib"
+TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib"
!endif
!endif
-!endif # TCLNMAKECONFIG
-
-!endif # !$(DOING_TCL)
-
+!endif
#----------------------------------------------------------
# Display stats being used.
#----------------------------------------------------------
-!if !$(DOING_TCL)
-!message *** Building against Tcl at '$(_TCLDIR)'
-!endif
-!if !$(DOING_TK) && $(NEED_TK)
-!message *** Building against Tk at '$(_TKDIR)'
-!endif
!message *** Intermediate directory will be '$(TMP_DIR)'
!message *** Output directory will be '$(OUT_DIR)'
-!message *** Installation, if selected, will be in '$(_INSTALLDIR)'
!message *** Suffix for binaries will be '$(SUFX)'
-!message *** Compiler version $(VCVER). Target $(MACHINE), host $(NATIVE_ARCH).
+!message *** Optional defines are '$(OPTDEFINES)'
+!message *** Compiler version $(VCVER). Target machine is $(MACHINE)
+!message *** Host architecture is $(NATIVE_ARCH)
+!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)'
+!message *** Link options '$(LINKERFLAGS)'
-!endif # ifdef _RULES_VC
+!endif
diff --git a/win/stub16.c b/win/stub16.c
new file mode 100644
index 0000000..70fc051
--- /dev/null
+++ b/win/stub16.c
@@ -0,0 +1,195 @@
+/*
+ * stub16.c
+ *
+ * A helper program used for running 16-bit DOS applications under
+ * Windows 95.
+ *
+ * Copyright (c) 1996 by Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#define STRICT
+
+#include <windows.h>
+#include <stdio.h>
+
+static HANDLE CreateTempFile(void);
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * main
+ *
+ * Entry point for the 32-bit console mode app used by Windows 95 to help
+ * run the 16-bit program specified on the command line.
+ *
+ * 1. EOF on a pipe that connects a detached 16-bit process and a 32-bit
+ * process is never seen. So, this process runs the 16-bit process
+ * _attached_, and then it is run detached from the calling 32-bit
+ * process.
+ *
+ * 2. If a 16-bit process blocks reading from or writing to a pipe, it
+ * never wakes up, and eventually brings the whole system down with it if
+ * you try to kill the process. This app simulates pipes. If any of the
+ * stdio handles is a pipe, this program accumulates information into
+ * temp files and forwards it to or from the DOS application as
+ * appropriate. This means that this program must receive EOF from a
+ * stdin pipe before it will actually start the DOS app, and the DOS app
+ * must finish generating stdout or stderr before the data will be sent
+ * to the next stage of the pipe. If the stdio handles are not pipes, no
+ * accumulation occurs and the data is passed straight through to and
+ * from the DOS application.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The child process is created and this process waits for it to
+ * complete.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+main(void)
+{
+ DWORD dwRead, dwWrite;
+ char *cmdLine;
+ HANDLE hStdInput, hStdOutput, hStdError;
+ HANDLE hFileInput, hFileOutput, hFileError;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ char buf[8192];
+ DWORD result;
+
+ hFileInput = INVALID_HANDLE_VALUE;
+ hFileOutput = INVALID_HANDLE_VALUE;
+ hFileError = INVALID_HANDLE_VALUE;
+ result = 1;
+
+ /*
+ * Don't get command line from argc, argv, because the command line
+ * tokenizer will have stripped off all the escape sequences needed for
+ * quotes and backslashes, and then we'd have to put them all back in
+ * again. Get the raw command line and parse off what we want ourselves.
+ * The command line should be of the form:
+ *
+ * stub16.exe program arg1 arg2 ...
+ */
+
+ cmdLine = strchr(GetCommandLine(), ' ');
+ if (cmdLine == NULL) {
+ return 1;
+ }
+ cmdLine++;
+
+ hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+ if (GetFileType(hStdInput) == FILE_TYPE_PIPE) {
+ hFileInput = CreateTempFile();
+ if (hFileInput == INVALID_HANDLE_VALUE) {
+ goto cleanup;
+ }
+ while (ReadFile(hStdInput, buf, sizeof(buf), &dwRead, NULL) != FALSE) {
+ if (dwRead == 0) {
+ break;
+ }
+ if (WriteFile(hFileInput, buf, dwRead, &dwWrite, NULL) == FALSE) {
+ goto cleanup;
+ }
+ }
+ SetFilePointer(hFileInput, 0, 0, FILE_BEGIN);
+ SetStdHandle(STD_INPUT_HANDLE, hFileInput);
+ }
+ if (GetFileType(hStdOutput) == FILE_TYPE_PIPE) {
+ hFileOutput = CreateTempFile();
+ if (hFileOutput == INVALID_HANDLE_VALUE) {
+ goto cleanup;
+ }
+ SetStdHandle(STD_OUTPUT_HANDLE, hFileOutput);
+ }
+ if (GetFileType(hStdError) == FILE_TYPE_PIPE) {
+ hFileError = CreateTempFile();
+ if (hFileError == INVALID_HANDLE_VALUE) {
+ goto cleanup;
+ }
+ SetStdHandle(STD_ERROR_HANDLE, hFileError);
+ }
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ if (CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si,
+ &pi) == FALSE) {
+ goto cleanup;
+ }
+
+ WaitForInputIdle(pi.hProcess, 5000);
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ GetExitCodeProcess(pi.hProcess, &result);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ if (hFileOutput != INVALID_HANDLE_VALUE) {
+ SetFilePointer(hFileOutput, 0, 0, FILE_BEGIN);
+ while (ReadFile(hFileOutput, buf, sizeof(buf), &dwRead, NULL) != FALSE) {
+ if (dwRead == 0) {
+ break;
+ }
+ if (WriteFile(hStdOutput, buf, dwRead, &dwWrite, NULL) == FALSE) {
+ break;
+ }
+ }
+ }
+ if (hFileError != INVALID_HANDLE_VALUE) {
+ SetFilePointer(hFileError, 0, 0, FILE_BEGIN);
+ while (ReadFile(hFileError, buf, sizeof(buf), &dwRead, NULL) != FALSE) {
+ if (dwRead == 0) {
+ break;
+ }
+ if (WriteFile(hStdError, buf, dwRead, &dwWrite, NULL) == FALSE) {
+ break;
+ }
+ }
+ }
+
+ cleanup:
+ if (hFileInput != INVALID_HANDLE_VALUE) {
+ CloseHandle(hFileInput);
+ }
+ if (hFileOutput != INVALID_HANDLE_VALUE) {
+ CloseHandle(hFileOutput);
+ }
+ if (hFileError != INVALID_HANDLE_VALUE) {
+ CloseHandle(hFileError);
+ }
+ CloseHandle(hStdInput);
+ CloseHandle(hStdOutput);
+ CloseHandle(hStdError);
+ ExitProcess(result);
+ return 1;
+}
+
+static HANDLE
+CreateTempFile(void)
+{
+ char name[MAX_PATH];
+ SECURITY_ATTRIBUTES sa;
+
+ if (GetTempPath(sizeof(name), name) == 0) {
+ return INVALID_HANDLE_VALUE;
+ }
+ if (GetTempFileName(name, "tcl", 0, name) == 0) {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+ return CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sa,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+ NULL);
+}
diff --git a/win/svnmanifest.in b/win/svnmanifest.in
deleted file mode 100644
index 18d2cad..0000000
--- a/win/svnmanifest.in
+++ /dev/null
@@ -1 +0,0 @@
-svn-r \ No newline at end of file
diff --git a/win/targets.vc b/win/targets.vc
deleted file mode 100644
index 077e8f7..0000000
--- a/win/targets.vc
+++ /dev/null
@@ -1,98 +0,0 @@
-#------------------------------------------------------------- -*- makefile -*-
-# targets.vc --
-#
-# Part of the nmake based build system for Tcl and its extensions.
-# This file defines some standard targets for the convenience of extensions
-# and can be optionally included by the extension makefile.
-# See TIP 477 (https://core.tcl-lang.org/tips/doc/main/tip/477.md) for docs.
-
-$(PROJECT): setup pkgindex $(PRJLIB)
-
-!ifdef PRJ_STUBOBJS
-$(PROJECT): $(PRJSTUBLIB)
-$(PRJSTUBLIB): $(PRJ_STUBOBJS)
- $(LIBCMD) $**
-
-$(PRJ_STUBOBJS):
- $(CCSTUBSCMD) %s
-!endif # PRJ_STUBOBJS
-
-!ifdef PRJ_MANIFEST
-$(PROJECT): $(PRJLIB).manifest
-$(PRJLIB).manifest: $(PRJ_MANIFEST)
- @nmakehlp -s << $** >$@
-@MACHINE@ $(MACHINE:IX86=X86)
-<<
-!endif
-
-!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk"
-$(PRJLIB): $(PRJ_OBJS) $(RESFILE)
-!if $(STATIC_BUILD)
- $(LIBCMD) $**
-!else
- $(DLLCMD) $**
- $(_VC_MANIFEST_EMBED_DLL)
-!endif
- -@del $*.exp
-!endif
-
-!if "$(PRJ_HEADERS)" != "" && "$(PRJ_OBJS)" != ""
-$(PRJ_OBJS): $(PRJ_HEADERS)
-!endif
-
-# If parent makefile has defined stub objects, add their installation
-# to the default install
-!if "$(PRJ_STUBOBJS)" != ""
-default-install: default-install-stubs
-!endif
-
-# Unlike the other default targets, these cannot be in rules.vc because
-# the executed command depends on existence of macro PRJ_HEADERS_PUBLIC
-# that the parent makefile will not define until after including rules-ext.vc
-!if "$(PRJ_HEADERS_PUBLIC)" != ""
-default-install: default-install-headers
-default-install-headers:
- @echo Installing headers to '$(INCLUDE_INSTALL_DIR)'
- @for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)"
-!endif
-
-!if "$(DISABLE_STANDARD_TARGETS)" == ""
-DISABLE_STANDARD_TARGETS = 0
-!endif
-
-!if "$(DISABLE_TARGET_setup)" == ""
-DISABLE_TARGET_setup = 0
-!endif
-!if "$(DISABLE_TARGET_install)" == ""
-DISABLE_TARGET_install = 0
-!endif
-!if "$(DISABLE_TARGET_clean)" == ""
-DISABLE_TARGET_clean = 0
-!endif
-!if "$(DISABLE_TARGET_test)" == ""
-DISABLE_TARGET_test = 0
-!endif
-!if "$(DISABLE_TARGET_shell)" == ""
-DISABLE_TARGET_shell = 0
-!endif
-
-!if !$(DISABLE_STANDARD_TARGETS)
-!if !$(DISABLE_TARGET_setup)
-setup: default-setup
-!endif
-!if !$(DISABLE_TARGET_install)
-install: default-install
-!endif
-!if !$(DISABLE_TARGET_clean)
-clean: default-clean
-realclean: hose
-hose: default-hose
-distclean: realclean default-distclean
-!endif
-!if !$(DISABLE_TARGET_test)
-test: default-test
-!endif
-!if !$(DISABLE_TARGET_shell)
-shell: default-shell
-!endif
-!endif # DISABLE_STANDARD_TARGETS
diff --git a/win/tcl.dsp b/win/tcl.dsp
index d033560..68920ad 100644
--- a/win/tcl.dsp
+++ b/win/tcl.dsp
@@ -34,18 +34,18 @@ CFG=tcl - Win32 Debug Static
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release\tcl_Dynamic"
-# PROP BASE Cmd_Line "nmake -nologo -f makefile.vc MSVCDIR=IDE"
+# PROP BASE Cmd_Line "nmake -nologo -f makefile.vc OPTS=none MSVCDIR=IDE"
# PROP BASE Rebuild_Opt "-a"
-# PROP BASE Target_File "Release\tclsh87.exe"
+# PROP BASE Target_File "Release\tclsh85.exe"
# PROP BASE Bsc_Name ""
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release\tcl_Dynamic"
-# PROP Cmd_Line "nmake -nologo -f makefile.vc MSVCDIR=IDE"
+# PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=threads MSVCDIR=IDE"
# PROP Rebuild_Opt "clean release"
-# PROP Target_File "Release\tclsh87t.exe"
+# PROP Target_File "Release\tclsh85t.exe"
# PROP Bsc_Name ""
# PROP Target_Dir ""
@@ -57,7 +57,7 @@ CFG=tcl - Win32 Debug Static
# PROP BASE Intermediate_Dir "Debug\tcl_Dynamic"
# PROP BASE Cmd_Line "nmake -nologo -f makefile.vc OPTS=symbols MSVCDIR=IDE"
# PROP BASE Rebuild_Opt "-a"
-# PROP BASE Target_File "Debug\tclsh87g.exe"
+# PROP BASE Target_File "Debug\tclsh85g.exe"
# PROP BASE Bsc_Name ""
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
@@ -66,7 +66,7 @@ CFG=tcl - Win32 Debug Static
# PROP Intermediate_Dir "Debug\tcl_Dynamic"
# PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=threads,symbols MSVCDIR=IDE"
# PROP Rebuild_Opt "clean release"
-# PROP Target_File "Debug\tclsh87tg.exe"
+# PROP Target_File "Debug\tclsh85tg.exe"
# PROP Bsc_Name ""
# PROP Target_Dir ""
@@ -78,7 +78,7 @@ CFG=tcl - Win32 Debug Static
# PROP BASE Intermediate_Dir "Debug\tcl_Static"
# PROP BASE Cmd_Line "nmake -nologo -f makefile.vc OPTS=symbols,static MSVCDIR=IDE"
# PROP BASE Rebuild_Opt "-a"
-# PROP BASE Target_File "Debug\tclsh87sg.exe"
+# PROP BASE Target_File "Debug\tclsh85sg.exe"
# PROP BASE Bsc_Name ""
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
@@ -87,7 +87,7 @@ CFG=tcl - Win32 Debug Static
# PROP Intermediate_Dir "Debug\tcl_Static"
# PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=symbols,static MSVCDIR=IDE"
# PROP Rebuild_Opt "-a"
-# PROP Target_File "Debug\tclsh87sg.exe"
+# PROP Target_File "Debug\tclsh85sg.exe"
# PROP Bsc_Name ""
# PROP Target_Dir ""
@@ -99,7 +99,7 @@ CFG=tcl - Win32 Debug Static
# PROP BASE Intermediate_Dir "Release\tcl_Static"
# PROP BASE Cmd_Line "nmake -nologo -f makefile.vc OPTS=static MSVCDIR=IDE"
# PROP BASE Rebuild_Opt "-a"
-# PROP BASE Target_File "Release\tclsh87s.exe"
+# PROP BASE Target_File "Release\tclsh85s.exe"
# PROP BASE Bsc_Name ""
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
@@ -108,7 +108,7 @@ CFG=tcl - Win32 Debug Static
# PROP Intermediate_Dir "Release\tcl_Static"
# PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=static MSVCDIR=IDE"
# PROP Rebuild_Opt "-a"
-# PROP Target_File "Release\tclsh87s.exe"
+# PROP Target_File "Release\tclsh85s.exe"
# PROP Bsc_Name ""
# PROP Target_Dir ""
@@ -136,10 +136,26 @@ CFG=tcl - Win32 Debug Static
# PROP Default_Filter ""
# Begin Source File
+SOURCE=..\compat\dirent.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\dirent2.h
+# End Source File
+# Begin Source File
+
SOURCE=..\compat\dlfcn.h
# End Source File
# Begin Source File
+SOURCE=..\compat\fixstrtod.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\float.h
+# End Source File
+# Begin Source File
+
SOURCE=..\compat\gettod.c
# End Source File
# Begin Source File
@@ -148,12 +164,56 @@ SOURCE=..\compat\limits.h
# End Source File
# Begin Source File
+SOURCE=..\compat\memcmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\opendir.c
+# End Source File
+# Begin Source File
+
SOURCE=..\compat\README
# End Source File
# Begin Source File
+SOURCE=..\compat\stdlib.h
+# End Source File
+# Begin Source File
+
SOURCE=..\compat\string.h
# End Source File
+# Begin Source File
+
+SOURCE=..\compat\strncasecmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\strstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\strtod.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\strtol.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\strtoul.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\tclErrno.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\unistd.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\compat\waitpid.c
+# End Source File
# End Group
# Begin Group "doc"
@@ -232,6 +292,10 @@ SOURCE=..\doc\CallDel.3
# End Source File
# Begin Source File
+SOURCE=..\doc\case.n
+# End Source File
+# Begin Source File
+
SOURCE=..\doc\catch.n
# End Source File
# Begin Source File
@@ -300,7 +364,7 @@ SOURCE=..\doc\CrtObjCmd.3
# End Source File
# Begin Source File
-SOURCE=..\doc\CrtAlias.3
+SOURCE=..\doc\CrtSlave.3
# End Source File
# Begin Source File
@@ -712,7 +776,7 @@ SOURCE=..\doc\safe.n
# End Source File
# Begin Source File
-SOURCE=..\doc\SaveInterpState.3
+SOURCE=..\doc\SaveResult.3
# End Source File
# Begin Source File
@@ -776,7 +840,7 @@ SOURCE=..\doc\SplitPath.3
# End Source File
# Begin Source File
-SOURCE=..\doc\StaticLibrary.3
+SOURCE=..\doc\StaticPkg.3
# End Source File
# Begin Source File
@@ -1204,10 +1268,6 @@ SOURCE=..\generic\tclProc.c
# End Source File
# Begin Source File
-SOURCE=..\generic\tclProcess.c
-# End Source File
-# Begin Source File
-
SOURCE=..\generic\tclRegexp.c
# End Source File
# Begin Source File
@@ -1240,14 +1300,6 @@ SOURCE=..\generic\tclStubLib.c
# End Source File
# Begin Source File
-SOURCE=..\generic\tclOOStubLib.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\generic\tclTomMathStubLib.c
-# End Source File
-# Begin Source File
-
SOURCE=..\generic\tclTest.c
# End Source File
# Begin Source File
@@ -1364,7 +1416,11 @@ SOURCE=.\configure
# End Source File
# Begin Source File
-SOURCE=.\configure.ac
+SOURCE=.\configure.in
+# End Source File
+# Begin Source File
+
+SOURCE=.\makefile.bc
# End Source File
# Begin Source File
@@ -1396,6 +1452,14 @@ SOURCE=.\rules.vc
# End Source File
# Begin Source File
+SOURCE=.\stub16.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tcl.hpj.in
+# End Source File
+# Begin Source File
+
SOURCE=.\tcl.m4
# End Source File
# Begin Source File
@@ -1464,10 +1528,6 @@ SOURCE=.\tclWinNotify.c
# End Source File
# Begin Source File
-SOURCE=.\tclWinPanic.c
-# End Source File
-# Begin Source File
-
SOURCE=.\tclWinPipe.c
# End Source File
# Begin Source File
@@ -1496,6 +1556,10 @@ SOURCE=.\tclWinThrd.c
# End Source File
# Begin Source File
+SOURCE=.\tclWinThrd.h
+# End Source File
+# Begin Source File
+
SOURCE=.\tclWinTime.c
# End Source File
# End Group
diff --git a/win/tcl.hpj.in b/win/tcl.hpj.in
new file mode 100644
index 0000000..8efff0b
--- /dev/null
+++ b/win/tcl.hpj.in
@@ -0,0 +1,19 @@
+; This file is maintained by HCW. Do not modify this file directly.
+
+[OPTIONS]
+HCW=0
+LCID=0x409 0x0 0x0 ;English (United States)
+REPORT=Yes
+TITLE=Tcl/Tk Reference Manual
+CNT=tcl85.cnt
+COPYRIGHT=Copyright © 2000 Ajuba Solutions
+HLP=tcl85.hlp
+
+[FILES]
+tcl.rtf
+
+[WINDOWS]
+main="Tcl/Tk Reference Manual",,0
+
+[CONFIG]
+BrowseButtons()
diff --git a/win/tcl.m4 b/win/tcl.m4
index fff706b..006778c 100644
--- a/win/tcl.m4
+++ b/win/tcl.m4
@@ -28,9 +28,9 @@ AC_DEFUN([SC_PATH_TCLCONFIG], [
# we reset no_tcl in case something fails here
no_tcl=true
AC_ARG_WITH(tcl,
- AS_HELP_STRING([--with-tcl],
+ AC_HELP_STRING([--with-tcl],
[directory containing tcl configuration (tclConfig.sh)]),
- [with_tclconfig="${withval}"])
+ with_tclconfig="${withval}")
AC_MSG_CHECKING([for Tcl configuration])
AC_CACHE_VAL(ac_cv_c_tclconfig,[
@@ -146,9 +146,9 @@ AC_DEFUN([SC_PATH_TKCONFIG], [
# we reset no_tk in case something fails here
no_tk=true
AC_ARG_WITH(tk,
- AS_HELP_STRING([--with-tk],
+ AC_HELP_STRING([--with-tk],
[directory containing tk configuration (tkConfig.sh)]),
- [with_tkconfig="${withval}"])
+ with_tkconfig="${withval}")
AC_MSG_CHECKING([for Tk configuration])
AC_CACHE_VAL(ac_cv_c_tkconfig,[
@@ -247,7 +247,7 @@ AC_DEFUN([SC_PATH_TKCONFIG], [
#
# Results:
#
-# Substitutes the following vars:
+# Subst the following vars:
# TCL_BIN_DIR
# TCL_SRC_DIR
# TCL_LIB_FILE
@@ -279,6 +279,14 @@ AC_DEFUN([SC_LOAD_TCLCONFIG], [
TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH}
fi
+ #
+ # eval is required to do the TCL_DBGX substitution
+ #
+
+ eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
+ eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
+ eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
+
eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
@@ -356,6 +364,14 @@ AC_DEFUN([SC_ENABLE_SHARED], [
AC_ARG_ENABLE(shared,
[ --enable-shared build and link with shared libraries (default: on)],
[tcl_ok=$enableval], [tcl_ok=yes])
+
+ if test "${enable_shared+set}" = set; then
+ enableval="$enable_shared"
+ tcl_ok=$enableval
+ else
+ tcl_ok=yes
+ fi
+
if test "$tcl_ok" = "yes" ; then
AC_MSG_RESULT([shared])
SHARED_BUILD=1
@@ -364,7 +380,42 @@ AC_DEFUN([SC_ENABLE_SHARED], [
SHARED_BUILD=0
AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?])
fi
- AC_SUBST(SHARED_BUILD)
+])
+
+#------------------------------------------------------------------------
+# SC_ENABLE_THREADS --
+#
+# Specify if thread support should be enabled
+#
+# Arguments:
+# none
+#
+# Results:
+#
+# Adds the following arguments to configure:
+# --enable-threads=yes|no
+#
+# Defines the following vars:
+# TCL_THREADS
+#------------------------------------------------------------------------
+
+AC_DEFUN([SC_ENABLE_THREADS], [
+ AC_MSG_CHECKING(for building with threads)
+ AC_ARG_ENABLE(threads, [ --enable-threads build with threads (default: off)],
+ [tcl_ok=$enableval], [tcl_ok=no])
+
+ if test "$tcl_ok" = "yes"; then
+ AC_MSG_RESULT(yes)
+ TCL_THREADS=1
+ AC_DEFINE(TCL_THREADS)
+ # USE_THREAD_ALLOC tells us to try the special thread-based
+ # allocator that significantly reduces lock contention
+ AC_DEFINE(USE_THREAD_ALLOC)
+ else
+ TCL_THREADS=0
+ AC_MSG_RESULT([no (default)])
+ fi
+ AC_SUBST(TCL_THREADS)
])
#------------------------------------------------------------------------
@@ -391,6 +442,7 @@ AC_DEFUN([SC_ENABLE_SHARED], [
# Sets to $(CFLAGS_OPTIMIZE) if false
# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true
# Sets to $(LDFLAGS_OPTIMIZE) if false
+# DBGX Debug library extension
#
#------------------------------------------------------------------------
@@ -401,6 +453,7 @@ AC_DEFUN([SC_ENABLE_SYMBOLS], [
if test "$tcl_ok" = "no"; then
CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)'
LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)'
+ DBGX=""
AC_DEFINE(NDEBUG, 1, [Is no debugging enabled?])
AC_MSG_RESULT([no])
@@ -408,6 +461,7 @@ AC_DEFUN([SC_ENABLE_SYMBOLS], [
else
CFLAGS_DEFAULT='$(CFLAGS_DEBUG)'
LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)'
+ DBGX=g
if test "$tcl_ok" = "yes"; then
AC_MSG_RESULT([yes (standard debugging)])
fi
@@ -453,7 +507,6 @@ AC_DEFUN([SC_ENABLE_SYMBOLS], [
# CFLAGS_DEBUG
# CFLAGS_OPTIMIZE
# CFLAGS_WARNING
-# CFLAGS_NOLTO
# LDFLAGS_DEBUG
# LDFLAGS_OPTIMIZE
# LDFLAGS_CONSOLE
@@ -491,50 +544,52 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
AC_ARG_ENABLE(64bit,[ --enable-64bit enable 64bit support (where applicable)], [do64bit=$enableval], [do64bit=no])
AC_MSG_RESULT($do64bit)
+ # Cross-compiling options for Windows/CE builds
+
+ AC_MSG_CHECKING([if Windows/CE build is requested])
+ AC_ARG_ENABLE(wince,[ --enable-wince enable Win/CE support (where applicable)], [doWince=$enableval], [doWince=no])
+ AC_MSG_RESULT($doWince)
+
+ AC_MSG_CHECKING([for Windows/CE celib directory])
+ AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR],
+ CELIB_DIR=$withval, CELIB_DIR=NO_CELIB)
+ AC_MSG_RESULT([$CELIB_DIR])
+
# Set some defaults (may get changed below)
EXTRA_CFLAGS=""
- AC_DEFINE(MODULE_SCOPE, [extern], [No need to mark inidividual symbols as hidden])
AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo)
- AC_CHECK_PROG(WINE, wine, wine,)
SHLIB_SUFFIX=".dll"
# MACHINE is IX86 for LINK, but this is used by the manifest,
- # which requires x86|amd64|arm64|ia64.
+ # which requires x86|amd64|ia64.
MACHINE="X86"
if test "$GCC" = "yes"; then
AC_CACHE_CHECK(for cross-compile version of gcc,
ac_cv_cross,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- #ifndef _WIN32
+ AC_TRY_COMPILE([
+ #ifndef __WIN32__
#error cross-compiler
#endif
- ]], [[]])],
- [ac_cv_cross=no],
- [ac_cv_cross=yes])
+ ], [],
+ ac_cv_cross=no,
+ ac_cv_cross=yes)
)
if test "$ac_cv_cross" = "yes"; then
case "$do64bit" in
amd64|x64|yes)
- CC="x86_64-w64-mingw32-${CC}"
+ CC="x86_64-w64-mingw32-gcc"
LD="x86_64-w64-mingw32-ld"
AR="x86_64-w64-mingw32-ar"
RANLIB="x86_64-w64-mingw32-ranlib"
RC="x86_64-w64-mingw32-windres"
;;
- arm64|aarch64)
- CC="aarch64-w64-mingw32-${CC}"
- LD="aarch64-w64-mingw32-ld"
- AR="aarch64-w64-mingw32-ar"
- RANLIB="aarch64-w64-mingw32-ranlib"
- RC="aarch64-w64-mingw32-windres"
- ;;
*)
- CC="i686-w64-mingw32-${CC}"
+ CC="i686-w64-mingw32-gcc"
LD="i686-w64-mingw32-ld"
AR="i686-w64-mingw32-ar"
RANLIB="i686-w64-mingw32-ranlib"
@@ -582,79 +637,26 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
extra_ldflags="-pipe -static-libgcc"
AC_CACHE_CHECK(for mingw32 version of gcc,
ac_cv_win32,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- #ifdef _WIN32
+ AC_TRY_COMPILE([
+ #ifdef __WIN32__
#error win32
#endif
- ]], [[]])],
- [ac_cv_win32=no],
- [ac_cv_win32=yes])
+ ], [],
+ ac_cv_win32=no,
+ ac_cv_win32=yes)
)
if test "$ac_cv_win32" != "yes"; then
AC_MSG_ERROR([${CC} cannot produce win32 executables.])
fi
- if test "$do64bit" != "arm64"; then
- extra_cflags="$extra_cflags -DHAVE_CPUID=1"
- fi
-
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -mwindows -municode -Dmain=xxmain"
- AC_CACHE_CHECK(for working -municode linker flag,
- ac_cv_municode,
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[
- #include <windows.h>
- int APIENTRY wWinMain(HINSTANCE a, HINSTANCE b, LPWSTR c, int d) {return 0;}
- ]], [[]])],
- [ac_cv_municode=yes],
- [ac_cv_municode=no])
- )
- CFLAGS=$hold_cflags
- if test "$ac_cv_municode" = "yes" ; then
- extra_ldflags="$extra_ldflags -municode"
- else
- extra_cflags="$extra_cflags -DTCL_BROKEN_MAINARGS"
- fi
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -fno-lto"
- AC_CACHE_CHECK(for working -fno-lto,
- ac_cv_nolto,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
- [ac_cv_nolto=yes],
- [ac_cv_nolto=no])
- )
- CFLAGS=$hold_cflags
- if test "$ac_cv_nolto" = "yes" ; then
- CFLAGS_NOLTO="-fno-lto"
- else
- CFLAGS_NOLTO=""
- fi
- AC_CACHE_CHECK([if the compiler understands -finput-charset],
- tcl_cv_cc_input_charset, [
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -finput-charset=UTF-8"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[tcl_cv_cc_input_charset=yes],[tcl_cv_cc_input_charset=no])
- CFLAGS=$hold_cflags])
- if test $tcl_cv_cc_input_charset = yes; then
- extra_cflags="$extra_cflags -finput-charset=UTF-8"
- fi
- fi
-
- hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Wl,--enable-auto-image-base"
- AC_CACHE_CHECK(for working --enable-auto-image-base,
- ac_cv_enable_auto_image_base,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
- [ac_cv_enable_auto_image_base=yes],
- [ac_cv_enable_auto_image_base=no])
- )
- CFLAGS=$hold_cflags
- if test "$ac_cv_enable_auto_image_base" == "yes" ; then
- extra_ldflags="$extra_ldflags -Wl,--enable-auto-image-base"
fi
AC_MSG_CHECKING([compiler flags])
if test "${GCC}" = "yes" ; then
SHLIB_LD=""
- SHLIB_LD_LIBS='${LIBS}'
- LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -luserenv -lws2_32"
+ SHLIB_LD_LIBS=""
+ LIBS="-lws2_32"
# mingw needs to link ole32 and oleaut32 for [send], but MSVC doesn't
- LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32 -luuid -lole32 -loleaut32 -lwinspool"
+ LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32 -luuid -lole32 -loleaut32"
STLIB_LD='${AR} cr'
RC_OUT=-o
RC_TYPE=
@@ -671,8 +673,11 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
# static
AC_MSG_RESULT([using static flags])
runtime=
+ MAKE_DLL="echo "
+ LIBSUFFIX="s\${DBGX}.a"
+ LIBFLAGSUFFIX="s\${DBGX}"
LIBRARIES="\${STATIC_LIBRARIES}"
- EXESUFFIX="s.exe"
+ EXESUFFIX="s\${DBGX}.exe"
else
# dynamic
AC_MSG_RESULT([using shared flags])
@@ -684,41 +689,32 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
fi
runtime=
+ # Link with gcc since ld does not link to default libs like
+ # -luser32 and -lmsvcrt by default.
+ SHLIB_LD='${CC} -shared'
+ SHLIB_LD_LIBS='${LIBS}'
# Add SHLIB_LD_LIBS to the Make rule, not here.
+ MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -o \[$]@ ${extra_ldflags} \
+ -Wl,--out-implib,\$(patsubst %.dll,lib%.a,\[$]@)"
- EXESUFFIX=".exe"
+ LIBSUFFIX="\${DBGX}.a"
+ LIBFLAGSUFFIX="\${DBGX}"
+ EXESUFFIX="\${DBGX}.exe"
LIBRARIES="\${SHARED_LIBRARIES}"
fi
- # Link with gcc since ld does not link to default libs like
- # -luser32 and -lmsvcrt by default.
- SHLIB_LD='${CC} -shared'
- SHLIB_LD_LIBS='${LIBS}'
- MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -o \[$]@ ${extra_ldflags} \
- -Wl,--out-implib,\$(patsubst %.dll,lib%.dll.a,\[$]@)"
# DLLSUFFIX is separate because it is the building block for
# users of tclConfig.sh that may build shared or static.
- DLLSUFFIX=".dll"
- LIBSUFFIX=".a"
- LIBFLAGSUFFIX=""
+ DLLSUFFIX="\${DBGX}.dll"
SHLIB_SUFFIX=.dll
EXTRA_CFLAGS="${extra_cflags}"
CFLAGS_DEBUG=-g
CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
- CFLAGS_WARNING="-Wall -Wextra -Wshadow -Wundef -Wwrite-strings -Wpointer-arith"
+ CFLAGS_WARNING="-Wall"
LDFLAGS_DEBUG=
LDFLAGS_OPTIMIZE=
- case "${CC}" in
- *++)
- CFLAGS_WARNING="${CFLAGS_WARNING} -Wno-format"
- ;;
- *)
- CFLAGS_WARNING="${CFLAGS_WARNING} -Wc++-compat -fextended-identifiers"
- ;;
- esac
-
# Specify the CC output file names based on the target name
CC_OBJNAME="-o \[$]@"
CC_EXENAME="-o \[$]@"
@@ -745,27 +741,23 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
MACHINE="AMD64" ; # assume AMD64 as default 64-bit build
AC_MSG_RESULT([ Using 64-bit $MACHINE mode])
;;
- arm64|aarch64)
- MACHINE="ARM64"
- AC_MSG_RESULT([ Using ARM64 $MACHINE mode])
- ;;
ia64)
MACHINE="IA64"
- AC_MSG_RESULT([ Using IA64 $MACHINE mode])
+ AC_MSG_RESULT([ Using 64-bit $MACHINE mode])
;;
*)
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ AC_TRY_COMPILE([
#ifndef _WIN64
#error 32-bit
#endif
- ]], [[]])],
- [tcl_win_64bit=yes],
- [tcl_win_64bit=no]
+ ], [],
+ tcl_win_64bit=yes,
+ tcl_win_64bit=no
)
if test "$tcl_win_64bit" = "yes" ; then
- do64bit=amd64
- MACHINE="AMD64"
- AC_MSG_RESULT([ Using 64-bit $MACHINE mode])
+ do64bit=amd64
+ MACHINE="AMD64"
+ AC_MSG_RESULT([ Using 64-bit $MACHINE mode])
fi
;;
esac
@@ -774,15 +766,23 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
# static
AC_MSG_RESULT([using static flags])
runtime=-MT
+ MAKE_DLL="echo "
+ LIBSUFFIX="s\${DBGX}.lib"
+ LIBFLAGSUFFIX="s\${DBGX}"
LIBRARIES="\${STATIC_LIBRARIES}"
- EXESUFFIX="s.exe"
+ EXESUFFIX="s\${DBGX}.exe"
+ SHLIB_LD_LIBS=""
else
# dynamic
AC_MSG_RESULT([using shared flags])
runtime=-MD
# Add SHLIB_LD_LIBS to the Make rule, not here.
+ MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -out:\[$]@"
+ LIBSUFFIX="\${DBGX}.lib"
+ LIBFLAGSUFFIX="\${DBGX}"
+ EXESUFFIX="\${DBGX}.exe"
LIBRARIES="\${SHARED_LIBRARIES}"
- EXESUFFIX=".exe"
+ SHLIB_LD_LIBS='${LIBS}'
case "x`echo \${VisualStudioVersion}`" in
x1[[4-9]]*)
lflags="${lflags} -nodefaultlib:libucrt.lib"
@@ -791,29 +791,36 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
;;
esac
fi
- MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -out:\[$]@"
# DLLSUFFIX is separate because it is the building block for
# users of tclConfig.sh that may build shared or static.
- DLLSUFFIX=".dll"
- LIBSUFFIX=".lib"
- LIBFLAGSUFFIX=""
+ DLLSUFFIX="\${DBGX}.dll"
+ # This is a 2-stage check to make sure we have the 64-bit SDK
+ # We have to know where the SDK is installed.
+ # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs
if test "$do64bit" != "no" ; then
+ if test "x${MSSDK}x" = "xx" ; then
+ MSSDK="C:/Progra~1/Microsoft Platform SDK"
+ fi
+ MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'`
+ PATH64=""
case "$do64bit" in
amd64|x64|yes)
MACHINE="AMD64" ; # assume AMD64 as default 64-bit build
- ;;
- arm64|aarch64)
- MACHINE="ARM64"
+ PATH64="${MSSDK}/Bin/Win64/x86/AMD64"
;;
ia64)
MACHINE="IA64"
+ PATH64="${MSSDK}/Bin/Win64"
;;
esac
+ if test ! -d "${PATH64}" ; then
+ AC_MSG_WARN([Could not find 64-bit $MACHINE SDK])
+ fi
AC_MSG_RESULT([ Using 64-bit $MACHINE mode])
fi
- LIBS="netapi32.lib kernel32.lib user32.lib advapi32.lib userenv.lib ws2_32.lib"
+ LIBS="user32.lib advapi32.lib ws2_32.lib"
case "x`echo \${VisualStudioVersion}`" in
x1[[4-9]]*)
@@ -824,11 +831,21 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
esac
if test "$do64bit" != "no" ; then
- RC="rc"
+ # The space-based-path will work for the Makefile, but will
+ # not work if AC_TRY_COMPILE is called. TEA has the
+ # TEA_PATH_NOSPACE to avoid this issue.
+ # Check if _WIN64 is already recognized, and if so we don't
+ # need to modify CC.
+ AC_CHECK_DECL([_WIN64], [],
+ [CC="\"${PATH64}/cl.exe\" -I\"${MSSDK}/Include\" \
+ -I\"${MSSDK}/Include/crt\" \
+ -I\"${MSSDK}/Include/crt/sys\""])
+ RC="\"${MSSDK}/bin/rc.exe\""
CFLAGS_DEBUG="-nologo -Zi -Od ${runtime}d"
- CFLAGS_OPTIMIZE="-nologo -O2 ${runtime}"
- lflags="${lflags} -nologo -MACHINE:${MACHINE}"
- LINKBIN="link"
+ # Do not use -O2 for Win64 - this has proved buggy in code gen.
+ CFLAGS_OPTIMIZE="-nologo -O1 ${runtime}"
+ lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\""
+ LINKBIN="\"${PATH64}/link.exe\""
# Avoid 'unresolved external symbol __security_cookie' errors.
# c.f. http://support.microsoft.com/?id=894573
LIBS="$LIBS bufferoverflowU.lib"
@@ -843,10 +860,100 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
LINKBIN="link"
fi
- LIBS_GUI="gdi32.lib comdlg32.lib imm32.lib comctl32.lib shell32.lib uuid.lib winspool.lib"
+ if test "$doWince" != "no" ; then
+ # Set defaults for common evc4/PPC2003 setup
+ # Currently Tcl requires 300+, possibly 420+ for sockets
+ CEVERSION=420; # could be 211 300 301 400 420 ...
+ TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ...
+ ARCH=ARM; # could be ARM MIPS X86EM ...
+ PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002"
+ if test "$doWince" != "yes"; then
+ # If !yes then the user specified something
+ # Reset ARCH to allow user to skip specifying it
+ ARCH=
+ eval `echo $doWince | awk -F "," '{ \
+ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \
+ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \
+ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \
+ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \
+ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \
+ }'`
+ if test "x${ARCH}" = "x" ; then
+ ARCH=$TARGETCPU;
+ fi
+ fi
+ OSVERSION=WCE$CEVERSION;
+ if test "x${WCEROOT}" = "x" ; then
+ WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0"
+ if test ! -d "${WCEROOT}" ; then
+ WCEROOT="C:/Program Files/Microsoft eMbedded Tools"
+ fi
+ fi
+ if test "x${SDKROOT}" = "x" ; then
+ SDKROOT="C:/Program Files/Windows CE Tools"
+ if test ! -d "${SDKROOT}" ; then
+ SDKROOT="C:/Windows CE Tools"
+ fi
+ fi
+ # The space-based-path will work for the Makefile, but will
+ # not work if AC_TRY_COMPILE is called.
+ WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'`
+ SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'`
+ CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'`
+ if test ! -d "${CELIB_DIR}/inc"; then
+ AC_MSG_ERROR([Invalid celib directory "${CELIB_DIR}"])
+ fi
+ if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}"\
+ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then
+ AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]])
+ else
+ CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include"
+ if test -d "${CEINCLUDE}/${TARGETCPU}" ; then
+ CEINCLUDE="${CEINCLUDE}/${TARGETCPU}"
+ fi
+ CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}"
+ fi
+ fi
+
+ if test "$doWince" != "no" ; then
+ CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin"
+ if test "${TARGETCPU}" = "X86"; then
+ CC="${CEBINROOT}/cl.exe"
+ else
+ CC="${CEBINROOT}/cl${ARCH}.exe"
+ fi
+ CC="\"${CC}\" -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\""
+ RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\""
+ arch=`echo ${ARCH} | awk '{print tolower([$]0)}'`
+ defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _DLL _WINDOWS"
+ for i in $defs ; do
+ AC_DEFINE_UNQUOTED($i)
+ done
+# if test "${ARCH}" = "X86EM"; then
+# AC_DEFINE_UNQUOTED(_WIN32_WCE_EMULATION)
+# fi
+ AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION)
+ AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION)
+ CFLAGS_DEBUG="-nologo -Zi -Od"
+ CFLAGS_OPTIMIZE="-nologo -O2"
+ lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'`
+ lflags="-nodefaultlib -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo"
+ LINKBIN="\"${CEBINROOT}/link.exe\""
+ AC_SUBST(CELIB_DIR)
+ if test "${CEVERSION}" -lt 400 ; then
+ LIBS="coredll.lib corelibc.lib winsock.lib"
+ else
+ LIBS="coredll.lib corelibc.lib ws2.lib"
+ fi
+ # celib currently stuck at wce300 status
+ #LIBS="$LIBS \${CELIB_DIR}/wince-${ARCH}-pocket-${OSVERSION}-release/celib.lib"
+ LIBS="$LIBS \"\${CELIB_DIR}/wince-${ARCH}-pocket-wce300-release/celib.lib\""
+ LIBS_GUI="commctrl.lib commdlg.lib"
+ else
+ LIBS_GUI="gdi32.lib comdlg32.lib imm32.lib comctl32.lib shell32.lib uuid.lib"
+ fi
SHLIB_LD="${LINKBIN} -dll -incremental:no ${lflags}"
- SHLIB_LD_LIBS='${LIBS}'
# link -lib only works when -lib is the first arg
STLIB_LD="${LINKBIN} -lib ${lflags}"
RC_OUT=-fo
@@ -874,7 +981,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
# Specify linker flags depending on the type of app being
# built -- Console vs. Window.
- if test "${TARGETCPU}" != "X86"; then
+ if test "$doWince" != "no" -a "${TARGETCPU}" != "X86"; then
LDFLAGS_CONSOLE="-link ${lflags}"
LDFLAGS_WINDOW=${LDFLAGS_CONSOLE}
else
@@ -890,7 +997,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
if test "${GCC}" = "yes" ; then
AC_CACHE_CHECK(for SEH support in compiler,
tcl_cv_seh,
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ AC_TRY_RUN([
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
@@ -905,10 +1012,10 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
}
return 1;
}
- ]])],
- [tcl_cv_seh=yes],
- [tcl_cv_seh=no],
- [tcl_cv_seh=no])
+ ],
+ tcl_cv_seh=yes,
+ tcl_cv_seh=no,
+ tcl_cv_seh=no)
)
if test "$tcl_cv_seh" = "no" ; then
AC_DEFINE(HAVE_NO_SEH, 1,
@@ -923,22 +1030,44 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
#
AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files,
tcl_cv_eh_disposition,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ AC_TRY_COMPILE([
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
- ]], [[
+ ],[
EXCEPTION_DISPOSITION x;
- ]])],
- [tcl_cv_eh_disposition=yes],
- [tcl_cv_eh_disposition=no])
+ ],
+ tcl_cv_eh_disposition=yes,
+ tcl_cv_eh_disposition=no)
)
if test "$tcl_cv_eh_disposition" = "no" ; then
AC_DEFINE(EXCEPTION_DISPOSITION, int,
[Defined when cygwin/mingw does not support EXCEPTION DISPOSITION])
fi
- AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have <stdbool.h>?])],)
+ # Check to see if winnt.h defines CHAR, SHORT, and LONG
+ # even if VOID has already been #defined. The win32api
+ # used by mingw and cygwin is known to do this.
+
+ AC_CACHE_CHECK(for winnt.h that ignores VOID define,
+ tcl_cv_winnt_ignore_void,
+ AC_TRY_COMPILE([
+ #define VOID void
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+ #undef WIN32_LEAN_AND_MEAN
+ ], [
+ CHAR c;
+ SHORT s;
+ LONG l;
+ ],
+ tcl_cv_winnt_ignore_void=yes,
+ tcl_cv_winnt_ignore_void=no)
+ )
+ if test "$tcl_cv_winnt_ignore_void" = "yes" ; then
+ AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1,
+ [Defined when cygwin/mingw ignores VOID define in winnt.h])
+ fi
# See if the compiler supports casting to a union type.
# This is used to stop gcc from printing a compiler
@@ -946,12 +1075,13 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
AC_CACHE_CHECK(for cast to union support,
tcl_cv_cast_to_union,
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
+ AC_TRY_COMPILE([],
+ [
union foo { int i; double d; };
union foo f = (union foo) (int) 0;
- ]])],
- [tcl_cv_cast_to_union=yes],
- [tcl_cv_cast_to_union=no])
+ ],
+ tcl_cv_cast_to_union=yes,
+ tcl_cv_cast_to_union=no)
)
if test "$tcl_cv_cast_to_union" = "yes"; then
AC_DEFINE(HAVE_CAST_TO_UNION, 1,
@@ -964,7 +1094,6 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
AC_SUBST(CFLAGS_DEBUG)
AC_SUBST(CFLAGS_OPTIMIZE)
AC_SUBST(CFLAGS_WARNING)
- AC_SUBST(CFLAGS_NOLTO)
])
#------------------------------------------------------------------------
@@ -985,13 +1114,13 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [
#------------------------------------------------------------------------
AC_DEFUN([SC_WITH_TCL], [
- if test -d ../../tcl8.7$1/win; then
- TCL_BIN_DEFAULT=../../tcl8.7$1/win
+ if test -d ../../tcl8.5$1/win; then
+ TCL_BIN_DEFAULT=../../tcl8.5$1/win
else
- TCL_BIN_DEFAULT=../../tcl8.7/win
+ TCL_BIN_DEFAULT=../../tcl8.5/win
fi
- AC_ARG_WITH(tcl, [ --with-tcl=DIR use Tcl 8.7 binaries from DIR],
+ AC_ARG_WITH(tcl, [ --with-tcl=DIR use Tcl 8.5 binaries from DIR],
TCL_BIN_DIR=$withval, TCL_BIN_DIR=`cd $TCL_BIN_DEFAULT; pwd`)
if test ! -d $TCL_BIN_DIR; then
AC_MSG_ERROR(Tcl directory $TCL_BIN_DIR does not exist)
@@ -1020,7 +1149,7 @@ AC_DEFUN([SC_WITH_TCL], [
# none
#
# Results
-# Substitutes the following values:
+# Subst's the following values:
# TCLSH_PROG
#------------------------------------------------------------------------
@@ -1066,13 +1195,13 @@ AC_DEFUN([SC_PROG_TCLSH], [
# none
#
# Results
-# Substitutes the following values:
+# Subst's the following values:
# BUILD_TCLSH
#------------------------------------------------------------------------
AC_DEFUN([SC_BUILD_TCLSH], [
AC_MSG_CHECKING([for tclsh in Tcl build directory])
- BUILD_TCLSH=${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}\${EXESUFFIX}
+ BUILD_TCLSH=${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}
AC_MSG_RESULT($BUILD_TCLSH)
AC_SUBST(BUILD_TCLSH)
])
@@ -1100,7 +1229,8 @@ AC_DEFUN([SC_TCL_CFG_ENCODING], [
if test x"${with_tcencoding}" != x ; then
AC_DEFINE_UNQUOTED(TCL_CFGVAL_ENCODING,"${with_tcencoding}")
else
- AC_DEFINE(TCL_CFGVAL_ENCODING,"utf-8")
+ # Default encoding on windows is not "iso8859-1"
+ AC_DEFINE(TCL_CFGVAL_ENCODING,"cp1252")
fi
])
@@ -1122,7 +1252,7 @@ AC_DEFUN([SC_TCL_CFG_ENCODING], [
AC_DEFUN([SC_EMBED_MANIFEST], [
AC_MSG_CHECKING(whether to embed manifest)
AC_ARG_ENABLE(embedded-manifest,
- AS_HELP_STRING([--enable-embedded-manifest],
+ AC_HELP_STRING([--enable-embedded-manifest],
[embed manifest if possible (default: yes)]),
[embed_ok=$enableval], [embed_ok=yes])
@@ -1155,126 +1285,3 @@ print("manifest needed")
AC_SUBST(VC_MANIFEST_EMBED_DLL)
AC_SUBST(VC_MANIFEST_EMBED_EXE)
])
-
-#------------------------------------------------------------------------
-# SC_CC_FOR_BUILD
-# For cross compiles, locate a C compiler that can generate native binaries.
-#
-# Arguments:
-# none
-#
-# Results:
-# Substitutes the following vars:
-# CC_FOR_BUILD
-# EXEEXT_FOR_BUILD
-#------------------------------------------------------------------------
-
-dnl Get a default for CC_FOR_BUILD to put into Makefile.
-AC_DEFUN([AX_CC_FOR_BUILD],
-[# Put a plausible default for CC_FOR_BUILD in Makefile.
-if test -z "$CC_FOR_BUILD"; then
- if test "x$cross_compiling" = "xno"; then
- CC_FOR_BUILD='$(CC)'
- else
- AC_MSG_CHECKING([for gcc])
- AC_CACHE_VAL(ac_cv_path_cc, [
- search_path=`echo ${PATH} | sed -e 's/:/ /g'`
- for dir in $search_path ; do
- for j in `ls -r $dir/gcc 2> /dev/null` \
- `ls -r $dir/gcc 2> /dev/null` ; do
- if test x"$ac_cv_path_cc" = x ; then
- if test -f "$j" ; then
- ac_cv_path_cc=$j
- break
- fi
- fi
- done
- done
- ])
- fi
-fi
-AC_SUBST(CC_FOR_BUILD)
-# Also set EXEEXT_FOR_BUILD.
-if test "x$cross_compiling" = "xno"; then
- EXEEXT_FOR_BUILD='$(EXEEXT)'
- OBJEXT_FOR_BUILD='$(OBJEXT)'
-else
- OBJEXT_FOR_BUILD='.no'
- AC_CACHE_CHECK([for build system executable suffix], bfd_cv_build_exeext,
- [rm -f conftest*
- echo 'int main () { return 0; }' > conftest.c
- bfd_cv_build_exeext=
- ${CC_FOR_BUILD} -o conftest conftest.c 1>&5 2>&5
- for file in conftest.*; do
- case $file in
- *.c | *.o | *.obj | *.ilk | *.pdb) ;;
- *) bfd_cv_build_exeext=`echo $file | sed -e s/conftest//` ;;
- esac
- done
- rm -f conftest*
- test x"${bfd_cv_build_exeext}" = x && bfd_cv_build_exeext=no])
- EXEEXT_FOR_BUILD=""
- test x"${bfd_cv_build_exeext}" != xno && EXEEXT_FOR_BUILD=${bfd_cv_build_exeext}
-fi
-AC_SUBST(EXEEXT_FOR_BUILD)])dnl
-AC_SUBST(OBJEXT_FOR_BUILD)])dnl
-
-
-
-#------------------------------------------------------------------------
-# SC_ZIPFS_SUPPORT
-# Locate a zip encoder installed on the system path, or none.
-#
-# Arguments:
-# none
-#
-# Results:
-# Substitutes the following vars:
-# ZIP_PROG
-# ZIP_PROG_OPTIONS
-# ZIP_PROG_VFSSEARCH
-# ZIP_INSTALL_OBJS
-#------------------------------------------------------------------------
-
-AC_DEFUN([SC_ZIPFS_SUPPORT], [
- ZIP_PROG=""
- ZIP_PROG_OPTIONS=""
- ZIP_PROG_VFSSEARCH=""
- ZIP_INSTALL_OBJS=""
-
- AC_MSG_CHECKING([for zip])
- AC_CACHE_VAL(ac_cv_path_zip, [
- search_path=`echo ${PATH} | sed -e 's/:/ /g'`
- for dir in $search_path ; do
- for j in `ls -r $dir/zip 2> /dev/null` \
- `ls -r $dir/zip 2> /dev/null` ; do
- if test x"$ac_cv_path_zip" = x ; then
- if test -f "$j" ; then
- ac_cv_path_zip=$j
- break
- fi
- fi
- done
- done
- ])
- if test -f "$ac_cv_path_zip" ; then
- ZIP_PROG="$ac_cv_path_zip"
- AC_MSG_RESULT([$ZIP_PROG])
- ZIP_PROG_OPTIONS="-rq"
- ZIP_PROG_VFSSEARCH="*"
- AC_MSG_RESULT([Found INFO Zip in environment])
- # Use standard arguments for zip
- else
- # It is not an error if an installed version of Zip can't be located.
- # We can use the locally distributed minizip instead
- ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}"
- ZIP_PROG_OPTIONS="-o -r"
- ZIP_PROG_VFSSEARCH="*"
- ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}"
- AC_MSG_RESULT([No zip found on PATH building minizip])
- fi
- AC_SUBST(ZIP_PROG)
- AC_SUBST(ZIP_PROG_OPTIONS)
- AC_SUBST(ZIP_PROG_VFSSEARCH)
- AC_SUBST(ZIP_INSTALL_OBJS)
-])
diff --git a/win/tcl.rc b/win/tcl.rc
index 3d125f2..be5e0a7 100644
--- a/win/tcl.rc
+++ b/win/tcl.rc
@@ -7,13 +7,19 @@
//
// build-up the name suffix that defines the type of build this is.
//
+#if TCL_THREADS
+#define SUFFIX_THREADS "t"
+#else
+#define SUFFIX_THREADS ""
+#endif
+
#if DEBUG && !UNCHECKED
#define SUFFIX_DEBUG "g"
#else
#define SUFFIX_DEBUG ""
#endif
-#define SUFFIX SUFFIX_DEBUG
+#define SUFFIX SUFFIX_THREADS SUFFIX_DEBUG
LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */
@@ -37,8 +43,9 @@ BEGIN
BEGIN
VALUE "FileDescription", "Tcl DLL\0"
VALUE "OriginalFilename", "tcl" STRINGIFY(TCL_MAJOR_VERSION) STRINGIFY(TCL_MINOR_VERSION) SUFFIX ".dll\0"
+ VALUE "CompanyName", "ActiveState Corporation\0"
VALUE "FileVersion", TCL_PATCH_LEVEL
- VALUE "LegalCopyright", "Copyright \251 1987-2022 Regents of the University of California and other parties\0"
+ VALUE "LegalCopyright", "Copyright \251 2001 by ActiveState Corporation, et al\0"
VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0"
VALUE "ProductVersion", TCL_PATCH_LEVEL
END
diff --git a/win/tclAppInit.c b/win/tclAppInit.c
index d1b38ee..251a610 100644
--- a/win/tclAppInit.c
+++ b/win/tclAppInit.c
@@ -2,78 +2,31 @@
* tclAppInit.c --
*
* Provides a default version of the main program and Tcl_AppInit
- * procedure for tclsh and other Tcl-based applications (without Tk).
- * Note that this program must be built in Win32 console mode to work
- * properly.
+ * function for Tcl applications (without Tk). Note that this program
+ * must be built in Win32 console mode to work properly.
*
- * Copyright (c) 1993 The Regents of the University of California.
- * Copyright (c) 1994-1997 Sun Microsystems, Inc.
- * Copyright (c) 1998-1999 Scriptics Corporation.
+ * Copyright (c) 1996-1997 by 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.
*/
#include "tcl.h"
-#if TCL_MAJOR_VERSION < 9
-# if defined(USE_TCL_STUBS)
-# error "Don't build with USE_TCL_STUBS!"
-# endif
-# if TCL_MINOR_VERSION < 7
-# define Tcl_LibraryInitProc Tcl_PackageInitProc
-# define Tcl_StaticLibrary Tcl_StaticPackage
-# endif
-#endif
+#include <windows.h>
+#include <locale.h>
#ifdef TCL_TEST
-extern Tcl_LibraryInitProc Tcltest_Init;
-extern Tcl_LibraryInitProc Tcltest_SafeInit;
+extern Tcl_PackageInitProc Procbodytest_Init;
+extern Tcl_PackageInitProc Procbodytest_SafeInit;
+extern Tcl_PackageInitProc Tcltest_Init;
+extern Tcl_PackageInitProc TclObjTest_Init;
#endif /* TCL_TEST */
-#if defined(STATIC_BUILD)
-extern Tcl_LibraryInitProc Registry_Init;
-extern Tcl_LibraryInitProc Dde_Init;
-extern Tcl_LibraryInitProc Dde_SafeInit;
-#endif
-
-#define WIN32_LEAN_AND_MEAN
-#define STRICT /* See MSDN Article Q83456 */
-#include <windows.h>
-#undef STRICT
-#undef WIN32_LEAN_AND_MEAN
-#include <locale.h>
-#include <stdlib.h>
-#include <tchar.h>
-#if defined(__GNUC__) || defined(TCL_BROKEN_MAINARGS)
+#if defined(__GNUC__)
int _CRT_glob = 0;
-#endif /* __GNUC__ || TCL_BROKEN_MAINARGS */
-#ifdef TCL_BROKEN_MAINARGS
-static void setargv(int *argcPtr, TCHAR ***argvPtr);
-#endif /* TCL_BROKEN_MAINARGS */
-
-/*
- * The following #if block allows you to change the AppInit function by using
- * a #define of TCL_LOCAL_APPINIT instead of rewriting this entire file. The
- * #if checks for that #define and uses Tcl_AppInit if it does not exist.
- */
-
-#ifndef TCL_LOCAL_APPINIT
-#define TCL_LOCAL_APPINIT Tcl_AppInit
-#endif
-#ifndef MODULE_SCOPE
-# define MODULE_SCOPE extern
-#endif
-MODULE_SCOPE int TCL_LOCAL_APPINIT(Tcl_Interp *);
-
-/*
- * The following #if block allows you to change how Tcl finds the startup
- * script, prime the library or encoding paths, fiddle with the argv, etc.,
- * without needing to rewrite Tcl_Main()
- */
-
-#ifdef TCL_LOCAL_MAIN_HOOK
-MODULE_SCOPE int TCL_LOCAL_MAIN_HOOK(int *argc, TCHAR ***argv);
-#endif
+static void setargv(int *argcPtr, char ***argvPtr);
+#endif /* __GNUC__ */
/*
*----------------------------------------------------------------------
@@ -83,46 +36,53 @@ MODULE_SCOPE int TCL_LOCAL_MAIN_HOOK(int *argc, TCHAR ***argv);
* This is the main program for the application.
*
* Results:
- * None: Tcl_Main never returns here, so this procedure never returns
+ * None: Tcl_Main never returns here, so this function never returns
* either.
*
* Side effects:
- * Just about anything, since from here we call arbitrary Tcl code.
+ * Whatever the application does.
*
*----------------------------------------------------------------------
*/
-#ifdef TCL_BROKEN_MAINARGS
int
main(
- int argc, /* Number of command-line arguments. */
- char **argv1) /* Not used. */
-{
- TCHAR **argv;
-#else
-int
-_tmain(
- int argc, /* Number of command-line arguments. */
- TCHAR *argv[]) /* Values of command-line arguments. */
+ int argc,
+ char *argv[])
{
+ /*
+ * The following #if block allows you to change the AppInit function by
+ * using a #define of TCL_LOCAL_APPINIT instead of rewriting this entire
+ * file. The #if checks for that #define and uses Tcl_AppInit if it
+ * doesn't exist.
+ */
+
+#ifndef TCL_LOCAL_APPINIT
+#define TCL_LOCAL_APPINIT Tcl_AppInit
#endif
- TCHAR *p;
+ extern int TCL_LOCAL_APPINIT (Tcl_Interp *interp);
/*
- * Set up the default locale to be standard "C" locale so parsing is
- * performed correctly.
+ * The following #if block allows you to change how Tcl finds the startup
+ * script, prime the library or encoding paths, fiddle with the argv,
+ * etc., without needing to rewrite Tcl_Main()
*/
- setlocale(LC_ALL, "C");
+#ifdef TCL_LOCAL_MAIN_HOOK
+ extern int TCL_LOCAL_MAIN_HOOK (int *argc, char ***argv);
+#endif
+
+ char *p;
-#ifdef TCL_BROKEN_MAINARGS
/*
- * Get our args from the c-runtime. Ignore command line.
+ * Set up the default locale to be standard "C" locale so parsing is
+ * performed correctly.
*/
- (void)argv1;
- setargv(&argc, &argv);
+#if defined(__GNUC__)
+ setargv( &argc, &argv );
#endif
+ setlocale(LC_ALL, "C");
/*
* Forward slashes substituted for backslashes.
@@ -136,12 +96,10 @@ _tmain(
#ifdef TCL_LOCAL_MAIN_HOOK
TCL_LOCAL_MAIN_HOOK(&argc, &argv);
-#elif (TCL_MAJOR_VERSION > 8 || TCL_MINOR_VERSION > 6) && (!defined(_WIN32) || defined(UNICODE))
- /* New in Tcl 8.7. This doesn't work on Windows without UNICODE */
- TclZipfs_AppHook(&argc, &argv);
#endif
Tcl_Main(argc, argv, TCL_LOCAL_APPINIT);
+
return 0; /* Needed only to prevent compiler warning. */
}
@@ -150,9 +108,9 @@ _tmain(
*
* Tcl_AppInit --
*
- * This procedure performs application-specific initialization. Most
+ * This function performs application-specific initialization. Most
* applications, especially those that incorporate additional packages,
- * will have their own version of this procedure.
+ * will have their own version of this function.
*
* Results:
* Returns a standard Tcl completion code, and leaves an error message in
@@ -172,40 +130,53 @@ Tcl_AppInit(
return TCL_ERROR;
}
-#if defined(STATIC_BUILD)
- if (Registry_Init(interp) == TCL_ERROR) {
+#ifdef TCL_TEST
+ if (Tcltest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
- Tcl_StaticLibrary(interp, "Registry", Registry_Init, NULL);
-
- if (Dde_Init(interp) == TCL_ERROR) {
+ Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, NULL);
+ if (TclObjTest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
- Tcl_StaticLibrary(interp, "Dde", Dde_Init, Dde_SafeInit);
-#endif
-
-#ifdef TCL_TEST
- if (Tcltest_Init(interp) == TCL_ERROR) {
+ if (Procbodytest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
- Tcl_StaticLibrary(interp, "Tcltest", Tcltest_Init, Tcltest_SafeInit);
+ Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init,
+ Procbodytest_SafeInit);
#endif /* TCL_TEST */
+#if defined(STATIC_BUILD) && TCL_USE_STATIC_PACKAGES
+ {
+ extern Tcl_PackageInitProc Registry_Init;
+ extern Tcl_PackageInitProc Dde_Init;
+ extern Tcl_PackageInitProc Dde_SafeInit;
+
+ if (Registry_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ Tcl_StaticPackage(interp, "registry", Registry_Init, NULL);
+
+ if (Dde_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ Tcl_StaticPackage(interp, "dde", Dde_Init, Dde_SafeInit);
+ }
+#endif
+
/*
- * Call the init procedures for included packages. Each call should look
+ * Call the init functions for included packages. Each call should look
* like this:
*
* if (Mod_Init(interp) == TCL_ERROR) {
* return TCL_ERROR;
* }
*
- * where "Mod" is the name of the module. (Dynamically-loadable packages
- * should have the same entry-point name.)
+ * where "Mod" is the name of the module.
*/
/*
- * Call Tcl_CreateObjCommand for application-specific commands, if they
- * weren't already created by the init procedures called above.
+ * Call Tcl_CreateCommand for application-specific commands, if they
+ * weren't already created by the init functions called above.
*/
/*
@@ -215,8 +186,7 @@ Tcl_AppInit(
* user-specific startup file will be run under any conditions.
*/
- Tcl_ObjSetVar2(interp, Tcl_NewStringObj("tcl_rcFileName", TCL_INDEX_NONE), NULL,
- Tcl_NewStringObj("~/tclshrc.tcl", TCL_INDEX_NONE), TCL_GLOBAL_ONLY);
+ Tcl_SetVar(interp, "tcl_rcFileName", "~/tclshrc.tcl", TCL_GLOBAL_ONLY);
return TCL_OK;
}
@@ -247,17 +217,17 @@ Tcl_AppInit(
*--------------------------------------------------------------------------
*/
-#ifdef TCL_BROKEN_MAINARGS
+#if defined(__GNUC__)
static void
setargv(
int *argcPtr, /* Filled with number of argument strings. */
- TCHAR ***argvPtr) /* Filled with argument strings (malloc'd). */
+ char ***argvPtr) /* Filled with argument strings (malloc'd). */
{
- TCHAR *cmdLine, *p, *arg, *argSpace;
- TCHAR **argv;
+ char *cmdLine, *p, *arg, *argSpace;
+ char **argv;
int argc, size, inquote, copy, slashes;
- cmdLine = GetCommandLine();
+ cmdLine = GetCommandLine(); /* INTL: BUG */
/*
* Precompute an overly pessimistic guess at the number of arguments in
@@ -276,15 +246,10 @@ setargv(
}
}
}
-
- /* Make sure we don't call ckalloc through the (not yet initialized) stub table */
-# undef Tcl_Alloc
-# undef Tcl_DbCkalloc
-
- argSpace = (TCHAR *)ckalloc(size * sizeof(char *)
- + (_tcslen(cmdLine) * sizeof(TCHAR)) + sizeof(TCHAR));
- argv = (TCHAR **) argSpace;
- argSpace += size * (sizeof(char *)/sizeof(TCHAR));
+ argSpace = (char *) ckalloc(
+ (unsigned) (size * sizeof(char *) + strlen(cmdLine) + 1));
+ argv = (char **) argSpace;
+ argSpace += size * sizeof(char *);
size--;
p = cmdLine;
@@ -342,7 +307,7 @@ setargv(
*argcPtr = argc;
*argvPtr = argv;
}
-#endif /* TCL_BROKEN_MAINARGS */
+#endif /* __GNUC__ */
/*
* Local Variables:
diff --git a/win/tclConfig.sh.in b/win/tclConfig.sh.in
index 1c33246..75324b2 100644
--- a/win/tclConfig.sh.in
+++ b/win/tclConfig.sh.in
@@ -23,10 +23,9 @@ TCL_CC='@CC@'
# -D flags for use with the C compiler.
TCL_DEFS='@DEFS@'
-# TCL_DBGX used to be used to distinguish debug vs. non-debug builds.
-# This was a righteous pain so the core doesn't do that any more.
-# DEPRECATED, will be removed in Tcl 9!
-TCL_DBGX=''
+# If TCL was built with debugging symbols, generated libraries contain
+# this string at the end of the library name (before the extension).
+TCL_DBGX=@TCL_DBGX@
# Default flags used in an optimized and debuggable build, respectively.
TCL_CFLAGS_DEBUG='@CFLAGS_DEBUG@'
@@ -42,14 +41,14 @@ TCL_SHARED_BUILD=@TCL_SHARED_BUILD@
# The name of the Tcl library (may be either a .a file or a shared library):
TCL_LIB_FILE='@TCL_LIB_FILE@'
-# The name of a zip containing the /library and /encodings (may be either a .zip file or a shared library):
-TCL_ZIP_FILE='@TCL_ZIP_FILE@'
-
# Flag to indicate whether shared libraries need export files.
-TCL_NEEDS_EXP_FILE=''
+TCL_NEEDS_EXP_FILE=@TCL_NEEDS_EXP_FILE@
-# Deprecated. Same as TCL_UNSHARED_LIB_SUFFIX
-TCL_EXPORT_FILE_SUFFIX='@CFG_TCL_UNSHARED_LIB_SUFFIX@'
+# String that can be evaluated to generate the part of the export file
+# name that comes after the "libxxx" (includes version number, if any,
+# extension, and anything else needed). May depend on the variables
+# VERSION. On most UNIX systems this is ${VERSION}.exp.
+TCL_EXPORT_FILE_SUFFIX='@CFG_TCL_EXPORT_FILE_SUFFIX@'
# Additional libraries to use when linking Tcl.
TCL_LIBS='@LIBS@'
@@ -78,7 +77,7 @@ TCL_SHLIB_LD='@SHLIB_LD@'
TCL_STLIB_LD='@STLIB_LD@'
# Either '$LIBS' (if dependent libraries should be included when linking
-# shared libraries) or an empty string. See Tcl's configure.ac for more
+# shared libraries) or an empty string. See Tcl's configure.in for more
# explanation.
TCL_SHLIB_LD_LIBS='@SHLIB_LD_LIBS@'
@@ -93,11 +92,10 @@ TCL_DL_LIBS='@DL_LIBS@'
# an executable tclsh or tcltest binary.
TCL_LD_FLAGS='@LDFLAGS@'
-# Flags to pass to cc/ld, such as "-R /usr/local/tcl/lib", that tell the
+# Flags to pass to ld, such as "-R /usr/local/tcl/lib", that tell the
# run-time dynamic linker where to look for shared libraries such as
# libtcl.so. Used when linking applications. Only works if there
# is a variable "LIB_RUNTIME_DIR" defined in the Makefile.
-TCL_CC_SEARCH_FLAGS='@TCL_CC_SEARCH_FLAGS@'
TCL_LD_SEARCH_FLAGS='@TCL_LD_SEARCH_FLAGS@'
# Additional object files linked with Tcl to provide compatibility
@@ -126,7 +124,7 @@ TCL_INCLUDE_SPEC='@TCL_INCLUDE_SPEC@'
# ("ok" means it's safe to use switches like -ltcl7.5; "nodots" means
# use switches like -ltcl75). SunOS and FreeBSD require "nodots", for
# example.
-TCL_LIB_VERSIONS_OK='nodots'
+TCL_LIB_VERSIONS_OK='@TCL_LIB_VERSIONS_OK@'
# String that can be evaluated to generate the part of a shared library
# name that comes after the "libxxx" (includes version number, if any,
@@ -177,8 +175,6 @@ TCL_BUILD_STUB_LIB_PATH='@TCL_BUILD_STUB_LIB_PATH@'
# Path to the Tcl stub library in the install directory.
TCL_STUB_LIB_PATH='@TCL_STUB_LIB_PATH@'
-# Name of the zlib library that extensions should use
-TCL_ZLIB_LIB_NAME='@TCL_ZLIB_LIB_NAME@'
+# Flag, 1: we built Tcl with threads enabled, 0 we didn't
+TCL_THREADS=@TCL_THREADS@
-# Name of the tommath library that extensions should use
-TCL_TOMMATH_LIB_NAME='@TCL_TOMMATH_LIB_NAME@'
diff --git a/win/tclUuid.h.in b/win/tclUuid.h.in
deleted file mode 100644
index cbb83e4..0000000
--- a/win/tclUuid.h.in
+++ /dev/null
@@ -1 +0,0 @@
-#define TCL_VERSION_UUID \
diff --git a/win/tclWin32Dll.c b/win/tclWin32Dll.c
index 7c3d8a4..e5e5202 100644
--- a/win/tclWin32Dll.c
+++ b/win/tclWin32Dll.c
@@ -4,17 +4,38 @@
* This file contains the DLL entry point and other low-level bit bashing
* code that needs inline assembly.
*
- * Copyright © 1995-1996 Sun Microsystems, Inc.
- * Copyright © 1998-2000 Scriptics Corporation.
+ * Copyright (c) 1995-1996 Sun Microsystems, Inc.
+ * Copyright (c) 1998-2000 Scriptics Corporation.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclWinInt.h"
-#if defined(HAVE_INTRIN_H)
-# include <intrin.h>
-#endif
+
+#ifndef TCL_NO_STACK_CHECK
+/*
+ * The following functions implement stack depth checking
+ */
+typedef struct ThreadSpecificData {
+ int *stackBound; /* The current stack boundary */
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
+#endif /* TCL_NO_STACK_CHECK */
+
+/*
+ * The following data structures are used when loading the thunking library
+ * for execing child processes under Win32s.
+ */
+
+typedef DWORD (WINAPI UT32PROC)(LPVOID lpBuff, DWORD dwUserDefined,
+ LPVOID *lpTranslationList);
+
+typedef BOOL (WINAPI UTREGISTER)(HANDLE hModule, LPCSTR SixteenBitDLL,
+ LPCSTR InitName, LPCSTR ProcName, UT32PROC **ThirtyTwoBitThunk,
+ FARPROC UT32Callback, LPVOID Buff);
+
+typedef VOID (WINAPI UTUNREGISTER)(HANDLE hModule);
/*
* The following variables keep track of information about this DLL on a
@@ -23,13 +44,160 @@
*/
static HINSTANCE hInstance; /* HINSTANCE of this DLL. */
+static int platformId; /* Running under NT, or 95/98? */
/*
+ * VC++ 5.x has no 'cpuid' assembler instruction, so we must emulate it
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER <= 1100)
+#define cpuid __asm __emit 0fh __asm __emit 0a2h
+#endif
+
+/*
+ * The following function tables are used to dispatch to either the
+ * wide-character or multi-byte versions of the operating system calls,
+ * depending on whether the Unicode calls are available.
+ */
+
+static TclWinProcs asciiProcs = {
+ 0,
+
+ (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBA,
+ (TCHAR *(WINAPI *)(TCHAR *)) CharLowerA,
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileA,
+ (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryA,
+ (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *,
+ DWORD, DWORD, HANDLE)) CreateFileA,
+ (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES,
+ LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *,
+ LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessA,
+ (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileA,
+ (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileA,
+ (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileA,
+ (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameA,
+ (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryA,
+ (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesA,
+ (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *,
+ TCHAR **)) GetFullPathNameA,
+ (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameA,
+ (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameA,
+ (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique,
+ WCHAR *)) GetTempFileNameA,
+ (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathA,
+ (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD,
+ WCHAR *, DWORD)) GetVolumeInformationA,
+ (HINSTANCE (WINAPI *)(CONST TCHAR *, HANDLE, DWORD)) LoadLibraryExA,
+ (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyA,
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileA,
+ (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryA,
+ (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD,
+ WCHAR *, TCHAR **)) SearchPathA,
+ (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryA,
+ (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesA,
+
+ /*
+ * The three NULL function pointers will only be set when
+ * Tcl_FindExecutable is called. If you don't ever call that function, the
+ * application will crash whenever WinTcl tries to call functions through
+ * these null pointers. That is not a bug in Tcl - Tcl_FindExecutable is
+ * mandatory in recent Tcl releases.
+ */
+
+ NULL,
+ NULL,
+ /* deleted (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime, */
+ NULL,
+ NULL,
+ /* getLongPathNameProc */
+ NULL,
+ /* Security SDK - not available on 95,98,ME */
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ /* ReadConsole and WriteConsole */
+ (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleA,
+ (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleA,
+ (BOOL (WINAPI *)(LPTSTR, LPDWORD)) GetUserNameA
+};
+
+static TclWinProcs unicodeProcs = {
+ 1,
+
+ (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBW,
+ (TCHAR *(WINAPI *)(TCHAR *)) CharLowerW,
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileW,
+ (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryW,
+ (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *,
+ DWORD, DWORD, HANDLE)) CreateFileW,
+ (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES,
+ LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *,
+ LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessW,
+ (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileW,
+ (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileW,
+ (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileW,
+ (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameW,
+ (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryW,
+ (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesW,
+ (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *,
+ TCHAR **)) GetFullPathNameW,
+ (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameW,
+ (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameW,
+ (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique,
+ WCHAR *)) GetTempFileNameW,
+ (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathW,
+ (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD,
+ WCHAR *, DWORD)) GetVolumeInformationW,
+ (HINSTANCE (WINAPI *)(CONST TCHAR *, HANDLE, DWORD)) LoadLibraryExW,
+ (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyW,
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileW,
+ (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryW,
+ (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD,
+ WCHAR *, TCHAR **)) SearchPathW,
+ (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryW,
+ (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesW,
+
+ /*
+ * The three NULL function pointers will only be set when
+ * Tcl_FindExecutable is called. If you don't ever call that function, the
+ * application will crash whenever WinTcl tries to call functions through
+ * these null pointers. That is not a bug in Tcl - Tcl_FindExecutable is
+ * mandatory in recent Tcl releases.
+ */
+
+ NULL,
+ NULL,
+ /* deleted (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime, */
+ NULL,
+ NULL,
+ /* getLongPathNameProc */
+ NULL,
+ /* Security SDK - will be filled in on NT,XP,2000,2003 */
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ /* ReadConsole and WriteConsole */
+ (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleW,
+ (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleW,
+ (BOOL (WINAPI *)(LPTSTR, LPDWORD)) GetUserNameW
+};
+
+TclWinProcs *tclWinProcs;
+static Tcl_Encoding tclWinTCharEncoding;
+
+#ifdef HAVE_NO_SEH
+/*
+ * Need to add noinline flag to DllMain declaration so that gcc -O3 does not
+ * inline asm code into DllEntryPoint and cause a compile time error because
+ * of redefined local labels.
+ */
+
+BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason,
+ LPVOID reserved) __attribute__ ((noinline));
+#else
+/*
* The following declaration is for the VC++ DLL entry point.
*/
BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason,
LPVOID reserved);
+#endif /* HAVE_NO_SEH */
/*
* The following structure and linked list is to allow us to map between
@@ -38,8 +206,8 @@ BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason,
*/
typedef struct MountPointMap {
- WCHAR *volumeName; /* Native wide string volume name. */
- WCHAR driveLetter; /* Drive letter corresponding to the volume
+ CONST WCHAR *volumeName; /* Native wide string volume name. */
+ char driveLetter; /* Drive letter corresponding to the volume
* name. */
struct MountPointMap *nextPtr;
/* Pointer to next structure in list, or
@@ -58,7 +226,9 @@ TCL_DECLARE_MUTEX(mountPointMap)
* We will need this below.
*/
-#ifdef _WIN32
+extern Tcl_FSDupInternalRepProc TclNativeDupInternalRep;
+
+#ifdef __WIN32__
#ifndef STATIC_BUILD
/*
@@ -82,7 +252,7 @@ BOOL APIENTRY
DllEntryPoint(
HINSTANCE hInst, /* Library instance handle. */
DWORD reason, /* Reason this function is being called. */
- LPVOID reserved)
+ LPVOID reserved) /* Not used. */
{
return DllMain(hInst, reason, reserved);
}
@@ -100,7 +270,10 @@ DllEntryPoint(
* TRUE on sucess, FALSE on failure.
*
* Side effects:
- * Initializes most rudimentary Windows bits.
+ * Establishes 32-to-16 bit thunk and initializes sockets library. This
+ * might call some sycronization functions, but MSDN documentation
+ * states: "Waiting on synchronization objects in DllMain can cause a
+ * deadlock."
*
*----------------------------------------------------------------------
*/
@@ -109,24 +282,113 @@ BOOL APIENTRY
DllMain(
HINSTANCE hInst, /* Library instance handle. */
DWORD reason, /* Reason this function is being called. */
- TCL_UNUSED(LPVOID))
+ LPVOID reserved) /* Not used. */
{
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
+ TCLEXCEPTION_REGISTRATION registration;
+#endif
+
switch (reason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hInst);
TclWinInit(hInst);
return TRUE;
+ case DLL_PROCESS_DETACH:
/*
- * DLL_PROCESS_DETACH is unnecessary as the user should call
- * Tcl_Finalize explicitly before unloading Tcl.
+ * Protect the call to Tcl_Finalize. The OS could be unloading us from
+ * an exception handler and the state of the stack might be unstable.
*/
+
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
+ __asm__ __volatile__ (
+
+ /*
+ * Construct an TCLEXCEPTION_REGISTRATION to protect the call to
+ * Tcl_Finalize
+ */
+
+ "leal %[registration], %%edx" "\n\t"
+ "movl %%fs:0, %%eax" "\n\t"
+ "movl %%eax, 0x0(%%edx)" "\n\t" /* link */
+ "leal 1f, %%eax" "\n\t"
+ "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
+ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
+ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
+ "movl %[error], 0x10(%%edx)" "\n\t" /* status */
+
+ /*
+ * Link the TCLEXCEPTION_REGISTRATION on the chain
+ */
+
+ "movl %%edx, %%fs:0" "\n\t"
+
+ /*
+ * Call Tcl_Finalize
+ */
+
+ "call _Tcl_Finalize" "\n\t"
+
+ /*
+ * Come here on a normal exit. Recover the TCLEXCEPTION_REGISTRATION
+ * and store a TCL_OK status
+ */
+
+ "movl %%fs:0, %%edx" "\n\t"
+ "movl %[ok], %%eax" "\n\t"
+ "movl %%eax, 0x10(%%edx)" "\n\t"
+ "jmp 2f" "\n"
+
+ /*
+ * Come here on an exception. Get the TCLEXCEPTION_REGISTRATION that
+ * we previously put on the chain.
+ */
+
+ "1:" "\t"
+ "movl %%fs:0, %%edx" "\n\t"
+ "movl 0x8(%%edx), %%edx" "\n"
+
+
+ /*
+ * Come here however we exited. Restore context from the
+ * TCLEXCEPTION_REGISTRATION in case the stack is unbalanced.
+ */
+
+ "2:" "\t"
+ "movl 0xc(%%edx), %%esp" "\n\t"
+ "movl 0x8(%%edx), %%ebp" "\n\t"
+ "movl 0x0(%%edx), %%eax" "\n\t"
+ "movl %%eax, %%fs:0" "\n\t"
+
+ :
+ /* No outputs */
+ :
+ [registration] "m" (registration),
+ [ok] "i" (TCL_OK),
+ [error] "i" (TCL_ERROR)
+ :
+ "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
+ );
+
+#else
+#ifndef HAVE_NO_SEH
+ __try {
+#endif
+ Tcl_Finalize();
+#ifndef HAVE_NO_SEH
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ /* empty handler body. */
+ }
+#endif
+#endif
+
+ break;
}
return TRUE;
}
#endif /* !STATIC_BUILD */
-#endif /* _WIN32 */
+#endif /* __WIN32__ */
/*
*----------------------------------------------------------------------
@@ -175,15 +437,44 @@ TclWinInit(
hInstance = hInst;
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
GetVersionExW(&os);
+ platformId = os.dwPlatformId;
/*
- * We no longer support Win32s or Win9x or Windows CE or Windows XP, so just
- * in case someone manages to get a runtime there, make sure they know that.
+ * We no longer support Win32s, so just in case someone manages to get a
+ * runtime there, make sure they know that.
*/
- if (os.dwPlatformId != VER_PLATFORM_WIN32_NT) {
- Tcl_Panic("Windows 7 is the minimum supported platform");
+ if (platformId == VER_PLATFORM_WIN32s) {
+ Tcl_Panic("Win32s is not a supported platform");
}
+
+ tclWinProcs = &asciiProcs;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclWinGetPlatformId --
+ *
+ * Determines whether running under NT, 95, or Win32s, to allow runtime
+ * conditional code.
+ *
+ * Results:
+ * The return value is one of:
+ * VER_PLATFORM_WIN32s Win32s on Windows 3.1. (not supported)
+ * VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95, 98, ME.
+ * VER_PLATFORM_WIN32_NT Win32 on Windows NT, 2000, XP
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclWinGetPlatformId(void)
+{
+ return platformId;
}
/*
@@ -218,12 +509,95 @@ TclWinNoBackslash(
}
/*
+ *----------------------------------------------------------------------
+ *
+ * TclpGetStackParams --
+ *
+ * Determine the stack params for the current thread: in which
+ * direction does the stack grow, and what is the stack lower (resp.
+ * upper) bound for safe invocation of a new command? This is used to
+ * cache the values needed for an efficient computation of
+ * TclpCheckStackSpace() when the interp is known.
+ *
+ * Results:
+ * Returns 1 if the stack grows down, in which case a stack lower bound
+ * is stored at stackBoundPtr. If the stack grows up, 0 is returned and
+ * an upper bound is stored at stackBoundPtr. If a bound cannot be
+ * determined NULL is stored at stackBoundPtr.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#ifndef TCL_NO_STACK_CHECK
+int
+TclpGetCStackParams(
+ int **stackBoundPtr)
+{
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ SYSTEM_INFO si; /* The system information, used to
+ * determine the page size */
+ MEMORY_BASIC_INFORMATION mbi;
+ /* The information about the memory
+ * area in which the stack resides */
+
+ if (!tsdPtr->stackBound
+ || ((UINT_PTR)&tsdPtr < (UINT_PTR)tsdPtr->stackBound)) {
+
+ /*
+ * Either we haven't determined the stack bound in this thread,
+ * or else we've overflowed the bound that we previously
+ * determined. We need to find a new stack bound from
+ * Windows.
+ */
+
+ GetSystemInfo(&si);
+ if (VirtualQuery((LPCVOID) &tsdPtr, &mbi, sizeof(mbi)) == 0) {
+
+ /* For some reason, the system didn't let us query the
+ * stack size. Nevertheless, we got here and haven't
+ * blown up yet. Don't update the calculated stack bound.
+ * If there is no calculated stack bound yet, set it to
+ * the base of the current page of stack. */
+
+ if (!tsdPtr->stackBound) {
+ tsdPtr->stackBound =
+ (int*) ((UINT_PTR)(&tsdPtr)
+ & ~ (UINT_PTR)(si.dwPageSize - 1));
+ }
+
+ } else {
+
+ /* The allocation base of the stack segment has to be advanced
+ * by one page (to allow for the guard page maintained in the
+ * C runtime) and then by TCL_WIN_STACK_THRESHOLD (to allow
+ * for the amount of stack that Tcl needs).
+ */
+
+ tsdPtr->stackBound =
+ (int*) ((UINT_PTR)(mbi.AllocationBase)
+ + (UINT_PTR)(si.dwPageSize)
+ + TCL_WIN_STACK_THRESHOLD);
+ }
+ }
+ *stackBoundPtr = tsdPtr->stackBound;
+ return 1;
+}
+#endif
+
+
+/*
*---------------------------------------------------------------------------
*
- * TclWinEncodingsCleanup --
+ * TclWinSetInterfaces --
*
- * Called during finalization to clean up any memory allocated in our
- * mount point map which is used to follow certain kinds of symlinks.
+ * A helper proc that allows the test library to change the tclWinProcs
+ * structure to dispatch to either the wide-character or multi-byte
+ * versions of the operating system calls, depending on whether Unicode
+ * is the system encoding.
+ *
+ * As well as this, we can also try to load in some additional procs
+ * which may/may not be present depending on the current Windows version
+ * (e.g. Win95 will not have the procs below).
*
* Results:
* None.
@@ -235,9 +609,137 @@ TclWinNoBackslash(
*/
void
-TclWinEncodingsCleanup(void)
+TclWinSetInterfaces(
+ int wide) /* Non-zero to use wide interfaces, 0
+ * otherwise. */
+{
+ Tcl_FreeEncoding(tclWinTCharEncoding);
+
+ if (wide) {
+ tclWinProcs = &unicodeProcs;
+ tclWinTCharEncoding = Tcl_GetEncoding(NULL, "unicode");
+ if (tclWinProcs->getFileAttributesExProc == NULL) {
+ HINSTANCE hInstance = LoadLibraryA("kernel32");
+ if (hInstance != NULL) {
+ tclWinProcs->getFileAttributesExProc =
+ (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS,
+ LPVOID)) GetProcAddress(hInstance,
+ "GetFileAttributesExW");
+ tclWinProcs->createHardLinkProc =
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*,
+ LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance,
+ "CreateHardLinkW");
+ tclWinProcs->findFirstFileExProc =
+ (HANDLE (WINAPI *)(CONST TCHAR*, UINT, LPVOID, UINT,
+ LPVOID, DWORD)) GetProcAddress(hInstance,
+ "FindFirstFileExW");
+ tclWinProcs->getVolumeNameForVMPProc =
+ (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*,
+ DWORD)) GetProcAddress(hInstance,
+ "GetVolumeNameForVolumeMountPointW");
+ tclWinProcs->getLongPathNameProc =
+ (DWORD (WINAPI *)(CONST TCHAR*, TCHAR*,
+ DWORD)) GetProcAddress(hInstance, "GetLongPathNameW");
+ FreeLibrary(hInstance);
+ }
+ hInstance = LoadLibraryA("advapi32");
+ if (hInstance != NULL) {
+ tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)(
+ LPCTSTR lpFileName,
+ SECURITY_INFORMATION RequestedInformation,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ DWORD nLength, LPDWORD lpnLengthNeeded))
+ GetProcAddress(hInstance, "GetFileSecurityW");
+ tclWinProcs->impersonateSelfProc = (BOOL (WINAPI *) (
+ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel))
+ GetProcAddress(hInstance, "ImpersonateSelf");
+ tclWinProcs->openThreadTokenProc = (BOOL (WINAPI *) (
+ HANDLE ThreadHandle, DWORD DesiredAccess,
+ BOOL OpenAsSelf, PHANDLE TokenHandle))
+ GetProcAddress(hInstance, "OpenThreadToken");
+ tclWinProcs->revertToSelfProc = (BOOL (WINAPI *) (void))
+ GetProcAddress(hInstance, "RevertToSelf");
+ tclWinProcs->mapGenericMaskProc = (VOID (WINAPI *) (
+ PDWORD AccessMask, PGENERIC_MAPPING GenericMapping))
+ GetProcAddress(hInstance, "MapGenericMask");
+ tclWinProcs->accessCheckProc = (BOOL (WINAPI *)(
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ HANDLE ClientToken, DWORD DesiredAccess,
+ PGENERIC_MAPPING GenericMapping,
+ PPRIVILEGE_SET PrivilegeSet,
+ LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess,
+ LPBOOL AccessStatus)) GetProcAddress(hInstance,
+ "AccessCheck");
+ FreeLibrary(hInstance);
+ }
+ }
+ } else {
+ tclWinProcs = &asciiProcs;
+ tclWinTCharEncoding = NULL;
+ if (tclWinProcs->getFileAttributesExProc == NULL) {
+ HINSTANCE hInstance = LoadLibraryA("kernel32");
+ if (hInstance != NULL) {
+ tclWinProcs->getFileAttributesExProc =
+ (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS,
+ LPVOID)) GetProcAddress(hInstance,
+ "GetFileAttributesExA");
+ tclWinProcs->createHardLinkProc =
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*,
+ LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance,
+ "CreateHardLinkA");
+ tclWinProcs->findFirstFileExProc = NULL;
+ tclWinProcs->getLongPathNameProc = NULL;
+ /*
+ * The 'findFirstFileExProc' function exists on some of
+ * 95/98/ME, but it seems not to work as anticipated.
+ * Therefore we don't set this function pointer. The relevant
+ * code will fall back on a slower approach using the normal
+ * findFirstFileProc.
+ *
+ * (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
+ * LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance,
+ * "FindFirstFileExA");
+ */
+ tclWinProcs->getVolumeNameForVMPProc =
+ (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*,
+ DWORD)) GetProcAddress(hInstance,
+ "GetVolumeNameForVolumeMountPointA");
+ FreeLibrary(hInstance);
+ }
+ }
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TclWinResetInterfaceEncodings --
+ *
+ * Called during finalization to free up any encodings we use. The
+ * tclWinProcs-> look up table is still ok to use after this call,
+ * provided no encoding conversion is required.
+ *
+ * We also clean up any memory allocated in our mount point map which is
+ * used to follow certain kinds of symlinks. That code should never be
+ * used once encodings are taken down.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+TclWinResetInterfaceEncodings(void)
{
MountPointMap *dlIter, *dlIter2;
+ if (tclWinTCharEncoding != NULL) {
+ Tcl_FreeEncoding(tclWinTCharEncoding);
+ tclWinTCharEncoding = NULL;
+ }
/*
* Clean up the mount point map.
@@ -247,14 +749,37 @@ TclWinEncodingsCleanup(void)
dlIter = driveLetterLookup;
while (dlIter != NULL) {
dlIter2 = dlIter->nextPtr;
- ckfree(dlIter->volumeName);
- ckfree(dlIter);
+ ckfree((char*)dlIter->volumeName);
+ ckfree((char*)dlIter);
dlIter = dlIter2;
}
Tcl_MutexUnlock(&mountPointMap);
}
/*
+ *---------------------------------------------------------------------------
+ *
+ * TclWinResetInterfaces --
+ *
+ * Called during finalization to reset us to a safe state for reuse.
+ * After this call, it is best not to use the tclWinProcs-> look up table
+ * since it is likely to be different to what is expected.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+void
+TclWinResetInterfaces(void)
+{
+ tclWinProcs = &asciiProcs;
+}
+
+/*
*--------------------------------------------------------------------
*
* TclWinDriveLetterForVolMountPoint
@@ -278,11 +803,11 @@ TclWinEncodingsCleanup(void)
char
TclWinDriveLetterForVolMountPoint(
- const WCHAR *mountPoint)
+ CONST WCHAR *mountPoint)
{
MountPointMap *dlIter, *dlPtr2;
WCHAR Target[55]; /* Target of mount at mount point */
- WCHAR drive[4] = L"A:\\";
+ WCHAR drive[4] = { L'A', L':', L'\\', L'\0' };
/*
* Detect the volume mounted there. Unfortunately, there is no simple way
@@ -300,21 +825,21 @@ TclWinDriveLetterForVolMountPoint(
* mount points on the fly.
*/
- drive[0] = (WCHAR) dlIter->driveLetter;
+ drive[0] = L'A' + (dlIter->driveLetter - 'A');
/*
* Try to read the volume mount point and see where it points.
*/
- if (GetVolumeNameForVolumeMountPointW(drive,
- Target, 55) != 0) {
- if (wcscmp(dlIter->volumeName, Target) == 0) {
+ if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive,
+ (TCHAR*)Target, 55) != 0) {
+ if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
/*
* Nothing has changed.
*/
Tcl_MutexUnlock(&mountPointMap);
- return (char) dlIter->driveLetter;
+ return dlIter->driveLetter;
}
}
@@ -341,8 +866,8 @@ TclWinDriveLetterForVolMountPoint(
* Now dlPtr2 points to the structure to free.
*/
- ckfree(dlPtr2->volumeName);
- ckfree(dlPtr2);
+ ckfree((char*)dlPtr2->volumeName);
+ ckfree((char*)dlPtr2);
/*
* Restart the loop - we could try to be clever and continue half
@@ -360,28 +885,28 @@ TclWinDriveLetterForVolMountPoint(
* We couldn't find it, so we must iterate over the letters.
*/
- for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++) {
+ for (drive[0] = L'A'; drive[0] <= L'Z'; drive[0]++) {
/*
* Try to read the volume mount point and see where it points.
*/
- if (GetVolumeNameForVolumeMountPointW(drive,
- Target, 55) != 0) {
+ if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive,
+ (TCHAR*)Target, 55) != 0) {
int alreadyStored = 0;
for (dlIter = driveLetterLookup; dlIter != NULL;
dlIter = dlIter->nextPtr) {
- if (wcscmp(dlIter->volumeName, Target) == 0) {
+ if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
alreadyStored = 1;
break;
}
}
if (!alreadyStored) {
- dlPtr2 = (MountPointMap *)ckalloc(sizeof(MountPointMap));
- dlPtr2->volumeName = (WCHAR *)TclNativeDupInternalRep(Target);
- dlPtr2->driveLetter = (WCHAR) drive[0];
+ dlPtr2 = (MountPointMap *) ckalloc(sizeof(MountPointMap));
+ dlPtr2->volumeName = TclNativeDupInternalRep(Target);
+ dlPtr2->driveLetter = 'A' + (drive[0] - L'A');
dlPtr2->nextPtr = driveLetterLookup;
- driveLetterLookup = dlPtr2;
+ driveLetterLookup = dlPtr2;
}
}
}
@@ -394,7 +919,7 @@ TclWinDriveLetterForVolMountPoint(
dlIter = dlIter->nextPtr) {
if (wcscmp(dlIter->volumeName, mountPoint) == 0) {
Tcl_MutexUnlock(&mountPointMap);
- return (char) dlIter->driveLetter;
+ return dlIter->driveLetter;
}
}
@@ -403,11 +928,11 @@ TclWinDriveLetterForVolMountPoint(
* that fact and store '-1' so we don't have to look it up each time.
*/
- dlPtr2 = (MountPointMap *)ckalloc(sizeof(MountPointMap));
- dlPtr2->volumeName = (WCHAR *)TclNativeDupInternalRep((void *)mountPoint);
- dlPtr2->driveLetter = (WCHAR)-1;
+ dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap));
+ dlPtr2->volumeName = TclNativeDupInternalRep((ClientData)mountPoint);
+ dlPtr2->driveLetter = -1;
dlPtr2->nextPtr = driveLetterLookup;
- driveLetterLookup = dlPtr2;
+ driveLetterLookup = dlPtr2;
Tcl_MutexUnlock(&mountPointMap);
return -1;
}
@@ -417,32 +942,39 @@ TclWinDriveLetterForVolMountPoint(
*
* Tcl_WinUtfToTChar, Tcl_WinTCharToUtf --
*
- * Convert between UTF-8 and Unicode when running Windows.
+ * Convert between UTF-8 and Unicode when running Windows NT or the
+ * current ANSI code page when running Windows 95.
*
- * On Mac and Unix, all strings exchanged between Tcl and the OS are
- * "char" oriented. We need only one Tcl_Encoding to convert between
- * UTF-8 and the system's native encoding. We use NULL to represent
- * that encoding.
+ * On Mac, Unix, and Windows 95, all strings exchanged between Tcl and
+ * the OS are "char" oriented. We need only one Tcl_Encoding to convert
+ * between UTF-8 and the system's native encoding. We use NULL to
+ * represent that encoding.
*
- * On Windows, some strings exchanged between Tcl and the OS are "char"
+ * On NT, some strings exchanged between Tcl and the OS are "char"
* oriented, while others are in Unicode. We need two Tcl_Encoding APIs
* depending on whether we are targeting a "char" or Unicode interface.
*
- * Calling Tcl_UtfToExternal() or Tcl_ExternalToUtf() with an encoding
- * of NULL should always used to convert between UTF-8 and the system's
+ * Calling Tcl_UtfToExternal() or Tcl_ExternalToUtf() with an encoding of
+ * NULL should always used to convert between UTF-8 and the system's
* "char" oriented encoding. The following two functions are used in
- * Windows-specific code to convert between UTF-8 and Unicode strings.
- * This saves you the trouble of writing the
+ * Windows-specific code to convert between UTF-8 and Unicode strings
+ * (NT) or "char" strings(95). This saves you the trouble of writing the
* following type of fragment over and over:
*
- * encoding <- Tcl_GetEncoding("unicode");
- * nativeBuffer <- UtfToExternal(encoding, utfBuffer);
- * Tcl_FreeEncoding(encoding);
+ * if (running NT) {
+ * encoding <- Tcl_GetEncoding("unicode");
+ * nativeBuffer <- UtfToExternal(encoding, utfBuffer);
+ * Tcl_FreeEncoding(encoding);
+ * } else {
+ * nativeBuffer <- UtfToExternal(NULL, utfBuffer);
+ * }
*
- * By convention, in Windows a WCHAR is a Unicode character. If you plan
- * on targeting a Unicode interface when running on Windows, these
- * functions should be used. If you plan on targetting a "char" oriented
- * function on Windows, use Tcl_UtfToExternal() with an encoding of NULL.
+ * By convention, in Windows a TCHAR is a character in the ANSI code page
+ * on Windows 95, a Unicode character on Windows NT. If you plan on
+ * targeting a Unicode interfaces when running on NT and a "char"
+ * oriented interface while running on 95, these functions should be
+ * used. If you plan on targetting the same "char" oriented function on
+ * both 95 and NT, use Tcl_UtfToExternal() with an encoding of NULL.
*
* Results:
* The result is a pointer to the string in the desired target encoding.
@@ -455,32 +987,30 @@ TclWinDriveLetterForVolMountPoint(
*---------------------------------------------------------------------------
*/
-#if !defined(TCL_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9
-#undef Tcl_WinUtfToTChar
TCHAR *
Tcl_WinUtfToTChar(
- const char *string, /* Source string in UTF-8. */
- int len, /* Source string length in bytes, or -1 for
+ CONST char *string, /* Source string in UTF-8. */
+ int len, /* Source string length in bytes, or < 0 for
* strlen(). */
Tcl_DString *dsPtr) /* Uninitialized or free DString in which the
* converted string is stored. */
{
- Tcl_DStringInit(dsPtr);
- return (TCHAR *)Tcl_UtfToWCharDString(string, len, dsPtr);
+ return (TCHAR *) Tcl_UtfToExternalDString(tclWinTCharEncoding,
+ string, len, dsPtr);
}
-#undef Tcl_WinTCharToUtf
+
char *
Tcl_WinTCharToUtf(
- const TCHAR *string, /* Source string in Unicode. */
- int len, /* Source string length in bytes, or -1 for
+ CONST TCHAR *string, /* Source string in Unicode when running NT,
+ * ANSI when running 95. */
+ int len, /* Source string length in bytes, or < 0 for
* platform-specific string length. */
Tcl_DString *dsPtr) /* Uninitialized or free DString in which the
* converted string is stored. */
{
- Tcl_DStringInit(dsPtr);
- return Tcl_WCharToUtfDString((WCHAR *)string, len >> 1, dsPtr);
+ return Tcl_ExternalToUtfDString(tclWinTCharEncoding,
+ (CONST char *) string, len, dsPtr);
}
-#endif /* !defined(TCL_NO_DEPRECATED) */
/*
*------------------------------------------------------------------------
@@ -502,21 +1032,16 @@ Tcl_WinTCharToUtf(
int
TclWinCPUID(
- int index, /* Which CPUID value to retrieve. */
- int *regsPtr) /* Registers after the CPUID. */
+ unsigned int index, /* Which CPUID value to retrieve. */
+ unsigned int *regsPtr) /* Registers after the CPUID. */
{
int status = TCL_ERROR;
-#if defined(HAVE_INTRIN_H) && defined(_WIN64) && defined(HAVE_CPUID)
-
- __cpuid((int *)regsPtr, index);
- status = TCL_OK;
-
-#elif defined(__GNUC__) && defined(HAVE_CPUID)
+#if defined(__GNUC__)
# if defined(_WIN64)
/*
* Execute the CPUID instruction with the given index, and store results
- * off 'regPtr'.
+ * off 'regsPtr'.
*/
__asm__ __volatile__(
@@ -531,7 +1056,7 @@ TclWinCPUID(
"movl %%eax, 0x0(%%edi)" "\n\t"
"movl %%ebx, 0x4(%%edi)" "\n\t"
"movl %%ecx, 0x8(%%edi)" "\n\t"
- "movl %%edx, 0xC(%%edi)" "\n\t"
+ "movl %%edx, 0xc(%%edi)" "\n\t"
:
/* No outputs */
@@ -563,7 +1088,7 @@ TclWinCPUID(
"leal 1f, %%eax" "\n\t"
"movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
"movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
- "movl %%esp, 0xC(%%edx)" "\n\t" /* esp */
+ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
"movl %[error], 0x10(%%edx)" "\n\t" /* status */
/*
@@ -583,7 +1108,7 @@ TclWinCPUID(
"movl %%eax, 0x0(%%edi)" "\n\t"
"movl %%ebx, 0x4(%%edi)" "\n\t"
"movl %%ecx, 0x8(%%edi)" "\n\t"
- "movl %%edx, 0xC(%%edi)" "\n\t"
+ "movl %%edx, 0xc(%%edi)" "\n\t"
/*
* Come here on a normal exit. Recover the TCLEXCEPTION_REGISTRATION and
@@ -610,7 +1135,7 @@ TclWinCPUID(
*/
"2:" "\t"
- "movl 0xC(%%edx), %%esp" "\n\t"
+ "movl 0xc(%%edx), %%esp" "\n\t"
"movl 0x8(%%edx), %%ebp" "\n\t"
"movl 0x0(%%edx), %%eax" "\n\t"
"movl %%eax, %%fs:0" "\n\t"
@@ -628,13 +1153,13 @@ TclWinCPUID(
status = registration.status;
# endif /* !_WIN64 */
-#elif defined(_MSC_VER) && defined(HAVE_CPUID)
+#elif defined(_MSC_VER)
# if defined(_WIN64)
__cpuid(regsPtr, index);
status = TCL_OK;
-# elif defined (_M_IX86)
+# else
/*
* Define a structure in the stack frame to hold the registers.
*/
@@ -683,8 +1208,6 @@ TclWinCPUID(
# endif
#else
- (void)index;
- (void)regsPtr;
/*
* Don't know how to do assembly code for this compiler and/or
* architecture.
diff --git a/win/tclWinChan.c b/win/tclWinChan.c
index 9b018e4..a271919 100644
--- a/win/tclWinChan.c
+++ b/win/tclWinChan.c
@@ -4,7 +4,7 @@
* Channel drivers for Windows channels based on files, command pipes and
* TCP sockets.
*
- * Copyright © 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -25,8 +25,7 @@
#define FILE_TYPE_CONSOLE (FILE_TYPE_PIPE+2)
/*
- * The following structure contains per-instance data for a file based
- * channel.
+ * The following structure contains per-instance data for a file based channel.
*/
typedef struct FileInfo {
@@ -44,7 +43,7 @@ typedef struct FileInfo {
* pending on the channel. */
} FileInfo;
-typedef struct {
+typedef struct ThreadSpecificData {
/*
* List of all file channels currently open.
*/
@@ -59,7 +58,7 @@ static Tcl_ThreadDataKey dataKey;
* events are generated.
*/
-typedef struct {
+typedef struct FileEvent {
Tcl_Event header; /* Information that is standard for all
* events. */
FileInfo *infoPtr; /* Pointer to file info structure. Note that
@@ -72,110 +71,54 @@ typedef struct {
* Static routines for this file:
*/
-static int FileBlockProc(void *instanceData, int mode);
-static void FileChannelExitHandler(void *clientData);
-static void FileCheckProc(void *clientData, int flags);
-static int FileCloseProc(void *instanceData,
- Tcl_Interp *interp, int flags);
+static int FileBlockProc(ClientData instanceData, int mode);
+static void FileChannelExitHandler(ClientData clientData);
+static void FileCheckProc(ClientData clientData, int flags);
+static int FileCloseProc(ClientData instanceData,
+ Tcl_Interp *interp);
static int FileEventProc(Tcl_Event *evPtr, int flags);
-static int FileGetHandleProc(void *instanceData,
- int direction, void **handlePtr);
-static int FileGetOptionProc(void *instanceData,
- Tcl_Interp *interp, const char *optionName,
- Tcl_DString *dsPtr);
+static int FileGetHandleProc(ClientData instanceData,
+ int direction, ClientData *handlePtr);
static ThreadSpecificData *FileInit(void);
-static int FileInputProc(void *instanceData, char *buf,
+static int FileInputProc(ClientData instanceData, char *buf,
int toRead, int *errorCode);
-static int FileOutputProc(void *instanceData,
- const char *buf, int toWrite, int *errorCode);
-#ifndef TCL_NO_DEPRECATED
-static int FileSeekProc(void *instanceData, long offset,
+static int FileOutputProc(ClientData instanceData,
+ CONST char *buf, int toWrite, int *errorCode);
+static int FileSeekProc(ClientData instanceData, long offset,
int mode, int *errorCode);
-#endif
-static long long FileWideSeekProc(void *instanceData,
- long long offset, int mode, int *errorCode);
-static void FileSetupProc(void *clientData, int flags);
-static void FileWatchProc(void *instanceData, int mask);
-static void FileThreadActionProc(void *instanceData,
+static Tcl_WideInt FileWideSeekProc(ClientData instanceData,
+ Tcl_WideInt offset, int mode, int *errorCode);
+static void FileSetupProc(ClientData clientData, int flags);
+static void FileWatchProc(ClientData instanceData, int mask);
+static void FileThreadActionProc(ClientData instanceData,
int action);
-static int FileTruncateProc(void *instanceData,
- long long length);
+static int FileTruncateProc(ClientData instanceData,
+ Tcl_WideInt length);
static DWORD FileGetType(HANDLE handle);
-static int NativeIsComPort(const WCHAR *nativeName);
-static Tcl_Channel OpenFileChannel(HANDLE handle, char *channelName,
- int permissions, int appendMode);
-
+static int NativeIsComPort(CONST TCHAR *nativeName);
/*
* This structure describes the channel type structure for file based IO.
*/
-static const Tcl_ChannelType fileChannelType = {
+static Tcl_ChannelType fileChannelType = {
"file", /* Type name. */
TCL_CHANNEL_VERSION_5, /* v5 channel */
- TCL_CLOSE2PROC, /* Close proc. */
+ FileCloseProc, /* Close proc. */
FileInputProc, /* Input proc. */
FileOutputProc, /* Output proc. */
-#ifndef TCL_NO_DEPRECATED
FileSeekProc, /* Seek proc. */
-#else
- NULL,
-#endif
NULL, /* Set option proc. */
- FileGetOptionProc, /* Get option proc. */
+ NULL, /* Get option proc. */
FileWatchProc, /* Set up the notifier to watch the channel. */
FileGetHandleProc, /* Get an OS handle from channel. */
- FileCloseProc, /* close2proc. */
+ NULL, /* close2proc. */
FileBlockProc, /* Set blocking or non-blocking mode.*/
NULL, /* flush proc. */
NULL, /* handler proc. */
FileWideSeekProc, /* Wide seek proc. */
FileThreadActionProc, /* Thread action proc. */
- FileTruncateProc /* Truncate proc. */
+ FileTruncateProc, /* Truncate proc. */
};
-
-/*
- * General useful clarification macros.
- */
-
-#define SET_FLAG(var, flag) ((var) |= (flag))
-#define CLEAR_FLAG(var, flag) ((var) &= ~(flag))
-#define TEST_FLAG(value, flag) (((value) & (flag)) != 0)
-
-/*
- * The number of 100-ns intervals between the Windows system epoch (1601-01-01
- * on the proleptic Gregorian calendar) and the Posix epoch (1970-01-01).
- */
-
-#define POSIX_EPOCH_AS_FILETIME \
- ((long long) 116444736 * (long long) 1000000000)
-
-
-/*
- *----------------------------------------------------------------------
- *
- * TclWinGenerateChannelName --
- *
- * This function generates names for channels.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Creates a new window and creates an exit handler.
- *
- *----------------------------------------------------------------------
- */
-void
-TclWinGenerateChannelName(
- char channelName[], /* Buffer to accept the name. */
- const char *channelTypeName,/* Name of type of channel. */
- void *channelImpl) /* Pointer to channel implementation
- * structure, used to generate a unique
- * ID. */
-{
- snprintf(channelName, 16 + TCL_INTEGER_SPACE, "%s%" TCL_Z_MODIFIER "x",
- channelTypeName, (size_t) channelImpl);
-}
/*
*----------------------------------------------------------------------
@@ -197,7 +140,7 @@ static ThreadSpecificData *
FileInit(void)
{
ThreadSpecificData *tsdPtr =
- (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey);
+ (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
if (tsdPtr == NULL) {
tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -227,7 +170,7 @@ FileInit(void)
static void
FileChannelExitHandler(
- TCL_UNUSED(void *))
+ ClientData clientData) /* Old window proc */
{
Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL);
}
@@ -251,14 +194,14 @@ FileChannelExitHandler(
void
FileSetupProc(
- TCL_UNUSED(void *),
+ ClientData data, /* Not used. */
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
FileInfo *infoPtr;
Tcl_Time blockTime = { 0, 0 };
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- if (!TEST_FLAG(flags, TCL_FILE_EVENTS)) {
+ if (!(flags & TCL_FILE_EVENTS)) {
return;
}
@@ -294,14 +237,14 @@ FileSetupProc(
static void
FileCheckProc(
- TCL_UNUSED(void *),
+ ClientData data, /* Not used. */
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
FileEvent *evPtr;
FileInfo *infoPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- if (!TEST_FLAG(flags, TCL_FILE_EVENTS)) {
+ if (!(flags & TCL_FILE_EVENTS)) {
return;
}
@@ -312,9 +255,9 @@ FileCheckProc(
for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
infoPtr = infoPtr->nextPtr) {
- if (infoPtr->watchMask && !TEST_FLAG(infoPtr->flags, FILE_PENDING)) {
- SET_FLAG(infoPtr->flags, FILE_PENDING);
- evPtr = (FileEvent *)ckalloc(sizeof(FileEvent));
+ if (infoPtr->watchMask && !(infoPtr->flags & FILE_PENDING)) {
+ infoPtr->flags |= FILE_PENDING;
+ evPtr = (FileEvent *) ckalloc(sizeof(FileEvent));
evPtr->header.proc = FileEventProc;
evPtr->infoPtr = infoPtr;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
@@ -353,7 +296,7 @@ FileEventProc(
FileInfo *infoPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- if (!TEST_FLAG(flags, TCL_FILE_EVENTS)) {
+ if (!(flags & TCL_FILE_EVENTS)) {
return 0;
}
@@ -367,7 +310,7 @@ FileEventProc(
for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
infoPtr = infoPtr->nextPtr) {
if (fileEvPtr->infoPtr == infoPtr) {
- CLEAR_FLAG(infoPtr->flags, FILE_PENDING);
+ infoPtr->flags &= ~(FILE_PENDING);
Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask);
break;
}
@@ -393,11 +336,11 @@ FileEventProc(
static int
FileBlockProc(
- void *instanceData, /* Instance data for channel. */
+ ClientData instanceData, /* Instance data for channel. */
int mode) /* TCL_MODE_BLOCKING or
* TCL_MODE_NONBLOCKING. */
{
- FileInfo *infoPtr = (FileInfo *)instanceData;
+ FileInfo *infoPtr = (FileInfo *) instanceData;
/*
* Files on Windows can not be switched between blocking and nonblocking,
@@ -407,9 +350,9 @@ FileBlockProc(
*/
if (mode == TCL_MODE_NONBLOCKING) {
- SET_FLAG(infoPtr->flags, FILE_ASYNC);
+ infoPtr->flags |= FILE_ASYNC;
} else {
- CLEAR_FLAG(infoPtr->flags, FILE_ASYNC);
+ infoPtr->flags &= ~(FILE_ASYNC);
}
return 0;
}
@@ -432,19 +375,14 @@ FileBlockProc(
static int
FileCloseProc(
- void *instanceData, /* Pointer to FileInfo structure. */
- TCL_UNUSED(Tcl_Interp *),
- int flags)
+ ClientData instanceData, /* Pointer to FileInfo structure. */
+ Tcl_Interp *interp) /* Not used. */
{
- FileInfo *fileInfoPtr = (FileInfo *)instanceData;
+ FileInfo *fileInfoPtr = (FileInfo *) instanceData;
FileInfo *infoPtr;
ThreadSpecificData *tsdPtr;
int errorCode = 0;
- if ((flags & (TCL_CLOSE_READ | TCL_CLOSE_WRITE)) != 0) {
- return EINVAL;
- }
-
/*
* Remove the file from the watch list.
*/
@@ -462,7 +400,7 @@ FileCloseProc(
&& (GetStdHandle(STD_OUTPUT_HANDLE) != fileInfoPtr->handle)
&& (GetStdHandle(STD_ERROR_HANDLE) != fileInfoPtr->handle))) {
if (CloseHandle(fileInfoPtr->handle) == FALSE) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
errorCode = errno;
}
}
@@ -486,7 +424,7 @@ FileCloseProc(
break;
}
}
- ckfree(fileInfoPtr);
+ ckfree((char *)fileInfoPtr);
return errorCode;
}
@@ -507,15 +445,15 @@ FileCloseProc(
*
*----------------------------------------------------------------------
*/
-#ifndef TCL_NO_DEPRECATED
+
static int
FileSeekProc(
- void *instanceData, /* File state. */
+ ClientData instanceData, /* File state. */
long offset, /* Offset to seek to. */
int mode, /* Relative to where should we seek? */
int *errorCodePtr) /* To store error code. */
{
- FileInfo *infoPtr = (FileInfo *)instanceData;
+ FileInfo *infoPtr = (FileInfo *) instanceData;
LONG newPos, newPosHigh, oldPos, oldPosHigh;
DWORD moveMethod;
@@ -534,11 +472,11 @@ FileSeekProc(
oldPosHigh = 0;
oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh, FILE_CURRENT);
- if (oldPos == (LONG) INVALID_SET_FILE_POINTER) {
+ if (oldPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
if (winError != NO_ERROR) {
- Tcl_WinConvertError(winError);
+ TclWinConvertError(winError);
*errorCodePtr = errno;
return -1;
}
@@ -546,11 +484,11 @@ FileSeekProc(
newPosHigh = (offset < 0 ? -1 : 0);
newPos = SetFilePointer(infoPtr->handle, offset, &newPosHigh, moveMethod);
- if (newPos == (LONG) INVALID_SET_FILE_POINTER) {
+ if (newPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
if (winError != NO_ERROR) {
- Tcl_WinConvertError(winError);
+ TclWinConvertError(winError);
*errorCodePtr = errno;
return -1;
}
@@ -567,7 +505,6 @@ FileSeekProc(
}
return (int) newPos;
}
-#endif
/*
*----------------------------------------------------------------------
@@ -587,14 +524,14 @@ FileSeekProc(
*----------------------------------------------------------------------
*/
-static long long
+static Tcl_WideInt
FileWideSeekProc(
- void *instanceData, /* File state. */
- long long offset, /* Offset to seek to. */
+ ClientData instanceData, /* File state. */
+ Tcl_WideInt offset, /* Offset to seek to. */
int mode, /* Relative to where should we seek? */
int *errorCodePtr) /* To store error code. */
{
- FileInfo *infoPtr = (FileInfo *)instanceData;
+ FileInfo *infoPtr = (FileInfo *) instanceData;
DWORD moveMethod;
LONG newPos, newPosHigh;
@@ -607,20 +544,19 @@ FileWideSeekProc(
moveMethod = FILE_END;
}
- newPosHigh = (LONG)(offset >> 32);
- newPos = SetFilePointer(infoPtr->handle, (LONG)offset,
+ newPosHigh = Tcl_WideAsLong(offset >> 32);
+ newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(offset),
&newPosHigh, moveMethod);
- if (newPos == (LONG) INVALID_SET_FILE_POINTER) {
+ if (newPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
if (winError != NO_ERROR) {
- Tcl_WinConvertError(winError);
+ TclWinConvertError(winError);
*errorCodePtr = errno;
return -1;
}
}
- return (((long long)((unsigned)newPos))
- | ((long long)newPosHigh << 32));
+ return (((Tcl_WideInt)((unsigned)newPos)) | (Tcl_LongAsWide(newPosHigh) << 32));
}
/*
@@ -641,10 +577,10 @@ FileWideSeekProc(
static int
FileTruncateProc(
- void *instanceData, /* File state. */
- long long length) /* Length to truncate at. */
+ ClientData instanceData, /* File state. */
+ Tcl_WideInt length) /* Length to truncate at. */
{
- FileInfo *infoPtr = (FileInfo *)instanceData;
+ FileInfo *infoPtr = (FileInfo *) instanceData;
LONG newPos, newPosHigh, oldPos, oldPosHigh;
/*
@@ -653,11 +589,10 @@ FileTruncateProc(
oldPosHigh = 0;
oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh, FILE_CURRENT);
- if (oldPos == (LONG) INVALID_SET_FILE_POINTER) {
+ if (oldPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
-
if (winError != NO_ERROR) {
- Tcl_WinConvertError(winError);
+ TclWinConvertError(winError);
return errno;
}
}
@@ -666,14 +601,13 @@ FileTruncateProc(
* Move to where we want to truncate
*/
- newPosHigh = (LONG)(length >> 32);
- newPos = SetFilePointer(infoPtr->handle, (LONG)length,
+ newPosHigh = Tcl_WideAsLong(length >> 32);
+ newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(length),
&newPosHigh, FILE_BEGIN);
- if (newPos == (LONG) INVALID_SET_FILE_POINTER) {
+ if (newPos == (LONG)INVALID_SET_FILE_POINTER) {
DWORD winError = GetLastError();
-
if (winError != NO_ERROR) {
- Tcl_WinConvertError(winError);
+ TclWinConvertError(winError);
return errno;
}
}
@@ -684,7 +618,7 @@ FileTruncateProc(
*/
if (!SetEndOfFile(infoPtr->handle)) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return errno;
}
@@ -717,21 +651,18 @@ FileTruncateProc(
static int
FileInputProc(
- void *instanceData, /* File state. */
+ ClientData instanceData, /* File state. */
char *buf, /* Where to store data read. */
int bufSize, /* Num bytes available in buffer. */
int *errorCode) /* Where to store error code. */
{
- FileInfo *infoPtr = (FileInfo *)instanceData;
+ FileInfo *infoPtr;
DWORD bytesRead;
*errorCode = 0;
+ infoPtr = (FileInfo *) instanceData;
/*
- * TODO: This comment appears to be out of date. We *do* have a console
- * driver, over in tclWinConsole.c. After some Windows developer confirms,
- * this comment should be revised.
- *
* Note that we will block on reads from a console buffer until a full
* line has been entered. The only way I know of to get around this is to
* write a console driver. We should probably do this at some point, but
@@ -741,10 +672,10 @@ FileInputProc(
if (ReadFile(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &bytesRead,
(LPOVERLAPPED) NULL) != FALSE) {
- return (int)bytesRead;
+ return bytesRead;
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
*errorCode = errno;
if (errno == EPIPE) {
return 0;
@@ -772,12 +703,12 @@ FileInputProc(
static int
FileOutputProc(
- void *instanceData, /* File state. */
- const char *buf, /* The data buffer. */
+ ClientData instanceData, /* File state. */
+ CONST char *buf, /* The data buffer. */
int toWrite, /* How many bytes to write? */
int *errorCode) /* Where to store error code. */
{
- FileInfo *infoPtr = (FileInfo *)instanceData;
+ FileInfo *infoPtr = (FileInfo *) instanceData;
DWORD bytesWritten;
*errorCode = 0;
@@ -787,18 +718,18 @@ FileOutputProc(
* seek to the end of the file before writing the current buffer.
*/
- if (TEST_FLAG(infoPtr->flags, FILE_APPEND)) {
+ if (infoPtr->flags & FILE_APPEND) {
SetFilePointer(infoPtr->handle, 0, NULL, FILE_END);
}
if (WriteFile(infoPtr->handle, (LPVOID) buf, (DWORD) toWrite,
&bytesWritten, (LPOVERLAPPED) NULL) == FALSE) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
*errorCode = errno;
return -1;
}
infoPtr->dirty = 1;
- return (int)bytesWritten;
+ return bytesWritten;
}
/*
@@ -819,12 +750,12 @@ FileOutputProc(
static void
FileWatchProc(
- void *instanceData, /* File state. */
+ ClientData instanceData, /* File state. */
int mask) /* What events to watch for; OR-ed combination
* of TCL_READABLE, TCL_WRITABLE and
* TCL_EXCEPTION. */
{
- FileInfo *infoPtr = (FileInfo *)instanceData;
+ FileInfo *infoPtr = (FileInfo *) instanceData;
Tcl_Time blockTime = { 0, 0 };
/*
@@ -858,207 +789,18 @@ FileWatchProc(
static int
FileGetHandleProc(
- void *instanceData, /* The file state. */
+ ClientData instanceData, /* The file state. */
int direction, /* TCL_READABLE or TCL_WRITABLE */
- void **handlePtr) /* Where to store the handle. */
-{
- FileInfo *infoPtr = (FileInfo *)instanceData;
-
- if (!TEST_FLAG(direction, infoPtr->validMask)) {
- return TCL_ERROR;
- }
-
- *handlePtr = (void *)infoPtr->handle;
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * FileGetOptionProc --
- *
- * Gets an option associated with an open file. If the optionName arg is
- * non-NULL, retrieves the value of that option. If the optionName arg is
- * NULL, retrieves a list of alternating option names and values for the
- * given channel.
- *
- * Results:
- * A standard Tcl result. Also sets the supplied DString to the string
- * value of the option(s) returned. Sets error message if needed
- * (by calling Tcl_BadChannelOption).
- *
- *----------------------------------------------------------------------
- */
-
-static inline ULONGLONG
-CombineDwords(
- DWORD hi,
- DWORD lo)
-{
- ULARGE_INTEGER converter;
-
- converter.LowPart = lo;
- converter.HighPart = hi;
- return converter.QuadPart;
-}
-
-static inline void
-StoreElementInDict(
- Tcl_Obj *dictObj,
- const char *name,
- Tcl_Obj *valueObj)
-{
- /*
- * We assume that the dict is being built fresh and that there's never any
- * duplicate keys.
- */
-
- Tcl_Obj *nameObj = Tcl_NewStringObj(name, TCL_INDEX_NONE);
- Tcl_DictObjPut(NULL, dictObj, nameObj, valueObj);
-}
-
-static inline time_t
-ToCTime(
- FILETIME fileTime) /* UTC time */
-{
- LARGE_INTEGER convertedTime;
-
- convertedTime.LowPart = fileTime.dwLowDateTime;
- convertedTime.HighPart = (LONG) fileTime.dwHighDateTime;
-
- return (time_t) ((convertedTime.QuadPart -
- (long long) POSIX_EPOCH_AS_FILETIME) / (long long) 10000000);
-}
-
-static Tcl_Obj *
-StatOpenFile(
- FileInfo *infoPtr)
-{
- DWORD attr;
- int dev, nlink = 1;
- unsigned short mode;
- unsigned long long size, inode;
- long long atime, ctime, mtime;
- BY_HANDLE_FILE_INFORMATION data;
- Tcl_Obj *dictObj;
-
- if (GetFileInformationByHandle(infoPtr->handle, &data) != TRUE) {
- Tcl_SetErrno(ENOENT);
- return NULL;
- }
-
- atime = ToCTime(data.ftLastAccessTime);
- mtime = ToCTime(data.ftLastWriteTime);
- ctime = ToCTime(data.ftCreationTime);
- attr = data.dwFileAttributes;
- size = CombineDwords(data.nFileSizeHigh, data.nFileSizeLow);
- nlink = data.nNumberOfLinks;
-
- /*
- * Unfortunately our stat definition's inode field (unsigned short) will
- * throw away most of the precision we have here, which means we can't
- * rely on inode as a unique identifier of a file. We'd really like to do
- * something like how we handle 'st_size'.
- */
-
- inode = CombineDwords(data.nFileIndexHigh, data.nFileIndexLow);
-
- dev = data.dwVolumeSerialNumber;
-
- /*
- * Note that this code has no idea whether the file can be executed.
- */
-
- mode = (attr & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR|S_IEXEC : S_IFREG;
- mode |= (attr & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD|S_IWRITE;
- mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 3;
- mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 6;
-
- /*
- * We don't construct a Tcl_StatBuf; we're using the info immediately.
- */
-
- TclNewObj(dictObj);
-#define STORE_ELEM(name, value) StoreElementInDict(dictObj, name, value)
-
- STORE_ELEM("dev", Tcl_NewWideIntObj((long) dev));
- STORE_ELEM("ino", Tcl_NewWideIntObj((long long) inode));
- STORE_ELEM("nlink", Tcl_NewIntObj(nlink));
- STORE_ELEM("uid", Tcl_NewIntObj(0));
- STORE_ELEM("gid", Tcl_NewIntObj(0));
- STORE_ELEM("size", Tcl_NewWideIntObj((long long) size));
- STORE_ELEM("atime", Tcl_NewWideIntObj(atime));
- STORE_ELEM("mtime", Tcl_NewWideIntObj(mtime));
- STORE_ELEM("ctime", Tcl_NewWideIntObj(ctime));
- STORE_ELEM("mode", Tcl_NewWideIntObj(mode));
-
- /*
- * Windows only has files and directories, as far as we're concerned.
- * Anything else and we definitely couldn't have got here anyway.
- */
- if (attr & FILE_ATTRIBUTE_DIRECTORY) {
- STORE_ELEM("type", Tcl_NewStringObj("directory", TCL_INDEX_NONE));
- } else {
- STORE_ELEM("type", Tcl_NewStringObj("file", TCL_INDEX_NONE));
- }
-#undef STORE_ELEM
-
- return dictObj;
-}
-
-static int
-FileGetOptionProc(
- void *instanceData, /* The file state. */
- Tcl_Interp *interp, /* For error reporting. */
- const char *optionName, /* What option to read, or NULL for all. */
- Tcl_DString *dsPtr) /* Where to write the value read. */
+ ClientData *handlePtr) /* Where to store the handle. */
{
- FileInfo *infoPtr = (FileInfo *)instanceData;
- int valid = 0; /* Flag if valid option parsed. */
- int len;
-
- if (optionName == NULL) {
- len = 0;
- valid = 1;
- } else {
- len = strlen(optionName);
- }
+ FileInfo *infoPtr = (FileInfo *) instanceData;
- /*
- * Get option -stat
- * Option is readonly and returned by [fconfigure chan -stat] but not
- * returned by [fconfigure chan] without explicit option name.
- */
-
- if ((len > 1) && (strncmp(optionName, "-stat", len) == 0)) {
- Tcl_Obj *dictObj = StatOpenFile(infoPtr);
- const char *dictContents;
- Tcl_Size dictLength;
-
- if (dictObj == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't read file channel status: %s",
- Tcl_PosixError(interp)));
- return TCL_ERROR;
- }
-
- /*
- * Transfer dictionary to the DString. Note that we don't do this as
- * an element as this is an option that can't be retrieved with a
- * general probe.
- */
-
- dictContents = TclGetStringFromObj(dictObj, &dictLength);
- Tcl_DStringAppend(dsPtr, dictContents, dictLength);
- Tcl_DecrRefCount(dictObj);
- return TCL_OK;
- }
-
- if (valid) {
+ if (direction & infoPtr->validMask) {
+ *handlePtr = (ClientData) infoPtr->handle;
return TCL_OK;
+ } else {
+ return TCL_ERROR;
}
- return Tcl_BadChannelOption(interp, optionName,
- "stat");
}
/*
@@ -1091,17 +833,17 @@ TclpOpenFileChannel(
Tcl_Channel channel = 0;
int channelPermissions = 0;
DWORD accessMode = 0, createMode, shareMode, flags;
- const WCHAR *nativeName;
+ CONST TCHAR *nativeName;
HANDLE handle;
char channelName[16 + TCL_INTEGER_SPACE];
TclFile readFile = NULL, writeFile = NULL;
- nativeName = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ nativeName = (TCHAR*) Tcl_FSGetNativePath(pathPtr);
if (nativeName == NULL) {
- if (interp) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't open \"%s\": filename is invalid on this platform",
- TclGetString(pathPtr)));
+ if (interp != (Tcl_Interp *) NULL) {
+ Tcl_AppendResult(interp, "couldn't open \"",
+ TclGetString(pathPtr), "\": filename is invalid on this platform",
+ NULL);
}
return NULL;
}
@@ -1149,46 +891,45 @@ TclpOpenFileChannel(
}
/*
- * [2413550] Avoid double-open of serial ports on Windows. Special
- * handling for Windows serial ports by a "name-hint" to directly open it
- * with the OVERLAPPED flag set.
+ * [2413550] Avoid double-open of serial ports on Windows
+ * Special handling for Windows serial ports by a "name-hint"
+ * to directly open it with the OVERLAPPED flag set.
*/
- if (NativeIsComPort(nativeName)) {
+ if( NativeIsComPort(nativeName) ) {
+
handle = TclWinSerialOpen(INVALID_HANDLE_VALUE, nativeName, accessMode);
if (handle == INVALID_HANDLE_VALUE) {
- Tcl_WinConvertError(GetLastError());
- if (interp) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't open serial \"%s\": %s",
- TclGetString(pathPtr), Tcl_PosixError(interp)));
+ TclWinConvertError(GetLastError());
+ if (interp != (Tcl_Interp *) NULL) {
+ Tcl_AppendResult(interp, "couldn't open serial \"",
+ TclGetString(pathPtr), "\": ",
+ Tcl_PosixError(interp), NULL);
}
return NULL;
}
/*
- * For natively-named Windows serial ports we are done.
- */
-
+ * For natively named Windows serial ports we are done.
+ */
channel = TclWinOpenSerialChannel(handle, channelName,
channelPermissions);
return channel;
}
-
/*
* If the file is being created, get the file attributes from the
* permissions argument, else use the existing file attributes.
*/
- if (TEST_FLAG(mode, O_CREAT)) {
- if (TEST_FLAG(permissions, S_IWRITE)) {
+ if (mode & O_CREAT) {
+ if (permissions & S_IWRITE) {
flags = FILE_ATTRIBUTE_NORMAL;
} else {
flags = FILE_ATTRIBUTE_READONLY;
}
} else {
- flags = GetFileAttributesW(nativeName);
+ flags = (*tclWinProcs->getFileAttributesProc)(nativeName);
if (flags == 0xFFFFFFFF) {
flags = 0;
}
@@ -1204,21 +945,19 @@ TclpOpenFileChannel(
* Now we get to create the file.
*/
- handle = CreateFileW(nativeName, accessMode, shareMode,
- NULL, createMode, flags, (HANDLE) NULL);
+ handle = (*tclWinProcs->createFileProc)(nativeName, accessMode,
+ shareMode, NULL, createMode, flags, (HANDLE) NULL);
if (handle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
- if ((err & 0xFFFFL) == ERROR_OPEN_FAILED) {
- err = TEST_FLAG(mode, O_CREAT) ? ERROR_FILE_EXISTS
- : ERROR_FILE_NOT_FOUND;
+ if ((err & 0xffffL) == ERROR_OPEN_FAILED) {
+ err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND;
}
- Tcl_WinConvertError(err);
- if (interp) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't open \"%s\": %s",
- TclGetString(pathPtr), Tcl_PosixError(interp)));
+ TclWinConvertError(err);
+ if (interp != (Tcl_Interp *) NULL) {
+ Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr),
+ "\": ", Tcl_PosixError(interp), NULL);
}
return NULL;
}
@@ -1228,9 +967,9 @@ TclpOpenFileChannel(
switch (FileGetType(handle)) {
case FILE_TYPE_SERIAL:
/*
- * Natively named serial ports "com1-9", "\\\\.\\comXX" are already
- * done with the code above. Here we handle all other serial port
- * names.
+ * Natively named serial ports "com1-9", "\\\\.\\comXX" are
+ * already done with the code above.
+ * Here we handle all other serial port names.
*
* Reopen channel for OVERLAPPED operation. Normally this shouldn't
* fail, because the channel exists.
@@ -1238,11 +977,11 @@ TclpOpenFileChannel(
handle = TclWinSerialOpen(handle, nativeName, accessMode);
if (handle == INVALID_HANDLE_VALUE) {
- Tcl_WinConvertError(GetLastError());
- if (interp) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't reopen serial \"%s\": %s",
- TclGetString(pathPtr), Tcl_PosixError(interp)));
+ TclWinConvertError(GetLastError());
+ if (interp != (Tcl_Interp *) NULL) {
+ Tcl_AppendResult(interp, "couldn't reopen serial \"",
+ TclGetString(pathPtr), "\": ",
+ Tcl_PosixError(interp), NULL);
}
return NULL;
}
@@ -1254,10 +993,10 @@ TclpOpenFileChannel(
channelPermissions);
break;
case FILE_TYPE_PIPE:
- if (TEST_FLAG(channelPermissions, TCL_READABLE)) {
+ if (channelPermissions & TCL_READABLE) {
readFile = TclWinMakeFile(handle);
}
- if (TEST_FLAG(channelPermissions, TCL_WRITABLE)) {
+ if (channelPermissions & TCL_WRITABLE) {
writeFile = TclWinMakeFile(handle);
}
channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL);
@@ -1265,9 +1004,8 @@ TclpOpenFileChannel(
case FILE_TYPE_CHAR:
case FILE_TYPE_DISK:
case FILE_TYPE_UNKNOWN:
- channel = OpenFileChannel(handle, channelName,
- channelPermissions,
- TEST_FLAG(mode, O_APPEND) ? FILE_APPEND : 0);
+ channel = TclWinOpenFileChannel(handle, channelName,
+ channelPermissions, (mode & O_APPEND) ? FILE_APPEND : 0);
break;
default:
@@ -1277,11 +1015,8 @@ TclpOpenFileChannel(
*/
channel = NULL;
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't open \"%s\": bad file type",
- TclGetString(pathPtr)));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "BAD_TYPE",
- (char *)NULL);
+ Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr),
+ "\": bad file type", NULL);
break;
}
@@ -1306,11 +1041,11 @@ TclpOpenFileChannel(
Tcl_Channel
Tcl_MakeFileChannel(
- void *rawHandle, /* OS level handle */
- int mode) /* OR'ed combination of TCL_READABLE and
+ ClientData rawHandle, /* OS level handle */
+ int mode) /* ORed combination of TCL_READABLE and
* TCL_WRITABLE to indicate file mode. */
{
-#if defined(HAVE_NO_SEH) && !defined(_WIN64) && !defined(__clang__)
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
TCLEXCEPTION_REGISTRATION registration;
#endif
char channelName[16 + TCL_INTEGER_SPACE];
@@ -1320,7 +1055,7 @@ Tcl_MakeFileChannel(
TclFile readFile = NULL, writeFile = NULL;
BOOL result;
- if ((mode & (TCL_READABLE|TCL_WRITABLE)) == 0) {
+ if (mode == 0) {
return NULL;
}
@@ -1332,10 +1067,10 @@ Tcl_MakeFileChannel(
channel = TclWinOpenConsoleChannel(handle, channelName, mode);
break;
case FILE_TYPE_PIPE:
- if (TEST_FLAG(mode, TCL_READABLE)) {
+ if (mode & TCL_READABLE) {
readFile = TclWinMakeFile(handle);
}
- if (TEST_FLAG(mode, TCL_WRITABLE)) {
+ if (mode & TCL_WRITABLE) {
writeFile = TclWinMakeFile(handle);
}
channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL);
@@ -1343,7 +1078,7 @@ Tcl_MakeFileChannel(
case FILE_TYPE_DISK:
case FILE_TYPE_CHAR:
- channel = OpenFileChannel(handle, channelName, mode, 0);
+ channel = TclWinOpenFileChannel(handle, channelName, mode, 0);
break;
case FILE_TYPE_UNKNOWN:
@@ -1363,7 +1098,7 @@ Tcl_MakeFileChannel(
if (result == 0) {
/*
- * Unable to make a duplicate. It's definitely invalid at this
+ * Unable to make a duplicate. It's definately invalid at this
* point.
*/
@@ -1376,7 +1111,7 @@ Tcl_MakeFileChannel(
*/
result = 0;
-#if defined(HAVE_NO_SEH) && !defined(_WIN64) && !defined(__clang__)
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
/*
* Don't have SEH available, do things the hard way. Note that this
* needs to be one block of asm, to avoid stack imbalance; also, it is
@@ -1402,7 +1137,7 @@ Tcl_MakeFileChannel(
"leal 1f, %%eax" "\n\t"
"movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
"movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
- "movl %%esp, 0xC(%%edx)" "\n\t" /* esp */
+ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
"movl $0, 0x10(%%edx)" "\n\t" /* status */
/*
@@ -1442,7 +1177,7 @@ Tcl_MakeFileChannel(
*/
"2:" "\t"
- "movl 0xC(%%edx), %%esp" "\n\t"
+ "movl 0xc(%%edx), %%esp" "\n\t"
"movl 0x8(%%edx), %%ebp" "\n\t"
"movl 0x0(%%edx), %%eax" "\n\t"
"movl %%eax, %%fs:0" "\n\t"
@@ -1477,7 +1212,7 @@ Tcl_MakeFileChannel(
* is valid to something.
*/
- channel = OpenFileChannel(handle, channelName, mode, 0);
+ channel = TclWinOpenFileChannel(handle, channelName, mode, 0);
}
return channel;
@@ -1507,8 +1242,8 @@ TclpGetDefaultStdChannel(
Tcl_Channel channel;
HANDLE handle;
int mode = -1;
- const char *bufMode = NULL;
- DWORD handleId = (DWORD) -1;
+ char *bufMode = NULL;
+ DWORD handleId = (DWORD)-1;
/* Standard handle to retrieve. */
switch (type) {
@@ -1555,7 +1290,7 @@ TclpGetDefaultStdChannel(
*/
if (Tcl_SetChannelOption(NULL,channel,"-translation","auto")!=TCL_OK ||
- Tcl_SetChannelOption(NULL,channel,"-eofchar","\x1A {}")!=TCL_OK ||
+ Tcl_SetChannelOption(NULL,channel,"-eofchar","\032 {}")!=TCL_OK ||
Tcl_SetChannelOption(NULL,channel,"-buffering",bufMode)!=TCL_OK) {
Tcl_Close(NULL, channel);
return (Tcl_Channel) NULL;
@@ -1566,7 +1301,7 @@ TclpGetDefaultStdChannel(
/*
*----------------------------------------------------------------------
*
- * OpenFileChannel --
+ * TclWinOpenFileChannel --
*
* Constructs a File channel for the specified standard OS handle. This
* is a helper function to break up the construction of channels into
@@ -1583,7 +1318,7 @@ TclpGetDefaultStdChannel(
*/
Tcl_Channel
-OpenFileChannel(
+TclWinOpenFileChannel(
HANDLE handle, /* Win32 HANDLE to swallow */
char *channelName, /* Buffer to receive channel name */
int permissions, /* OR'ed combination of TCL_READABLE,
@@ -1603,12 +1338,11 @@ OpenFileChannel(
for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
infoPtr = infoPtr->nextPtr) {
if (infoPtr->handle == (HANDLE) handle) {
- return ((permissions & (TCL_READABLE|TCL_WRITABLE|TCL_EXCEPTION))==infoPtr->validMask)
- ? infoPtr->channel : NULL;
+ return (permissions==infoPtr->validMask) ? infoPtr->channel : NULL;
}
}
- infoPtr = (FileInfo *)ckalloc(sizeof(FileInfo));
+ infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo));
/*
* TIP #218. Removed the code inserting the new structure into the global
@@ -1617,14 +1351,15 @@ OpenFileChannel(
*/
infoPtr->nextPtr = NULL;
- infoPtr->validMask = permissions & (TCL_READABLE|TCL_WRITABLE|TCL_EXCEPTION);
+ infoPtr->validMask = permissions;
infoPtr->watchMask = 0;
infoPtr->flags = appendMode;
infoPtr->handle = handle;
infoPtr->dirty = 0;
- TclWinGenerateChannelName(channelName, "file", infoPtr);
+ sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t)infoPtr);
+
infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName,
- infoPtr, permissions);
+ (ClientData) infoPtr, permissions);
/*
* Files have default translation of AUTO and ^Z eof char, which means
@@ -1632,7 +1367,7 @@ OpenFileChannel(
*/
Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto");
- Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\x1A {}");
+ Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}");
return infoPtr->channel;
}
@@ -1694,11 +1429,11 @@ TclWinFlushDirtyChannels(void)
static void
FileThreadActionProc(
- void *instanceData,
+ ClientData instanceData,
int action)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- FileInfo *infoPtr = (FileInfo *)instanceData;
+ FileInfo *infoPtr = (FileInfo *) instanceData;
if (action == TCL_CHANNEL_THREAD_INSERT) {
infoPtr->nextPtr = tsdPtr->firstFilePtr;
@@ -1782,13 +1517,13 @@ FileGetType(
*
* NativeIsComPort --
*
- * Determines if a path refers to a Windows serial port. A simple and
- * efficient solution is to use a "name hint" to detect COM ports by
- * their filename instead of resorting to a syscall to detect serialness
- * after the fact.
- *
+ * Determines if a path refers to a Windows serial port.
+ * A simple and efficient solution is to use a "name hint" to detect
+ * COM ports by their filename instead of resorting to a syscall
+ * to detect serialness after the fact.
* The following patterns cover common serial port names:
- * COM[1-9]
+ * COM[1-9]:?
+ * //./COM[0-9]+
* \\.\COM[0-9]+
*
* Results:
@@ -1799,41 +1534,96 @@ FileGetType(
static int
NativeIsComPort(
- const WCHAR *nativePath) /* Path of file to access, native encoding. */
+ const TCHAR *nativePath) /* Path of file to access, native encoding. */
{
- const WCHAR *p = (const WCHAR *) nativePath;
- size_t i, len = wcslen(p);
-
/*
- * 1. Look for com[1-9]:?
+ * Use wide-char or plain character case-insensitive comparison
*/
+ if (tclWinProcs->useWide) {
+ const WCHAR *p = (const WCHAR *) nativePath;
+ int i, len = wcslen(p);
- if ((len == 4) && (_wcsnicmp(p, L"com", 3) == 0)) {
/*
- * The 4th character must be a digit 1..9
+ * 1. Look for com[1-9]:?
*/
- if ((p[3] < '1') || (p[3] > '9')) {
- return 0;
+ if ( (len >= 4) && (len <= 5)
+ && (_wcsnicmp(p, L"com", 3) == 0) ) {
+ /*
+ * The 4th character must be a digit 1..9 optionally followed by a ":"
+ */
+
+ if ( (p[3] < L'1') || (p[3] > L'9') ) {
+ return 0;
+ }
+ if ( (len == 5) && (p[4] != L':') ) {
+ return 0;
+ }
+ return 1;
}
- return 1;
- }
- /*
- * 2. Look for \\.\com[0-9]+
- */
+ /*
+ * 2. Look for //./com[0-9]+ or \\.\com[0-9]+
+ */
+
+ if ( (len >= 8) && (
+ (_wcsnicmp(p, L"//./com", 7) == 0)
+ || (_wcsnicmp(p, L"\\\\.\\com", 7) == 0) ) )
+ {
+ /*
+ * Charaters 8..end must be a digits 0..9
+ */
+
+ for ( i=7; i<len; i++ ) {
+ if ( (p[i] < '0') || (p[i] > '9') ) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ } else {
+ const char *p = (const char *) nativePath;
+ int i, len = strlen(p);
- if ((len >= 8) && (_wcsnicmp(p, L"\\\\.\\com", 7) == 0)) {
/*
- * Charaters 8..end must be a digits 0..9
+ * 1. Look for com[1-9]:?
*/
- for (i=7; i<len; i++) {
- if ((p[i] < '0') || (p[i] > '9')) {
+ if ( (len >= 4) && (len <= 5)
+ && (strnicmp(p, "com", 3) == 0) ) {
+ /*
+ * The 4th character must be a digit 1..9 optionally followed by a ":"
+ */
+
+ if ( (p[3] < '1') || (p[3] > '9') ) {
+ return 0;
+ }
+ if ( (len == 5) && (p[4] != ':') ) {
return 0;
}
+ return 1;
+ }
+
+ /*
+ * 2. Look for //./com[0-9]+ or \\.\com[0-9]+
+ */
+
+ if ( (len >= 8) && (
+ (strnicmp(p, "//./com", 7) == 0)
+ || (strnicmp(p, "\\\\.\\com", 7) == 0) ) )
+ {
+ /*
+ * Charaters 8..end must be a digits 0..9
+ */
+
+ for ( i=7; i<len; i++ ) {
+ if ( (p[i] < '0') || (p[i] > '9') ) {
+ return 0;
+ }
+ }
+ return 1;
}
- return 1;
}
return 0;
}
diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c
index c7e12ae..361fb3d 100644
--- a/win/tclWinConsole.c
+++ b/win/tclWinConsole.c
@@ -2,208 +2,128 @@
* tclWinConsole.c --
*
* This file implements the Windows-specific console functions, and the
- * "console" channel driver. Windows 7 or later required.
+ * "console" channel driver.
*
- * Copyright © 2022 Ashok P. Nadkarni
+ * Copyright (c) 1999 by Scriptics Corp.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#ifdef TCL_CONSOLE_DEBUG
-#undef NDEBUG /* Enable asserts */
-#endif
-
#include "tclWinInt.h"
-#include <assert.h>
-#include <ctype.h>
+
+#include <fcntl.h>
+#include <io.h>
/*
- * A general note on the design: The console channel driver differs from
- * most other drivers in the following respects:
- *
- * - There can be at most 3 console handles at any time since Windows does
- * support allocation of more than one console (with three handles
- * corresponding to stdin, stdout, stderr)
- *
- * - Consoles are created / inherited at process startup. There is currently
- * no way in Tcl to programmatically create a console. Even if these were
- * added the above Windows limitation would still apply.
- *
- * - Unlike files, sockets etc. where there is a one-to-one
- * correspondence between Tcl channels and operating system handles,
- * std* channels are shared amongst threads which means there can be
- * multiple Tcl channels corresponding to a single console handle.
- *
- * - Even with multiple threads, more than one file event handler is
- * unlikely. It does not make sense for multiple threads to register
- * handlers for stdin because the input would be randomly fragmented amongst
- * the threads.
- *
- * Various design factors are driven by the above, e.g. use of lists instead
- * of hash tables (at most 3 console handles) and use of global instead of
- * per thread queues which simplifies lock management particularly because
- * thread-console relation is not one-one and is likely more performant as
- * well with fewer locks needing to be obtained.
- *
- * Some additional design notes/reminders for the future:
- *
- * Aligned, synchronous reads are done directly by interpreter thread.
- * Unaligned or asynchronous reads are done through the reader thread.
- *
- * The reader thread does not read ahead. That is, it will not post a read
- * until some interpreter thread is actually requesting a read. This is
- * because an interpreter may (for example) turn off echo for passwords and
- * the read ahead would come in the way of that.
- *
- * If multiple threads are reading from stdin, the input is sprayed in
- * random fashion. This is not good application design and hence no plan to
- * address this (not clear what should be done even in theory)
- *
- * For output, we do not restrict all output to the console writer threads.
- * See ConsoleOutputProc for the conditions.
- *
- * Locks are never held when calling the ReadConsole/WriteConsole API's
- * since they may block.
+ * The following variable is used to tell whether this module has been
+ * initialized.
*/
-static int gInitialized = 0;
+static int initialized = 0;
/*
- * INPUT_BUFFER_SIZE is size of buffer passed to ReadConsole in bytes.
- * Note that ReadConsole will only allow reading of line lengths up to the
- * max of 256 and buffer size passed to it. So dropping this below 512
- * means user can type at most 256 chars.
+ * The consoleMutex locks around access to the initialized variable, and it is
+ * used to protect background threads from being terminated while they are
+ * using APIs that hold locks.
*/
-#ifndef INPUT_BUFFER_SIZE
-#define INPUT_BUFFER_SIZE 8192 /* In bytes, so 4096 chars */
-#endif
-/*
- * CONSOLE_BUFFER_SIZE is size of storage used in ring buffers.
- * In theory, at least sizeof(WCHAR) but note the Tcl channel bug
- * https://core.tcl-lang.org/tcl/tktview/b3977d199b08e3979a8da970553d5209b3042e9c
- * will cause failures in test suite if close to max input line in the suite.
- */
-#ifndef CONSOLE_BUFFER_SIZE
-#define CONSOLE_BUFFER_SIZE 8192 /* In bytes */
-#endif
+TCL_DECLARE_MUTEX(consoleMutex)
/*
- * Ring buffer for storing data. Actual data is from bufPtr[start]:bufPtr[size-1]
- * and bufPtr[0]:bufPtr[length - (size-start)].
+ * Bit masks used in the flags field of the ConsoleInfo structure below.
*/
-typedef struct RingBuffer {
- char *bufPtr; /* Pointer to buffer storage */
- Tcl_Size capacity; /* Size of the buffer in RingBufferChar */
- Tcl_Size start; /* Start of the data within the buffer. */
- Tcl_Size length; /* Number of RingBufferChar*/
-} RingBuffer;
-#define RingBufferLength(ringPtr_) ((ringPtr_)->length)
-#define RingBufferHasFreeSpace(ringPtr_) ((ringPtr_)->length < (ringPtr_)->capacity)
-#define RINGBUFFER_ASSERT(ringPtr_) assert(RingBufferCheck(ringPtr_))
+
+#define CONSOLE_PENDING (1<<0) /* Message is pending in the queue. */
+#define CONSOLE_ASYNC (1<<1) /* Channel is non-blocking. */
/*
- * The Win32 console API does not support non-blocking I/O in any form. Thus
- * the actual calls are made on a separate thread. Moreover, separate
- * threads are needed for each handle because (for example) blocking on user
- * input on stdin should not prevent output to stdout when non-blocking i/o
- * is configured at the script level.
- *
- * In the input (e.g. stdin) case, the console stdin thread is the producer
- * writing to the buffer ring buffer. The Tcl interpreter threads are the
- * consumer. For the output (e.g. stdout/stderr) case, the Tcl interpreter
- * are the producers while the console stdout/stderr threads are the
- * consumers.
- *
- * Consoles are identified purely by handles and multiple threads may open
- * them (as stdin/stdout/stderr are shared).
- *
- * Note on reference counting - a ConsoleHandleInfo instance has multiple
- * references to it - one each from every channel that is attached to it
- * plus one from the console thread itself which also serves as the reference
- * from gConsoleHandleInfoList.
+ * Bit masks used in the sharedFlags field of the ConsoleInfo structure below.
*/
-typedef struct ConsoleHandleInfo {
- struct ConsoleHandleInfo *nextPtr; /* Process-global list of consoles */
- HANDLE console; /* Console handle */
- HANDLE consoleThread; /* Handle to thread doing actual i/o on the console */
- SRWLOCK lock; /* Controls access to this structure.
- * Cheaper than CRITICAL_SECTION but note does not
- * support recursive locks or Try* style attempts.*/
- CONDITION_VARIABLE consoleThreadCV;/* For awakening console thread */
- CONDITION_VARIABLE interpThreadCV; /* For awakening interpthread(s) */
- RingBuffer buffer; /* Buffer for data transferred between console
- * threads and Tcl threads. For input consoles,
- * written by the console thread and read by Tcl
- * threads. The converse for output threads */
- DWORD initMode; /* Initial console mode. */
- DWORD lastError; /* An error caused by the last background
- * operation. Set to 0 if no error has been
- * detected. */
- int numRefs; /* See comments above */
- int permissions; /* TCL_READABLE for input consoles, TCL_WRITABLE
- * for output. Only one or the other can be set. */
- int flags;
-#define CONSOLE_DATA_AWAITED 0x0001 /* An interpreter is awaiting data */
-} ConsoleHandleInfo;
+
+#define CONSOLE_EOF (1<<2) /* Console has reached EOF. */
+#define CONSOLE_BUFFERED (1<<3) /* Data was read into a buffer by the reader
+ * thread. */
+
+#define CONSOLE_BUFFER_SIZE (8*1024)
/*
* This structure describes per-instance data for a console based channel.
- *
- * Note on locking - this structure has no locks because it is accessed
- * only from the thread owning channel EXCEPT when a console traverses it
- * looking for a channel that is watching for events on the console. Even
- * in that case, no locking is required because that access is only under
- * the gConsoleLock lock which prevents the channel from being removed from
- * the gWatchingChannelList which in turn means it will not be deallocated
- * from under the console thread. Access to individual fields does not need
- * to be controlled because
- * - the console thread does not write to any fields
- * - changes to the nextWatchingChannelPtr field
- * - changes to other fields do not matter because after being read for
- * queueing events, they are verified again when the event is received
- * in the interpreter thread (since they could have changed anyways while
- * the event was in-flight on the event queue)
- *
- * Note on reference counting - a structure instance may be referenced from
- * three places:
- * - the Tcl channel subsystem. This reference is created when on channel
- * opening and dropped on channel close. This also covers the reference
- * from gWatchingChannelList since queueing / dequeuing from that list
- * happens in conjunction with channel operations.
- * - the Tcl event queue entries. This reference is added when the event
- * is queued and dropped on receipt.
*/
-typedef struct ConsoleChannelInfo {
- HANDLE handle; /* Console handle */
- Tcl_ThreadId threadId; /* Id of owning thread */
- struct ConsoleChannelInfo *nextWatchingChannelPtr;
- /* Pointer to next channel watching events. */
+
+typedef struct ConsoleInfo {
+ HANDLE handle;
+ int type;
+ struct ConsoleInfo *nextPtr;/* Pointer to next registered console. */
Tcl_Channel channel; /* Pointer to channel structure. */
- DWORD initMode; /* Initial console mode. */
- int numRefs; /* See comments above */
- int permissions; /* OR'ed combination of TCL_READABLE,
+ int validMask; /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, or TCL_EXCEPTION: indicates
* which operations are valid on the file. */
int watchMask; /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, or TCL_EXCEPTION: indicates
* which events should be reported. */
- int flags; /* State flags */
-#define CONSOLE_EVENT_QUEUED 0x0001 /* Notification event already queued */
-#define CONSOLE_ASYNC 0x0002 /* Channel is non-blocking. */
-#define CONSOLE_READ_OPS 0x0004 /* Channel supports read-related ops. */
-} ConsoleChannelInfo;
+ int flags; /* State flags, see above for a list. */
+ Tcl_ThreadId threadId; /* Thread to which events should be reported.
+ * This value is used by the reader/writer
+ * threads. */
+ HANDLE writeThread; /* Handle to writer thread. */
+ HANDLE readThread; /* Handle to reader thread. */
+ HANDLE writable; /* Manual-reset event to signal when the
+ * writer thread has finished waiting for the
+ * current buffer to be written. */
+ HANDLE readable; /* Manual-reset event to signal when the
+ * reader thread has finished waiting for
+ * input. */
+ HANDLE startWriter; /* Auto-reset event used by the main thread to
+ * signal when the writer thread should
+ * attempt to write to the console. */
+ HANDLE stopWriter; /* Auto-reset event used by the main thread to
+ * signal when the writer thread should exit */
+ HANDLE startReader; /* Auto-reset event used by the main thread to
+ * signal when the reader thread should
+ * attempt to read from the console. */
+ HANDLE stopReader; /* Auto-reset event used by the main thread to
+ * signal when the reader thread should exit */
+ DWORD writeError; /* An error caused by the last background
+ * write. Set to 0 if no error has been
+ * detected. This word is shared with the
+ * writer thread so access must be
+ * synchronized with the writable object. */
+ char *writeBuf; /* Current background output buffer. Access is
+ * synchronized with the writable object. */
+ int writeBufLen; /* Size of write buffer. Access is
+ * synchronized with the writable object. */
+ int toWrite; /* Current amount to be written. Access is
+ * synchronized with the writable object. */
+ int readFlags; /* Flags that are shared with the reader
+ * thread. Access is synchronized with the
+ * readable object. */
+ int bytesRead; /* number of bytes in the buffer */
+ int offset; /* number of bytes read out of the buffer */
+ char buffer[CONSOLE_BUFFER_SIZE];
+ /* Data consumed by reader thread. */
+} ConsoleInfo;
+
+typedef struct ThreadSpecificData {
+ /*
+ * The following pointer refers to the head of the list of consoles that
+ * are being watched for file events.
+ */
+
+ ConsoleInfo *firstConsolePtr;
+} ThreadSpecificData;
+
+static Tcl_ThreadDataKey dataKey;
/*
* The following structure is what is added to the Tcl event queue when
* console events are generated.
*/
-typedef struct {
- Tcl_Event header; /* Information that is standard for all events. */
- ConsoleChannelInfo *chanInfoPtr;
- /* Pointer to console info structure. Note
+typedef struct ConsoleEvent {
+ Tcl_Event header; /* Information that is standard for all
+ * events. */
+ ConsoleInfo *infoPtr; /* Pointer to console info structure. Note
* that we still have to verify that the
* console exists before dereferencing this
* pointer. */
@@ -213,408 +133,94 @@ typedef struct {
* Declarations for functions used only in this file.
*/
-static int ConsoleBlockModeProc(void *instanceData, int mode);
-static void ConsoleCheckProc(void *clientData, int flags);
-static int ConsoleCloseProc(void *instanceData,
- Tcl_Interp *interp, int flags);
+static int ConsoleBlockModeProc(ClientData instanceData,int mode);
+static void ConsoleCheckProc(ClientData clientData, int flags);
+static int ConsoleCloseProc(ClientData instanceData,
+ Tcl_Interp *interp);
static int ConsoleEventProc(Tcl_Event *evPtr, int flags);
-static void ConsoleExitHandler(void *clientData);
-static int ConsoleGetHandleProc(void *instanceData,
- int direction, void **handlePtr);
-static int ConsoleGetOptionProc(void *instanceData,
- Tcl_Interp *interp, const char *optionName,
- Tcl_DString *dsPtr);
+static void ConsoleExitHandler(ClientData clientData);
+static int ConsoleGetHandleProc(ClientData instanceData,
+ int direction, ClientData *handlePtr);
static void ConsoleInit(void);
-static int ConsoleInputProc(void *instanceData, char *buf,
+static int ConsoleInputProc(ClientData instanceData, char *buf,
int toRead, int *errorCode);
-static int ConsoleOutputProc(void *instanceData,
- const char *buf, int toWrite, int *errorCode);
-static int ConsoleSetOptionProc(void *instanceData,
- Tcl_Interp *interp, const char *optionName,
- const char *value);
-static void ConsoleSetupProc(void *clientData, int flags);
-static void ConsoleWatchProc(void *instanceData, int mask);
-static void ProcExitHandler(void *clientData);
-static void ConsoleThreadActionProc(void *instanceData, int action);
-static DWORD ReadConsoleChars(HANDLE hConsole, WCHAR *lpBuffer,
- Tcl_Size nChars, Tcl_Size *nCharsReadPtr);
-static DWORD WriteConsoleChars(HANDLE hConsole,
- const WCHAR *lpBuffer, Tcl_Size nChars,
- Tcl_Size *nCharsWritten);
-static void RingBufferInit(RingBuffer *ringPtr, Tcl_Size capacity);
-static void RingBufferClear(RingBuffer *ringPtr);
-static Tcl_Size RingBufferIn(RingBuffer *ringPtr, const char *srcPtr,
- Tcl_Size srcLen, int partialCopyOk);
-static Tcl_Size RingBufferOut(RingBuffer *ringPtr, char *dstPtr,
- Tcl_Size dstCapacity, int partialCopyOk);
-static ConsoleHandleInfo *AllocateConsoleHandleInfo(HANDLE consoleHandle,
- int permissions);
-static ConsoleHandleInfo *FindConsoleInfo(const ConsoleChannelInfo *);
+static int ConsoleOutputProc(ClientData instanceData,
+ CONST char *buf, int toWrite, int *errorCode);
static DWORD WINAPI ConsoleReaderThread(LPVOID arg);
+static void ConsoleSetupProc(ClientData clientData, int flags);
+static void ConsoleWatchProc(ClientData instanceData, int mask);
static DWORD WINAPI ConsoleWriterThread(LPVOID arg);
-static void NudgeWatchers(HANDLE consoleHandle);
-#ifndef NDEBUG
-static int RingBufferCheck(const RingBuffer *ringPtr);
-#endif
-
-/*
- * Static data.
- */
-
-typedef struct {
- /* Currently this struct is only used to detect thread initialization */
- int notUsed; /* Dummy field */
-} ThreadSpecificData;
-static Tcl_ThreadDataKey dataKey;
-
-/*
- * All access to static data is controlled through a single process-wide
- * lock. A process can have only a single console at a time, with three
- * handles for stdin, stdout and stderr. Creation/destruction of consoles is
- * a relatively rare event (currently only possible during process start),
- * the number of consoles (as opposed to channels) is small (only stdin,
- * stdout and stderr), and contention low. More finer-grained locking would
- * likely not only complicate implementation but be slower due to multiple
- * locks being held. Note console channels also differ from other Tcl
- * channel types in that the channel<->OS descriptor mapping is not one-to-one.
- */
-SRWLOCK gConsoleLock;
-
-
-/* Process-wide list of console handles. Access control through gConsoleLock */
-static ConsoleHandleInfo *gConsoleHandleInfoList;
-
-/*
- * Process-wide list of channels that are listening for events. Again access
- * control through gConsoleLock. Common list for all threads is simplifies
- * locking and bookkeeping and is workable because in practice multiple
- * threads are very unlikely to be all waiting on stdin (not workable
- * because input would be randomly distributed to threads)
- */
-static ConsoleChannelInfo *gWatchingChannelList;
+static void ProcExitHandler(ClientData clientData);
+static int WaitForRead(ConsoleInfo *infoPtr, int blocking);
+static void ConsoleThreadActionProc(ClientData instanceData,
+ int action);
/*
* This structure describes the channel type structure for command console
* based IO.
*/
-static const Tcl_ChannelType consoleChannelType = {
- "console", /* Type name. */
- TCL_CHANNEL_VERSION_5, /* v5 channel */
- TCL_CLOSE2PROC, /* Close proc. */
- ConsoleInputProc, /* Input proc. */
- ConsoleOutputProc, /* Output proc. */
- NULL, /* Seek proc. */
- ConsoleSetOptionProc, /* Set option proc. */
- ConsoleGetOptionProc, /* Get option proc. */
- ConsoleWatchProc, /* Set up notifier to watch the channel. */
- ConsoleGetHandleProc, /* Get an OS handle from channel. */
- ConsoleCloseProc, /* close2proc. */
- ConsoleBlockModeProc, /* Set blocking or non-blocking mode. */
- NULL, /* Flush proc. */
- NULL, /* Handler proc. */
- NULL, /* Wide seek proc. */
- ConsoleThreadActionProc, /* Thread action proc. */
- NULL /* Truncation proc. */
+static Tcl_ChannelType consoleChannelType = {
+ "console", /* Type name. */
+ TCL_CHANNEL_VERSION_5, /* v5 channel */
+ ConsoleCloseProc, /* Close proc. */
+ ConsoleInputProc, /* Input proc. */
+ ConsoleOutputProc, /* Output proc. */
+ NULL, /* Seek proc. */
+ NULL, /* Set option proc. */
+ NULL, /* Get option proc. */
+ ConsoleWatchProc, /* Set up notifier to watch the channel. */
+ ConsoleGetHandleProc, /* Get an OS handle from channel. */
+ NULL, /* close2proc. */
+ ConsoleBlockModeProc, /* Set blocking or non-blocking mode.*/
+ NULL, /* flush proc. */
+ NULL, /* handler proc. */
+ NULL, /* wide seek proc */
+ ConsoleThreadActionProc, /* thread action proc */
+ NULL, /* truncation */
};
-
-/*
- *------------------------------------------------------------------------
- *
- * RingBufferInit --
- *
- * Initializes the ring buffer to a given size.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Panics on allocation failure.
- *
- *------------------------------------------------------------------------
- */
-static void
-RingBufferInit(
- RingBuffer *ringPtr,
- Tcl_Size capacity)
-{
- if (capacity <= 0 || capacity > TCL_SIZE_MAX) {
- Tcl_Panic("Internal error: invalid ring buffer capacity requested.");
- }
- ringPtr->bufPtr = (char *) ckalloc(capacity);
- ringPtr->capacity = capacity;
- ringPtr->start = 0;
- ringPtr->length = 0;
-}
-
-/*
- *------------------------------------------------------------------------
- *
- * RingBufferClear
- *
- * Clears the contents of a ring buffer.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The allocated internal buffer is freed.
- *
- *------------------------------------------------------------------------
- */
-static void
-RingBufferClear(
- RingBuffer *ringPtr)
-{
- if (ringPtr->bufPtr) {
- ckfree(ringPtr->bufPtr);
- ringPtr->bufPtr = NULL;
- }
- ringPtr->capacity = 0;
- ringPtr->start = 0;
- ringPtr->length = 0;
-}
/*
- *------------------------------------------------------------------------
- *
- * RingBufferIn --
- *
- * Appends data to the ring buffer.
- *
- * Results:
- * Returns number of bytes copied.
- *
- * Side effects:
- * Internal buffer is updated.
- *
- *------------------------------------------------------------------------
- */
-static Tcl_Size
-RingBufferIn(
- RingBuffer *ringPtr,
- const char *srcPtr, /* Source to be copied */
- Tcl_Size srcLen, /* Length of source */
- int partialCopyOk) /* If true, partial copy is permitted */
-{
- Tcl_Size freeSpace;
-
- RINGBUFFER_ASSERT(ringPtr);
-
- freeSpace = ringPtr->capacity - ringPtr->length;
- if (freeSpace < srcLen) {
- if (!partialCopyOk) {
- return 0;
- }
- /* Copy only as much as free space allows */
- srcLen = freeSpace;
- }
-
- if (ringPtr->capacity - ringPtr->start > ringPtr->length) {
- /* There is room at the back */
- Tcl_Size endSpaceStart = ringPtr->start + ringPtr->length;
- Tcl_Size endSpace = ringPtr->capacity - endSpaceStart;
- if (endSpace >= srcLen) {
- /* Everything fits at the back */
- memmove(endSpaceStart + ringPtr->bufPtr, srcPtr, srcLen);
- } else {
- /* srcLen > endSpace */
- memmove(endSpaceStart + ringPtr->bufPtr, srcPtr, endSpace);
- memmove(ringPtr->bufPtr, endSpace + srcPtr, srcLen - endSpace);
- }
- } else {
- /* No room at the back. Existing data wrap to front. */
- Tcl_Size wrapLen =
- ringPtr->start + ringPtr->length - ringPtr->capacity;
- memmove(wrapLen + ringPtr->bufPtr, srcPtr, srcLen);
- }
-
- ringPtr->length += srcLen;
-
- RINGBUFFER_ASSERT(ringPtr);
-
- return srcLen;
-}
-
-/*
- *------------------------------------------------------------------------
- *
- * RingBufferOut --
- *
- * Moves data out of the ring buffer. If dstPtr is NULL, the data
- * is simply removed.
- *
- * Results:
- * Returns number of bytes copied or removed.
- *
- * Side effects:
- * Internal buffer is updated.
- *
- *------------------------------------------------------------------------
- */
-static Tcl_Size
-RingBufferOut(
- RingBuffer *ringPtr,
- char *dstPtr, /* Buffer for output data. May be NULL */
- Tcl_Size dstCapacity, /* Size of buffer */
- int partialCopyOk) /* If true, return what's available */
-{
- Tcl_Size leadLen;
-
- RINGBUFFER_ASSERT(ringPtr);
-
- if (dstCapacity > ringPtr->length) {
- if (dstPtr && !partialCopyOk) {
- return 0;
- }
- dstCapacity = ringPtr->length;
- }
-
- if (ringPtr->start <= (ringPtr->capacity - ringPtr->length)) {
- /* No content wrap around. So leadLen is entire content */
- leadLen = ringPtr->length;
- } else {
- /* Content wraps around so lead segment stretches to end of buffer */
- leadLen = ringPtr->capacity - ringPtr->start;
- }
- if (leadLen >= dstCapacity) {
- if (dstPtr) {
- memmove(dstPtr, ringPtr->start + ringPtr->bufPtr, dstCapacity);
- }
- ringPtr->start += dstCapacity;
- } else {
- Tcl_Size wrapLen = dstCapacity - leadLen;
- if (dstPtr) {
- memmove(dstPtr,
- ringPtr->start + ringPtr->bufPtr,
- leadLen);
- memmove(
- leadLen + dstPtr, ringPtr->bufPtr, wrapLen);
- }
- ringPtr->start = wrapLen;
- }
-
- ringPtr->length -= dstCapacity;
- if (ringPtr->start == ringPtr->capacity || ringPtr->length == 0) {
- ringPtr->start = 0;
- }
-
- RINGBUFFER_ASSERT(ringPtr);
-
- return dstCapacity;
-}
-
-#ifndef NDEBUG
-static int
-RingBufferCheck(
- const RingBuffer *ringPtr)
-{
- return (ringPtr->bufPtr != NULL && ringPtr->capacity == CONSOLE_BUFFER_SIZE
- && ringPtr->start < ringPtr->capacity
- && ringPtr->length <= ringPtr->capacity);
-}
-#endif
-
-/*
- *------------------------------------------------------------------------
- *
- * ReadConsoleChars --
- *
- * Wrapper for ReadConsoleW.
- *
- * Results:
- * Returns 0 on success, else Windows error code.
- *
- * Side effects:
- * On success the number of characters (not bytes) read is stored in
- * *nCharsReadPtr. This will be 0 if the operation was interrupted by
- * a Ctrl-C or a CancelIo call.
+ *----------------------------------------------------------------------
*
- *------------------------------------------------------------------------
+ * readConsoleBytes, writeConsoleBytes --
+ * Wrapper for ReadConsole{A,W}, that takes and returns number of bytes
+ * instead of number of TCHARS
*/
-static DWORD
-ReadConsoleChars(
+static BOOL
+readConsoleBytes(
HANDLE hConsole,
- WCHAR *lpBuffer,
- Tcl_Size nChars,
- Tcl_Size *nCharsReadPtr)
+ LPVOID lpBuffer,
+ DWORD nbytes,
+ LPDWORD nbytesread)
{
- DWORD nRead;
+ DWORD ntchars;
BOOL result;
-
- /*
- * If user types a Ctrl-Break or Ctrl-C, ReadConsole will return success
- * with ntchars == 0 and GetLastError() will be ERROR_OPERATION_ABORTED.
- * If no Ctrl signal handlers have been established, the default signal
- * OS handler in a separate thread will terminate the program. If a Ctrl
- * signal handler has been established (through an extension for
- * example), it will run and take whatever action it deems appropriate.
- *
- * If one thread closes its channel, it calls CancelSynchronousIo on the
- * console handle which results again in success being returned and
- * GetLastError() being ERROR_OPERATION_ABORTED but ntchars in
- * unmodified.
- *
- * In both cases above we will return success but with nbytesread as 0.
- * This allows caller to check for thread termination etc.
- *
- * See https://bugs.python.org/issue30237
- * or https://github.com/microsoft/terminal/issues/12143
- */
- nRead = (DWORD)-1;
- result = ReadConsoleW(hConsole, lpBuffer, nChars, &nRead, NULL);
- if (result) {
- if ((nRead == 0 || nRead == (DWORD)-1)
- && GetLastError() == ERROR_OPERATION_ABORTED) {
- nRead = 0;
- }
- *nCharsReadPtr = nRead;
- return 0;
- } else {
- return GetLastError();
- }
+ int tcharsize;
+ tcharsize = tclWinProcs->useWide? 2 : 1;
+ result = tclWinProcs->readConsoleProc(
+ hConsole, lpBuffer, nbytes / tcharsize, &ntchars, NULL);
+ if (nbytesread)
+ *nbytesread = (ntchars*tcharsize);
+ return result;
}
-
-/*
- *------------------------------------------------------------------------
- *
- * WriteConsoleChars --
- *
- * Wrapper for WriteConsoleW.
- *
- * Results:
- * Returns 0 on success, Windows error code on failure.
- *
- * Side effects:
- * On success the number of characters (not bytes) written is stored in
- * *nCharsWrittenPtr. This will be 0 if the operation was interrupted by
- * a Ctrl-C or a CancelIo call.
- *
- *------------------------------------------------------------------------
- */
-static DWORD
-WriteConsoleChars(
+static BOOL
+writeConsoleBytes(
HANDLE hConsole,
- const WCHAR *lpBuffer,
- Tcl_Size nChars,
- Tcl_Size *nCharsWrittenPtr)
+ const VOID *lpBuffer,
+ DWORD nbytes,
+ LPDWORD nbyteswritten)
{
- DWORD nCharsWritten;
+ DWORD ntchars;
BOOL result;
-
- /* See comments in ReadConsoleChars, not sure that applies here */
- nCharsWritten = (DWORD)-1;
- result = WriteConsoleW(hConsole, lpBuffer, nChars, &nCharsWritten, NULL);
- if (result) {
- if (nCharsWritten == (DWORD) -1) {
- nCharsWritten = 0;
- }
- *nCharsWrittenPtr = nCharsWritten;
- return 0;
- } else {
- return GetLastError();
- }
+ int tcharsize;
+ tcharsize = tclWinProcs->useWide? 2 : 1;
+ result = tclWinProcs->writeConsoleProc(
+ hConsole, lpBuffer, nbytes / tcharsize, &ntchars, NULL);
+ if (nbyteswritten)
+ *nbyteswritten = (ntchars*tcharsize);
+ return result;
}
/*
@@ -636,24 +242,26 @@ WriteConsoleChars(
static void
ConsoleInit(void)
{
+ ThreadSpecificData *tsdPtr;
+
/*
* Check the initialized flag first, then check again in the mutex. This
* is a speed enhancement.
*/
- if (!gInitialized) {
- AcquireSRWLockExclusive(&gConsoleLock);
- if (!gInitialized) {
- gInitialized = 1;
+ if (!initialized) {
+ Tcl_MutexLock(&consoleMutex);
+ if (!initialized) {
+ initialized = 1;
Tcl_CreateExitHandler(ProcExitHandler, NULL);
}
- ReleaseSRWLockExclusive(&gConsoleLock);
+ Tcl_MutexUnlock(&consoleMutex);
}
- if (TclThreadDataKeyGet(&dataKey) == NULL) {
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
- tsdPtr->notUsed = 0;
+ tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
+ if (tsdPtr == NULL) {
+ tsdPtr = TCL_TSD_INIT(&dataKey);
+ tsdPtr->firstConsolePtr = NULL;
Tcl_CreateEventSource(ConsoleSetupProc, ConsoleCheckProc, NULL);
Tcl_CreateThreadExitHandler(ConsoleExitHandler, NULL);
}
@@ -678,7 +286,7 @@ ConsoleInit(void)
static void
ConsoleExitHandler(
- TCL_UNUSED(void *))
+ ClientData clientData) /* Old window proc */
{
Tcl_DeleteEventSource(ConsoleSetupProc, ConsoleCheckProc, NULL);
}
@@ -702,50 +310,11 @@ ConsoleExitHandler(
static void
ProcExitHandler(
- TCL_UNUSED(void *))
+ ClientData clientData) /* Old window proc */
{
- AcquireSRWLockExclusive(&gConsoleLock);
- gInitialized = 0;
- ReleaseSRWLockExclusive(&gConsoleLock);
-}
-
-/*
- *------------------------------------------------------------------------
- *
- * NudgeWatchers --
- *
- * Wakes up all threads which have file event watchers on the passed
- * console handle.
- *
- * The function locks and releases gConsoleLock.
- * Caller must not be holding locks that will violate lock hierarchy.
- *
- * Results:
- * None.
- *
- * Side effects:
- * As above.
- *------------------------------------------------------------------------
- */
-static void
-NudgeWatchers(
- HANDLE consoleHandle)
-{
- ConsoleChannelInfo *chanInfoPtr;
- AcquireSRWLockShared(&gConsoleLock); /* Shared-read lock */
- for (chanInfoPtr = gWatchingChannelList; chanInfoPtr;
- chanInfoPtr = chanInfoPtr->nextWatchingChannelPtr) {
- /*
- * Notify channels interested in our handle AND that have
- * a thread attached.
- * No lock needed for chanInfoPtr. See ConsoleChannelInfo.
- */
- if (chanInfoPtr->handle == consoleHandle
- && chanInfoPtr->threadId != NULL) {
- Tcl_ThreadAlert(chanInfoPtr->threadId);
- }
- }
- ReleaseSRWLockShared(&gConsoleLock);
+ Tcl_MutexLock(&consoleMutex);
+ initialized = 0;
+ Tcl_MutexUnlock(&consoleMutex);
}
/*
@@ -754,9 +323,7 @@ NudgeWatchers(
* ConsoleSetupProc --
*
* This procedure is invoked before Tcl_DoOneEvent blocks waiting for an
- * event. It walks the channel list and if any input channel has data
- * available or output channel has space for data, sets the event loop
- * blocking time to 0 so that it will poll immediately.
+ * event.
*
* Results:
* None.
@@ -769,48 +336,36 @@ NudgeWatchers(
void
ConsoleSetupProc(
- TCL_UNUSED(void *),
+ ClientData data, /* Not used. */
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
- ConsoleChannelInfo *chanInfoPtr;
+ ConsoleInfo *infoPtr;
Tcl_Time blockTime = { 0, 0 };
int block = 1;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!(flags & TCL_FILE_EVENTS)) {
return;
}
/*
- * Walk the list of channels. See general comments for struct
- * ConsoleChannelInfo with regard to locking and field access.
+ * Look to see if any events are already pending. If they are, poll.
*/
- AcquireSRWLockShared(&gConsoleLock); /* READ lock - no data modification */
-
- for (chanInfoPtr = gWatchingChannelList; block && chanInfoPtr != NULL;
- chanInfoPtr = chanInfoPtr->nextWatchingChannelPtr) {
- ConsoleHandleInfo *handleInfoPtr;
- handleInfoPtr = FindConsoleInfo(chanInfoPtr);
- if (handleInfoPtr != NULL) {
- AcquireSRWLockShared(&handleInfoPtr->lock);
- /* Remember at most one of READABLE, WRITABLE set */
- if (chanInfoPtr->watchMask & TCL_READABLE) {
- if (RingBufferLength(&handleInfoPtr->buffer) > 0
- || handleInfoPtr->lastError != ERROR_SUCCESS) {
- block = 0; /* Input data available */
- }
- } else if (chanInfoPtr->watchMask & TCL_WRITABLE) {
- if (RingBufferHasFreeSpace(&handleInfoPtr->buffer)) {
- /* TCL_WRITABLE */
- block = 0; /* Output space available */
- }
+
+ for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL;
+ infoPtr = infoPtr->nextPtr) {
+ if (infoPtr->watchMask & TCL_WRITABLE) {
+ if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) {
+ block = 0;
+ }
+ }
+ if (infoPtr->watchMask & TCL_READABLE) {
+ if (WaitForRead(infoPtr, 0) >= 0) {
+ block = 0;
}
- ReleaseSRWLockShared(&handleInfoPtr->lock);
}
}
- ReleaseSRWLockShared(&gConsoleLock);
-
if (!block) {
- /* At least one channel is readable/writable. Set block time to 0 */
Tcl_SetMaxBlockTime(&blockTime);
}
}
@@ -834,87 +389,57 @@ ConsoleSetupProc(
static void
ConsoleCheckProc(
- TCL_UNUSED(void *),
+ ClientData data, /* Not used. */
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
- ConsoleChannelInfo *chanInfoPtr;
- Tcl_ThreadId me;
+ ConsoleInfo *infoPtr;
+ ConsoleEvent *evPtr;
int needEvent;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!(flags & TCL_FILE_EVENTS)) {
return;
}
- me = Tcl_GetCurrentThread();
-
/*
- * Acquire a shared lock. Note this is ok even though we potentially
- * modify the chanInfoPtr->flags because chanInfoPtr is only modified
- * when it belongs to this thread and no other thread will write to it.
- * THe shared lock is intended to protect the global gWatchingChannelList
- * as we traverse it.
+ * Queue events for any ready consoles that don't already have events
+ * queued.
*/
- AcquireSRWLockShared(&gConsoleLock);
-
- for (chanInfoPtr = gWatchingChannelList; chanInfoPtr != NULL;
- chanInfoPtr = chanInfoPtr->nextWatchingChannelPtr) {
- ConsoleHandleInfo *handleInfoPtr;
- if (chanInfoPtr->threadId != me) {
- /* Some other thread owns the channel */
+ for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL;
+ infoPtr = infoPtr->nextPtr) {
+ if (infoPtr->flags & CONSOLE_PENDING) {
continue;
}
- if (chanInfoPtr->flags & CONSOLE_EVENT_QUEUED) {
- /* A notification event already queued. No point in another. */
- continue;
- }
-
- handleInfoPtr = FindConsoleInfo(chanInfoPtr);
- /* Pointer is safe to access as we are holding gConsoleLock */
- if (handleInfoPtr == NULL) {
- /* Stale event */
- continue;
- }
+ /*
+ * Queue an event if the console is signaled for reading or writing.
+ */
needEvent = 0;
- AcquireSRWLockShared(&handleInfoPtr->lock);
- /* Rememeber channel is read or write, never both */
- if (chanInfoPtr->watchMask & TCL_READABLE) {
- if (RingBufferLength(&handleInfoPtr->buffer) > 0
- || handleInfoPtr->lastError != ERROR_SUCCESS) {
- needEvent = 1; /* Input data available or error/EOF */
+ if (infoPtr->watchMask & TCL_WRITABLE) {
+ if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) {
+ needEvent = 1;
}
- /*
- * TCL_READABLE watch means someone is looking out for data being
- * available, let reader thread know. Note channel need not be
- * ASYNC! (Bug [baa51423c2])
- */
- handleInfoPtr->flags |= CONSOLE_DATA_AWAITED;
- WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
- } else if (chanInfoPtr->watchMask & TCL_WRITABLE) {
- if (RingBufferHasFreeSpace(&handleInfoPtr->buffer)) {
- needEvent = 1; /* Output space available */
+ }
+
+ if (infoPtr->watchMask & TCL_READABLE) {
+ if (WaitForRead(infoPtr, 0) >= 0) {
+ needEvent = 1;
}
}
- ReleaseSRWLockShared(&handleInfoPtr->lock);
if (needEvent) {
- ConsoleEvent *evPtr = (ConsoleEvent *)ckalloc(sizeof(ConsoleEvent));
-
- /* See note above loop why this can be accessed without locks */
- chanInfoPtr->flags |= CONSOLE_EVENT_QUEUED;
- chanInfoPtr->numRefs += 1; /* So it does not go away while event
- is in queue */
+ infoPtr->flags |= CONSOLE_PENDING;
+ evPtr = (ConsoleEvent *) ckalloc(sizeof(ConsoleEvent));
evPtr->header.proc = ConsoleEventProc;
- evPtr->chanInfoPtr = chanInfoPtr;
+ evPtr->infoPtr = infoPtr;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
}
}
-
- ReleaseSRWLockShared(&gConsoleLock);
}
-
+
+
/*
*----------------------------------------------------------------------
*
@@ -933,11 +458,11 @@ ConsoleCheckProc(
static int
ConsoleBlockModeProc(
- void *instanceData, /* Instance data for channel. */
+ ClientData instanceData, /* Instance data for channel. */
int mode) /* TCL_MODE_BLOCKING or
* TCL_MODE_NONBLOCKING. */
{
- ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
+ ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData;
/*
* Consoles on Windows can not be switched between blocking and
@@ -948,9 +473,9 @@ ConsoleBlockModeProc(
*/
if (mode == TCL_MODE_NONBLOCKING) {
- chanInfoPtr->flags |= CONSOLE_ASYNC;
+ infoPtr->flags |= CONSOLE_ASYNC;
} else {
- chanInfoPtr->flags &= ~CONSOLE_ASYNC;
+ infoPtr->flags &= ~(CONSOLE_ASYNC);
}
return 0;
}
@@ -973,102 +498,166 @@ ConsoleBlockModeProc(
static int
ConsoleCloseProc(
- void *instanceData, /* Pointer to ConsoleChannelInfo structure. */
- TCL_UNUSED(Tcl_Interp *),
- int flags)
+ ClientData instanceData, /* Pointer to ConsoleInfo structure. */
+ Tcl_Interp *interp) /* For error reporting. */
{
- ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
- ConsoleHandleInfo *handleInfoPtr;
- int errorCode = 0;
- ConsoleChannelInfo **nextPtrPtr;
- int closeHandle;
-
- if ((flags & (TCL_CLOSE_READ | TCL_CLOSE_WRITE)) != 0) {
- return EINVAL;
- }
- /*
- * Don't close the Win32 handle if the handle is a standard channel
- * during the thread exit process. Otherwise, one thread may kill the
- * stdio of another while exiting. Note an explicit close in script will
- * still close the handle. That's historical behavior on all platforms.
- */
- if (!TclInThreadExit()
- || ( (GetStdHandle(STD_INPUT_HANDLE) != chanInfoPtr->handle)
- && (GetStdHandle(STD_OUTPUT_HANDLE) != chanInfoPtr->handle)
- && (GetStdHandle(STD_ERROR_HANDLE) != chanInfoPtr->handle))) {
- closeHandle = 1;
- } else {
- closeHandle = 0;
- }
+ ConsoleInfo *consolePtr = (ConsoleInfo *) instanceData;
+ int errorCode;
+ ConsoleInfo *infoPtr, **nextPtrPtr;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ DWORD exitCode;
- AcquireSRWLockExclusive(&gConsoleLock);
+ errorCode = 0;
- /* Remove channel from watchers' list */
- for (nextPtrPtr = &gWatchingChannelList; *nextPtrPtr != NULL;
- nextPtrPtr = &(*nextPtrPtr)->nextWatchingChannelPtr) {
- if (*nextPtrPtr == (ConsoleChannelInfo *) chanInfoPtr) {
- *nextPtrPtr = (*nextPtrPtr)->nextWatchingChannelPtr;
- break;
- }
- }
+ /*
+ * Clean up the background thread if necessary. Note that this must be
+ * done before we can close the file, since the thread may be blocking
+ * trying to read from the console.
+ */
- handleInfoPtr = FindConsoleInfo(chanInfoPtr);
- if (handleInfoPtr) {
+ if (consolePtr->readThread) {
/*
- * Console thread may be blocked either waiting for console i/o
- * or waiting on the condition variable for buffer empty/full
+ * The thread may already have closed on it's own. Check it's exit
+ * code.
*/
- AcquireSRWLockShared(&handleInfoPtr->lock);
- if (closeHandle) {
- handleInfoPtr->console = INVALID_HANDLE_VALUE;
+ GetExitCodeThread(consolePtr->readThread, &exitCode);
+
+ if (exitCode == STILL_ACTIVE) {
+ /*
+ * Set the stop event so that if the reader thread is blocked in
+ * ConsoleReaderThread on WaitForMultipleEvents, it will exit
+ * cleanly.
+ */
+
+ SetEvent(consolePtr->stopReader);
+
+ /*
+ * Wait at most 20 milliseconds for the reader thread to close.
+ */
+
+ if (WaitForSingleObject(consolePtr->readThread, 20)
+ == WAIT_TIMEOUT) {
+ /*
+ * Forcibly terminate the background thread as a last resort.
+ * Note that we need to guard against terminating the thread
+ * while it is in the middle of Tcl_ThreadAlert because it
+ * won't be able to release the notifier lock.
+ */
+
+ Tcl_MutexLock(&consoleMutex);
+
+ /* BUG: this leaks memory. */
+ TerminateThread(consolePtr->readThread, 0);
+ Tcl_MutexUnlock(&consoleMutex);
+ }
}
- /* Break the thread out of blocking console i/o */
- handleInfoPtr->numRefs -= 1; /* Remove reference from this channel */
- if (handleInfoPtr->numRefs == 1) {
+ CloseHandle(consolePtr->readThread);
+ CloseHandle(consolePtr->readable);
+ CloseHandle(consolePtr->startReader);
+ CloseHandle(consolePtr->stopReader);
+ consolePtr->readThread = NULL;
+ }
+ consolePtr->validMask &= ~TCL_READABLE;
+
+ /*
+ * Wait for the writer thread to finish the current buffer, then terminate
+ * the thread and close the handles. If the channel is nonblocking, there
+ * should be no pending write operations.
+ */
+
+ if (consolePtr->writeThread) {
+ if (consolePtr->toWrite) {
/*
- * Abort the i/o if no other threads are listening on it.
- * Note without this check, an input line will be skipped on
- * the cancel.
+ * We only need to wait if there is something to write. This may
+ * prevent infinite wait on exit. [python bug 216289]
*/
- CancelSynchronousIo(handleInfoPtr->consoleThread);
+
+ WaitForSingleObject(consolePtr->writable, INFINITE);
}
/*
- * Wake up the console handling thread. Note we do not explicitly
- * tell it handle is closed (below). It will find out on next access
+ * The thread may already have closed on it's own. Check it's exit
+ * code.
*/
- WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
- ReleaseSRWLockShared(&handleInfoPtr->lock);
+ GetExitCodeThread(consolePtr->writeThread, &exitCode);
+
+ if (exitCode == STILL_ACTIVE) {
+ /*
+ * Set the stop event so that if the reader thread is blocked in
+ * ConsoleWriterThread on WaitForMultipleEvents, it will exit
+ * cleanly.
+ */
+
+ SetEvent(consolePtr->stopWriter);
+
+ /*
+ * Wait at most 20 milliseconds for the writer thread to close.
+ */
+
+ if (WaitForSingleObject(consolePtr->writeThread, 20)
+ == WAIT_TIMEOUT) {
+ /*
+ * Forcibly terminate the background thread as a last resort.
+ * Note that we need to guard against terminating the thread
+ * while it is in the middle of Tcl_ThreadAlert because it
+ * won't be able to release the notifier lock.
+ */
+
+ Tcl_MutexLock(&consoleMutex);
+
+ /* BUG: this leaks memory. */
+ TerminateThread(consolePtr->writeThread, 0);
+ Tcl_MutexUnlock(&consoleMutex);
+ }
+ }
+
+ CloseHandle(consolePtr->writeThread);
+ CloseHandle(consolePtr->writable);
+ CloseHandle(consolePtr->startWriter);
+ CloseHandle(consolePtr->stopWriter);
+ consolePtr->writeThread = NULL;
}
+ consolePtr->validMask &= ~TCL_WRITABLE;
- ReleaseSRWLockExclusive(&gConsoleLock);
- chanInfoPtr->channel = NULL;
- chanInfoPtr->watchMask = 0;
- chanInfoPtr->permissions = 0;
+ /*
+ * Don't close the Win32 handle if the handle is a standard channel during
+ * the thread exit process. Otherwise, one thread may kill the stdio of
+ * another.
+ */
- if (closeHandle && chanInfoPtr->handle != INVALID_HANDLE_VALUE) {
- if (CloseHandle(chanInfoPtr->handle) == FALSE) {
- Tcl_WinConvertError(GetLastError());
+ if (!TclInThreadExit()
+ || ((GetStdHandle(STD_INPUT_HANDLE) != consolePtr->handle)
+ && (GetStdHandle(STD_OUTPUT_HANDLE) != consolePtr->handle)
+ && (GetStdHandle(STD_ERROR_HANDLE) != consolePtr->handle))) {
+ if (CloseHandle(consolePtr->handle) == FALSE) {
+ TclWinConvertError(GetLastError());
errorCode = errno;
}
- chanInfoPtr->handle = INVALID_HANDLE_VALUE;
}
+ consolePtr->watchMask &= consolePtr->validMask;
+
/*
- * Note, we can check and manipulate numRefs without a lock because
- * we have removed it from the watch queue so the console thread cannot
- * get at it.
+ * Remove the file from the list of watched files.
*/
- if (chanInfoPtr->numRefs > 1) {
- /* There may be references already on the event queue */
- chanInfoPtr->numRefs -= 1;
- } else {
- ckfree(chanInfoPtr);
+
+ for (nextPtrPtr = &(tsdPtr->firstConsolePtr), infoPtr = *nextPtrPtr;
+ infoPtr != NULL;
+ nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) {
+ if (infoPtr == (ConsoleInfo *)consolePtr) {
+ *nextPtrPtr = infoPtr->nextPtr;
+ break;
+ }
}
+ if (consolePtr->writeBuf != NULL) {
+ ckfree(consolePtr->writeBuf);
+ consolePtr->writeBuf = 0;
+ }
+ ckfree((char*) consolePtr);
return errorCode;
}
@@ -1090,143 +679,73 @@ ConsoleCloseProc(
*
*----------------------------------------------------------------------
*/
+
static int
ConsoleInputProc(
- void *instanceData, /* Console state. */
- char *bufPtr, /* Where to store data read. */
+ ClientData instanceData, /* Console state. */
+ char *buf, /* Where to store data read. */
int bufSize, /* How much space is available in the
* buffer? */
int *errorCode) /* Where to store error code. */
{
- ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
- ConsoleHandleInfo *handleInfoPtr;
- Tcl_Size numRead;
-
- if (chanInfoPtr->handle == INVALID_HANDLE_VALUE) {
- return 0; /* EOF */
- }
+ ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData;
+ DWORD count, bytesRead = 0;
+ int result;
*errorCode = 0;
- AcquireSRWLockShared(&gConsoleLock);
- handleInfoPtr = FindConsoleInfo(chanInfoPtr);
- if (handleInfoPtr == NULL) {
- /* Really shouldn't happen since channel is holding a reference */
- ReleaseSRWLockShared(&gConsoleLock);
- return 0; /* EOF */
+ /*
+ * Synchronize with the reader thread.
+ */
+
+ result = WaitForRead(infoPtr, (infoPtr->flags & CONSOLE_ASYNC) ? 0 : 1);
+
+ /*
+ * If an error occurred, return immediately.
+ */
+
+ if (result == -1) {
+ *errorCode = errno;
+ return -1;
}
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
- ReleaseSRWLockShared(&gConsoleLock); /* AFTER acquiring handleInfoPtr->lock */
- while (1) {
- numRead = RingBufferOut(&handleInfoPtr->buffer, bufPtr, bufSize, 1);
- /*
- * Note: even if channel is closed or has an error, as long there is
- * buffered data, we will pass it up.
- */
- if (numRead != 0) {
- break;
- }
+ if (infoPtr->readFlags & CONSOLE_BUFFERED) {
/*
- * No data available.
- * - If an error was recorded, generate that and reset it.
- * - If EOF, indicate as much. It is up to the application to close
- * the channel.
- * - Otherwise, if non-blocking return EAGAIN or wait for more data.
+ * Data is stored in the buffer.
*/
- if (handleInfoPtr->lastError != 0) {
- if (handleInfoPtr->lastError == ERROR_INVALID_HANDLE) {
- numRead = 0; /* Treat as EOF */
- } else {
- Tcl_WinConvertError(handleInfoPtr->lastError);
- handleInfoPtr->lastError = 0;
- *errorCode = Tcl_GetErrno();
- numRead = -1;
- }
- break;
- }
- if (handleInfoPtr->console == INVALID_HANDLE_VALUE) {
- /* EOF - break with numRead == 0 */
- chanInfoPtr->handle = INVALID_HANDLE_VALUE;
- break;
- }
- /* For async, tell caller we are blocked */
- if (chanInfoPtr->flags & CONSOLE_ASYNC) {
- *errorCode = EWOULDBLOCK;
- numRead = -1;
- break;
- }
+ if (bufSize < (infoPtr->bytesRead - infoPtr->offset)) {
+ memcpy(buf, &infoPtr->buffer[infoPtr->offset], (size_t) bufSize);
+ bytesRead = bufSize;
+ infoPtr->offset += bufSize;
+ } else {
+ memcpy(buf, &infoPtr->buffer[infoPtr->offset], (size_t) bufSize);
+ bytesRead = infoPtr->bytesRead - infoPtr->offset;
- /*
- * Blocking read. Just get data from directly from console. There
- * is a small complication in that
- * 1. The destination buffer should be WCHAR aligned.
- * 2. We can only read even number of bytes (wide-character API).
- * 3. Caller has large enough buffer (else length of line user can
- * enter will be limited)
- * If any condition is not met, we defer to the
- * reader thread which handles these cases rather than dealing with
- * them here (which is a little trickier than it might sound.)
- *
- * TODO - not clear this block is a useful optimization. bufSize by
- * default is 4K which is < INPUT_BUFFER_SIZE and will rarely be
- * increased on stdin.
- */
- if ((1 & (size_t)bufPtr) == 0 /* aligned buffer */
- && (1 & bufSize) == 0 /* Even number of bytes */
- && bufSize > INPUT_BUFFER_SIZE) {
- DWORD lastError;
- Tcl_Size numChars;
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- lastError = ReadConsoleChars(chanInfoPtr->handle,
- (WCHAR *)bufPtr, bufSize / sizeof(WCHAR), &numChars);
- /* NOTE lock released so DON'T break. Return instead */
- if (lastError != ERROR_SUCCESS) {
- Tcl_WinConvertError(lastError);
- *errorCode = Tcl_GetErrno();
- return -1;
- } else if (numChars > 0) {
- /* Successfully read something. */
- return numChars * sizeof(WCHAR);
- } else {
- /*
- * Ctrl-C/Ctrl-Brk interrupt. Loop around to retry.
- * We have to reacquire the lock. No worried about handleInfoPtr
- * having gone away since the channel holds a reference.
- */
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
- continue;
- }
- }
- /*
- * Deferring blocking read to reader thread.
- * Release the lock and sleep. Note that because the channel
- * holds a reference count on handleInfoPtr, it will not
- * be deallocated while the lock is released.
- */
- handleInfoPtr->flags |= CONSOLE_DATA_AWAITED;
- WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
- if (!SleepConditionVariableSRW(&handleInfoPtr->interpThreadCV,
- &handleInfoPtr->lock, INFINITE, 0)) {
- Tcl_WinConvertError(GetLastError());
- *errorCode = Tcl_GetErrno();
- numRead = -1;
- break;
+ /*
+ * Reset the buffer
+ */
+
+ infoPtr->readFlags &= ~CONSOLE_BUFFERED;
+ infoPtr->offset = 0;
}
- /* Lock is reacquired, loop back to try again */
+ return bytesRead;
}
- /* We read data. Ask for more if either async or watching for reads */
- if ((chanInfoPtr->flags & CONSOLE_ASYNC)
- || (chanInfoPtr->watchMask & TCL_READABLE)) {
- handleInfoPtr->flags |= CONSOLE_DATA_AWAITED;
- WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
+ /*
+ * Attempt to read bufSize bytes. The read will return immediately if
+ * there is any data available. Otherwise it will block until at least one
+ * byte is available or an EOF occurs.
+ */
+
+ if (readConsoleBytes(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &count)
+ == TRUE) {
+ buf[count] = '\0';
+ return count;
}
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- return numRead;
+ return -1;
}
/*
@@ -1246,113 +765,79 @@ ConsoleInputProc(
*
*----------------------------------------------------------------------
*/
+
static int
ConsoleOutputProc(
- void *instanceData, /* Console state. */
- const char *buf, /* The data buffer. */
+ ClientData instanceData, /* Console state. */
+ CONST char *buf, /* The data buffer. */
int toWrite, /* How many bytes to write? */
int *errorCode) /* Where to store error code. */
{
- ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
- ConsoleHandleInfo *handleInfoPtr;
- Tcl_Size numWritten;
+ ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData;
+ DWORD bytesWritten, timeout;
*errorCode = 0;
+ timeout = (infoPtr->flags & CONSOLE_ASYNC) ? 0 : INFINITE;
+ if (WaitForSingleObject(infoPtr->writable, timeout) == WAIT_TIMEOUT) {
+ /*
+ * The writer thread is blocked waiting for a write to complete and
+ * the channel is in non-blocking mode.
+ */
- if (chanInfoPtr->handle == INVALID_HANDLE_VALUE) {
- /* Some other thread would have *previously* closed the stdio handle */
- *errorCode = EPIPE;
- return -1;
+ errno = EAGAIN;
+ goto error;
}
- AcquireSRWLockShared(&gConsoleLock);
- handleInfoPtr = FindConsoleInfo(chanInfoPtr);
- if (handleInfoPtr == NULL) {
- /* Really shouldn't happen since channel is holding a reference */
- *errorCode = EPIPE;
- ReleaseSRWLockShared(&gConsoleLock);
- return -1;
- }
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
- ReleaseSRWLockShared(&gConsoleLock); /* AFTER acquiring handleInfoPtr->lock */
+ /*
+ * Check for a background error on the last write.
+ */
- /* Keep looping until all written. Break out for async and errors */
- numWritten = 0;
- while (1) {
- /* Check for error and closing on every loop. */
- if (handleInfoPtr->lastError != 0) {
- Tcl_WinConvertError(handleInfoPtr->lastError);
- *errorCode = Tcl_GetErrno();
- numWritten = -1;
- break;
- }
- if (handleInfoPtr->console == INVALID_HANDLE_VALUE) {
- *errorCode = EPIPE;
- chanInfoPtr->handle = INVALID_HANDLE_VALUE;
- numWritten = -1;
- break;
- }
+ if (infoPtr->writeError) {
+ TclWinConvertError(infoPtr->writeError);
+ infoPtr->writeError = 0;
+ goto error;
+ }
+ if (infoPtr->flags & CONSOLE_ASYNC) {
/*
- * We can either write directly or through the console thread's
- * ring buffer. We have to do the latter when
- * (1) the operation is async since WriteConsoleChars is always blocking
- * (2) when there is already data in the ring buffer because we don't
- * want to reorder output from within a thread
- * (3) when there are an odd number of bytes since WriteConsole
- * takes whole WCHARs
- * (4) when the pointer is not aligned on WCHAR
- * The ring buffer deals with cases (3) and (4). It would be harder
- * to duplicate that here.
+ * The console is non-blocking, so copy the data into the output
+ * buffer and restart the writer thread.
*/
- if ((chanInfoPtr->flags & CONSOLE_ASYNC) /* Case (1) */
- || RingBufferLength(&handleInfoPtr->buffer) != 0 /* Case (2) */
- || (toWrite & 1) != 0 /* Case (3) */
- || (PTR2INT(buf) & 1) != 0) { /* Case (4) */
- numWritten += RingBufferIn(&handleInfoPtr->buffer,
- numWritten + buf, toWrite - numWritten, 1);
- if (numWritten == toWrite || chanInfoPtr->flags & CONSOLE_ASYNC) {
- /* All done or async, just accept whatever was written */
- break;
- }
+
+ if (toWrite > infoPtr->writeBufLen) {
/*
- * Release the lock and sleep. Note that because the channel
- * holds a reference count on handleInfoPtr, it will not
- * be deallocated while the lock is released.
+ * Reallocate the buffer to be large enough to hold the data.
*/
- WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
- if (!SleepConditionVariableSRW(&handleInfoPtr->interpThreadCV,
- &handleInfoPtr->lock, INFINITE, 0)) {
- /* Report the error */
- Tcl_WinConvertError(GetLastError());
- *errorCode = Tcl_GetErrno();
- numWritten = -1;
- break;
- }
- } else {
- /* Direct output */
- DWORD winStatus;
- HANDLE consoleHandle = handleInfoPtr->console;
- /* Unlock before blocking in WriteConsole */
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- /* UNLOCKED so return, DON'T break out of loop as it will unlock
- * again! */
- winStatus = WriteConsoleChars(consoleHandle,
- (WCHAR *)buf, toWrite / sizeof(WCHAR), &numWritten);
- if (winStatus == ERROR_SUCCESS) {
- return numWritten * sizeof(WCHAR);
- } else {
- Tcl_WinConvertError(winStatus);
- *errorCode = Tcl_GetErrno();
- return -1;
+
+ if (infoPtr->writeBuf) {
+ ckfree(infoPtr->writeBuf);
}
+ infoPtr->writeBufLen = toWrite;
+ infoPtr->writeBuf = ckalloc((size_t)toWrite);
}
+ memcpy(infoPtr->writeBuf, buf, (size_t)toWrite);
+ infoPtr->toWrite = toWrite;
+ ResetEvent(infoPtr->writable);
+ SetEvent(infoPtr->startWriter);
+ bytesWritten = toWrite;
+ } else {
+ /*
+ * In the blocking case, just try to write the buffer directly. This
+ * avoids an unnecessary copy.
+ */
- /* Lock must have been reacquired before continuing loop */
+ if (writeConsoleBytes(infoPtr->handle, buf, (DWORD)toWrite,
+ &bytesWritten)
+ == FALSE) {
+ TclWinConvertError(GetLastError());
+ goto error;
+ }
}
- WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- return numWritten;
+ return bytesWritten;
+
+ error:
+ *errorCode = errno;
+ return -1;
}
/*
@@ -1382,84 +867,66 @@ ConsoleEventProc(
int flags) /* Flags that indicate what events to handle,
* such as TCL_FILE_EVENTS. */
{
- ConsoleEvent *consoleEvPtr = (ConsoleEvent *) evPtr;
- ConsoleChannelInfo *chanInfoPtr;
- int freeChannel;
- int mask = 0;
+ ConsoleEvent *consoleEvPtr = (ConsoleEvent *)evPtr;
+ ConsoleInfo *infoPtr;
+ int mask;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!(flags & TCL_FILE_EVENTS)) {
return 0;
}
- chanInfoPtr = consoleEvPtr->chanInfoPtr;
/*
- * We know chanInfoPtr is valid because its reference count would have
- * been incremented when the event was queued. The corresponding release
- * happens in this function.
+ * Search through the list of watched consoles for the one whose handle
+ * matches the event. We do this rather than simply dereferencing the
+ * handle in the event so that consoles can be deleted while the event is
+ * in the queue.
*/
+ for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL;
+ infoPtr = infoPtr->nextPtr) {
+ if (consoleEvPtr->infoPtr == infoPtr) {
+ infoPtr->flags &= ~(CONSOLE_PENDING);
+ break;
+ }
+ }
+
/*
- * Global lock used for chanInfoPtr. A read (shared) lock suffices
- * because all access is within the channel owning thread with the
- * exception of watchers which is a read-only access. See comments
- * to ConsoleChannelInfo.
+ * Remove stale events.
*/
- AcquireSRWLockShared(&gConsoleLock);
- chanInfoPtr->flags &= ~CONSOLE_EVENT_QUEUED;
+
+ if (!infoPtr) {
+ return 1;
+ }
/*
- * Only handle the event if the Tcl channel has not gone away AND is
- * still owned by this thread AND is still watching events.
+ * Check to see if the console is readable. Note that we can't tell if a
+ * console is writable, so we always report it as being writable unless we
+ * have detected EOF.
*/
- if (chanInfoPtr->channel && chanInfoPtr->threadId == Tcl_GetCurrentThread()
- && (chanInfoPtr->watchMask & (TCL_READABLE|TCL_WRITABLE))) {
- ConsoleHandleInfo *handleInfoPtr = FindConsoleInfo(chanInfoPtr);
- if (handleInfoPtr == NULL) {
- /* Console was closed. EOF->read event only (not write) */
- if (chanInfoPtr->watchMask & TCL_READABLE) {
- mask = TCL_READABLE;
- }
- } else {
- AcquireSRWLockShared(&handleInfoPtr->lock);
- /* Remember at most one of READABLE, WRITABLE set */
- if ((chanInfoPtr->watchMask & TCL_READABLE)
- && RingBufferLength(&handleInfoPtr->buffer)) {
+
+ mask = 0;
+ if (infoPtr->watchMask & TCL_WRITABLE) {
+ if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) {
+ mask = TCL_WRITABLE;
+ }
+ }
+
+ if (infoPtr->watchMask & TCL_READABLE) {
+ if (WaitForRead(infoPtr, 0) >= 0) {
+ if (infoPtr->readFlags & CONSOLE_EOF) {
mask = TCL_READABLE;
- } else if ((chanInfoPtr->watchMask & TCL_WRITABLE)
- && RingBufferHasFreeSpace(&handleInfoPtr->buffer)) {
- /* Generate write event space available */
- mask = TCL_WRITABLE;
+ } else {
+ mask |= TCL_READABLE;
}
- ReleaseSRWLockShared(&handleInfoPtr->lock);
}
}
/*
- * Tcl_NotifyChannel can recurse through the file event callback so need
- * to release locks first. Our reference still holds so no danger of
- * chanInfoPtr being deallocated if the callback closes the channel.
+ * Inform the channel of the events.
*/
- ReleaseSRWLockShared(&gConsoleLock);
- if (mask) {
- Tcl_NotifyChannel(chanInfoPtr->channel, mask);
- /* Note: chanInfoPtr ref count may have changed */
- }
-
- /* No need to lock - see comments earlier */
-
- /* Remove the reference to the channel from event record */
- if (chanInfoPtr->numRefs > 1) {
- chanInfoPtr->numRefs -= 1;
- freeChannel = 0;
- } else {
- assert(chanInfoPtr->channel == NULL);
- freeChannel = 1;
- }
-
- if (freeChannel) {
- ckfree(chanInfoPtr);
- }
+ Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask & mask);
return 1;
}
@@ -1481,57 +948,42 @@ ConsoleEventProc(
static void
ConsoleWatchProc(
- void *instanceData, /* Console state. */
- int newMask) /* What events to watch for, one of
- * of TCL_READABLE, TCL_WRITABLE */
+ ClientData instanceData, /* Console state. */
+ int mask) /* What events to watch for, OR-ed combination
+ * of TCL_READABLE, TCL_WRITABLE and
+ * TCL_EXCEPTION. */
{
- ConsoleChannelInfo **nextPtrPtr, *ptr;
- ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
- int oldMask = chanInfoPtr->watchMask;
+ ConsoleInfo **nextPtrPtr, *ptr;
+ ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData;
+ int oldMask = infoPtr->watchMask;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
* Since most of the work is handled by the background threads, we just
* need to update the watchMask and then force the notifier to poll once.
*/
- chanInfoPtr->watchMask = newMask & chanInfoPtr->permissions;
- if (chanInfoPtr->watchMask) {
+ infoPtr->watchMask = mask & infoPtr->validMask;
+ if (infoPtr->watchMask) {
Tcl_Time blockTime = { 0, 0 };
-
if (!oldMask) {
- AcquireSRWLockExclusive(&gConsoleLock);
- /* Add to list of watched channels */
- chanInfoPtr->nextWatchingChannelPtr = gWatchingChannelList;
- gWatchingChannelList = chanInfoPtr;
-
- /*
- * For read channels, need to tell the console reader thread
- * that we are looking for data since it will not do reads until
- * it knows someone is awaiting.
- */
- ConsoleHandleInfo *handleInfoPtr = FindConsoleInfo(chanInfoPtr);
- if (handleInfoPtr) {
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
- handleInfoPtr->flags |= CONSOLE_DATA_AWAITED;
- WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- }
- ReleaseSRWLockExclusive(&gConsoleLock);
+ infoPtr->nextPtr = tsdPtr->firstConsolePtr;
+ tsdPtr->firstConsolePtr = infoPtr;
}
Tcl_SetMaxBlockTime(&blockTime);
} else if (oldMask) {
- /* Remove from list of watched channels */
+ /*
+ * Remove the console from the list of watched consoles.
+ */
- AcquireSRWLockExclusive(&gConsoleLock);
- for (nextPtrPtr = &gWatchingChannelList, ptr = *nextPtrPtr;
+ for (nextPtrPtr = &(tsdPtr->firstConsolePtr), ptr = *nextPtrPtr;
ptr != NULL;
- nextPtrPtr = &ptr->nextWatchingChannelPtr, ptr = *nextPtrPtr) {
- if (chanInfoPtr == ptr) {
- *nextPtrPtr = ptr->nextWatchingChannelPtr;
+ nextPtrPtr = &ptr->nextPtr, ptr = *nextPtrPtr) {
+ if (infoPtr == ptr) {
+ *nextPtrPtr = ptr->nextPtr;
break;
}
}
- ReleaseSRWLockExclusive(&gConsoleLock);
}
}
@@ -1555,70 +1007,117 @@ ConsoleWatchProc(
static int
ConsoleGetHandleProc(
- void *instanceData, /* The console state. */
- TCL_UNUSED(int) /*direction*/,
- void **handlePtr) /* Where to store the handle. */
+ ClientData instanceData, /* The console state. */
+ int direction, /* TCL_READABLE or TCL_WRITABLE */
+ ClientData *handlePtr) /* Where to store the handle. */
{
- ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
+ ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData;
- if (chanInfoPtr->handle == INVALID_HANDLE_VALUE) {
- return TCL_ERROR;
- } else {
- *handlePtr = chanInfoPtr->handle;
- return TCL_OK;
- }
+ *handlePtr = (ClientData) infoPtr->handle;
+ return TCL_OK;
}
/*
- *------------------------------------------------------------------------
+ *----------------------------------------------------------------------
*
- * ConsoleDataAvailable --
+ * WaitForRead --
*
- * Checks if there is data in the console input queue.
+ * Wait until some data is available, the console is at EOF or the reader
+ * thread is blocked waiting for data (if the channel is in non-blocking
+ * mode).
*
* Results:
- * Returns 1 if the input queue has data, -1 on error else 0 if empty.
+ * Returns 1 if console is readable. Returns 0 if there is no data on the
+ * console, but there is buffered data. Returns -1 if an error occurred.
+ * If an error occurred, the threads may not be synchronized.
*
* Side effects:
- * None.
+ * Updates the shared state flags. If no error occurred, the reader
+ * thread is blocked waiting for a signal from the main thread.
*
- *------------------------------------------------------------------------
+ *----------------------------------------------------------------------
*/
- static int
- ConsoleDataAvailable(
- HANDLE consoleHandle)
+
+static int
+WaitForRead(
+ ConsoleInfo *infoPtr, /* Console state. */
+ int blocking) /* Indicates whether call should be blocking
+ * or not. */
{
- INPUT_RECORD input[10];
- DWORD count;
- DWORD i;
+ DWORD timeout, count;
+ HANDLE *handle = infoPtr->handle;
+ INPUT_RECORD input;
- /*
- * Need at least one keyboard event.
- */
- if (PeekConsoleInputW(consoleHandle, input,
- sizeof(input) / sizeof(input[0]), &count) == FALSE) {
- return -1;
- }
- /*
- * Even if windows size and mouse events are disabled, can still have
- * events other than keyboard, like focus events. Look for at least one
- * keydown event because a trailing LF keyup is always present from the
- * last input. However, if our buffer is full, assume there is a key
- * down somewhere in the unread buffer. I suppose we could expand the
- * buffer but not worth...
- */
- if (count == (sizeof(input)/sizeof(input[0]))) {
- return 1;
- }
- for (i = 0; i < count; ++i) {
- if (input[i].EventType == KEY_EVENT
- && input[i].Event.KeyEvent.bKeyDown) {
+ while (1) {
+ /*
+ * Synchronize with the reader thread.
+ */
+
+ timeout = blocking ? INFINITE : 0;
+ if (WaitForSingleObject(infoPtr->readable, timeout) == WAIT_TIMEOUT) {
+ /*
+ * The reader thread is blocked waiting for data and the channel
+ * is in non-blocking mode.
+ */
+
+ errno = EAGAIN;
+ return -1;
+ }
+
+ /*
+ * At this point, the two threads are synchronized, so it is safe to
+ * access shared state.
+ */
+
+ /*
+ * If the console has hit EOF, it is always readable.
+ */
+
+ if (infoPtr->readFlags & CONSOLE_EOF) {
+ return 1;
+ }
+
+ if (PeekConsoleInput(handle, &input, 1, &count) == FALSE) {
+ /*
+ * Check to see if the peek failed because of EOF.
+ */
+
+ TclWinConvertError(GetLastError());
+
+ if (errno == EOF) {
+ infoPtr->readFlags |= CONSOLE_EOF;
+ return 1;
+ }
+
+ /*
+ * Ignore errors if there is data in the buffer.
+ */
+
+ if (infoPtr->readFlags & CONSOLE_BUFFERED) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
+ /*
+ * If there is data in the buffer, the console must be readable (since
+ * it is a line-oriented device).
+ */
+
+ if (infoPtr->readFlags & CONSOLE_BUFFERED) {
return 1;
}
+
+ /*
+ * There wasn't any data available, so reset the thread and try again.
+ */
+
+ ResetEvent(infoPtr->readable);
+ SetEvent(infoPtr->startReader);
}
- return 0;
}
-
+
/*
*----------------------------------------------------------------------
*
@@ -1628,10 +1127,12 @@ ConsoleGetHandleProc(
* available on a console.
*
* Results:
- * Always 0.
+ * None.
*
* Side effects:
- * Signals the main thread when input become available.
+ * Signals the main thread when input become available. May cause the
+ * main thread to wake up by posting a message. May one line from the
+ * console for each wait operation.
*
*----------------------------------------------------------------------
*/
@@ -1640,182 +1141,75 @@ static DWORD WINAPI
ConsoleReaderThread(
LPVOID arg)
{
- ConsoleHandleInfo *handleInfoPtr = (ConsoleHandleInfo *) arg;
- ConsoleHandleInfo **iterator;
- Tcl_Size inputLen = 0;
- Tcl_Size inputOffset = 0;
- Tcl_Size lastReadSize = 0;
- DWORD sleepTime;
- char inputChars[INPUT_BUFFER_SIZE];
+ ConsoleInfo *infoPtr = (ConsoleInfo *)arg;
+ HANDLE *handle = infoPtr->handle;
+ DWORD waitResult;
+ HANDLE wEvents[2];
- /*
- * Keep looping until one of the following happens.
- * - there are no more channels listening on the console
- * - the console handle has been closed
- */
+ /* The first event takes precedence. */
+ wEvents[0] = infoPtr->stopReader;
+ wEvents[1] = infoPtr->startReader;
- /* This thread is holding a reference so pointer is safe */
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
+ for (;;) {
+ /*
+ * Wait for the main thread to signal before attempting to wait.
+ */
- while (1) {
+ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
- if (handleInfoPtr->numRefs == 1) {
+ if (waitResult != (WAIT_OBJECT_0 + 1)) {
/*
- * Sole reference. That's this thread. Exit since no clients
- * and no way for a thread to attach to a console after process
- * start.
+ * The start event was not signaled. It must be the stop event or
+ * an error, so exit this thread.
*/
+
break;
}
/*
- * Shared buffer has no data. If we have some in our private buffer
- * copy that. Else check if there has been an error. In both cases
- * notify the interp threads.
+ * Look for data on the console, but first ignore any events that are
+ * not KEY_EVENTs.
*/
- if (inputLen > 0 || handleInfoPtr->lastError != 0) {
- HANDLE consoleHandle;
- if (inputLen > 0) {
- /* Private buffer has data. Copy it over. */
- Tcl_Size nStored;
-
- assert((inputLen - inputOffset) > 0);
- nStored = RingBufferIn(&handleInfoPtr->buffer,
- inputOffset + inputChars, inputLen - inputOffset,
- 1);
- inputOffset += nStored;
- if (inputOffset == inputLen) {
- /* Temp buffer now empty */
- inputOffset = 0;
- inputLen = 0;
- }
- } else {
- /*
- * On error, nothing but inform caller and wait
- * We do not want to exit until there are no client interps.
- */
- }
+ if (readConsoleBytes(handle, infoPtr->buffer, CONSOLE_BUFFER_SIZE,
+ (LPDWORD) &infoPtr->bytesRead) != FALSE) {
/*
- * Wake up any threads waiting either synchronously or
- * asynchronously. Since we are providing data, turn off the
- * AWAITED flag. If the data provided is not sufficient the
- * clients will request again. Note we have to wake up ALL
- * awaiting threads, not just one, so they can all reissue
- * requests if needed. (In a properly designed app, at most one
- * thread should be reading standard input but...)
- */
- handleInfoPtr->flags &= ~CONSOLE_DATA_AWAITED;
- /* Wake synchronous channels */
- WakeAllConditionVariable(&handleInfoPtr->interpThreadCV);
- /*
- * Wake up async channels registered for file events. Note in
- * order to follow the locking hierarchy, we need to release
- * handleInfoPtr->lock before calling NudgeWatchers.
+ * Data was stored in the buffer.
*/
- consoleHandle = handleInfoPtr->console;
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- NudgeWatchers(consoleHandle);
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
-
- /*
- * Loop back to recheck for exit conditions changes while the
- * the lock was not held.
- */
- continue;
- }
- assert(inputLen == 0);
+ infoPtr->readFlags |= CONSOLE_BUFFERED;
+ } else {
+ DWORD err;
+ err = GetLastError();
- /*
- * Read more data in two cases:
- * 1. The previous read filled the buffer and there could be more
- * data in the console internal *text* buffer. Note
- * ConsolePendingInput (checked in ConsoleDataAvailable) will NOT
- * show this. It holds input events not yet translated to text.
- * 2. Tcl threads want more data AND there is data in the
- * ConsolePendingInput buffer. The latter check necessary because
- * we do not want to read ahead because the interp thread might
- * change the read mode, e.g. turning off echo for password
- * input. So only do so if at least one interpreter has requested
- * data.
- */
- if (lastReadSize == sizeof(inputChars)
- || ((handleInfoPtr->flags & CONSOLE_DATA_AWAITED)
- && ConsoleDataAvailable(handleInfoPtr->console))) {
- DWORD error;
- /* Do not hold the lock while blocked in console */
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- error = ReadConsoleChars(handleInfoPtr->console,
- (WCHAR *)inputChars, sizeof(inputChars) / sizeof(WCHAR),
- &inputLen);
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
- if (error == 0) {
- inputLen *= sizeof(WCHAR);
- lastReadSize = inputLen;
- } else {
- /*
- * We only store the last error. It is up to channel
- * handlers whether to close or not in case of errors.
- */
- lastReadSize = 0;
- handleInfoPtr->lastError = error;
- if (handleInfoPtr->lastError == ERROR_INVALID_HANDLE) {
- handleInfoPtr->console = INVALID_HANDLE_VALUE;
- }
+ if (err == (DWORD)EOF) {
+ infoPtr->readFlags = CONSOLE_EOF;
}
- } else {
- /*
- * Either no one was asking for data, or no data was available.
- * In the former case, wait until someone wakes us asking for
- * data. In the latter case, there is no alternative but to
- * poll since ReadConsole does not support async operation.
- * So sleep for a short while and loop back to retry.
- */
- sleepTime =
- handleInfoPtr->flags & CONSOLE_DATA_AWAITED ? 50 : INFINITE;
- SleepConditionVariableSRW(&handleInfoPtr->consoleThreadCV,
- &handleInfoPtr->lock, sleepTime, 0);
}
- /* Loop again to check for exit or wait for readers to wake us */
- }
-
- /*
- * Exiting:
- * - remove the console from global list
- * - close the handle if still valid
- * - release the structure
- * Note there is not need to check for any watchers because we only
- * exit when there are no channels open to this console.
- */
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- AcquireSRWLockExclusive(&gConsoleLock); /* Modifying - exclusive lock */
- for (iterator = &gConsoleHandleInfoList; *iterator;
- iterator = &(*iterator)->nextPtr) {
- if (*iterator == handleInfoPtr) {
- *iterator = handleInfoPtr->nextPtr;
- break;
- }
- }
- ReleaseSRWLockExclusive(&gConsoleLock);
+ /*
+ * Signal the main thread by signalling the readable event and then
+ * waking up the notifier thread.
+ */
- /* No need for relocking - no other thread should have access to it now */
- RingBufferClear(&handleInfoPtr->buffer);
+ SetEvent(infoPtr->readable);
- if (handleInfoPtr->console != INVALID_HANDLE_VALUE
- && handleInfoPtr->lastError != ERROR_INVALID_HANDLE) {
- SetConsoleMode(handleInfoPtr->console, handleInfoPtr->initMode);
/*
- * NOTE: we do not call CloseHandle(handleInfoPtr->console) here.
- * As per the GetStdHandle documentation, it need not be closed.
- * Other components may be directly using it. Note however that
- * an explicit chan close script command does close the handle
- * for all threads.
+ * Alert the foreground thread. Note that we need to treat this like a
+ * critical section so the foreground thread does not terminate this
+ * thread while we are holding a mutex in the notifier code.
*/
- }
- ckfree(handleInfoPtr);
+ Tcl_MutexLock(&consoleMutex);
+ if (infoPtr->threadId != NULL) {
+ /*
+ * TIP #218. When in flight ignore the event, no one will receive
+ * it anyway.
+ */
+ Tcl_ThreadAlert(infoPtr->threadId);
+ }
+ Tcl_MutexUnlock(&consoleMutex);
+ }
return 0;
}
@@ -1832,255 +1226,91 @@ ConsoleReaderThread(
* Always returns 0.
*
* Side effects:
- * Signals the main thread when an output operation is completed.
+
+ * Signals the main thread when an output operation is completed. May
+ * cause the main thread to wake up by posting a message.
*
*----------------------------------------------------------------------
*/
+
static DWORD WINAPI
ConsoleWriterThread(
LPVOID arg)
{
- ConsoleHandleInfo *handleInfoPtr = (ConsoleHandleInfo *) arg;
- ConsoleHandleInfo **iterator;
- BOOL success;
- Tcl_Size numBytes;
- /*
- * This buffer size has no relation really with the size of the shared
- * buffer. Could be bigger or smaller. Make larger as multiple threads
- * could potentially be writing to it.
- */
- char buffer[2*CONSOLE_BUFFER_SIZE];
- /*
- * Keep looping until one of the following happens.
- *
- * - there are not more channels listening on the console
- * - the console handle has been closed
- *
- * On each iteration,
- * - if the channel buffer is empty, wait for some channel writer to write
- * - if there is data in our buffer, write it to the console
- */
-
- /* This thread is holding a reference so pointer is safe */
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
- while (1) {
- /* handleInfoPtr->lock must be held on entry to loop */
+ ConsoleInfo *infoPtr = (ConsoleInfo *)arg;
+ HANDLE *handle = infoPtr->handle;
+ DWORD count, toWrite, waitResult;
+ char *buf;
+ HANDLE wEvents[2];
- int offset;
- HANDLE consoleHandle;
+ /* The first event takes precedence. */
+ wEvents[0] = infoPtr->stopWriter;
+ wEvents[1] = infoPtr->startWriter;
+ for (;;) {
/*
- * Sadly, we need to do another copy because do not want to hold
- * a lock on handleInfoPtr->buffer while calling WriteConsole as that
- * might block. Also, we only want to copy an integral number of
- * WCHAR's, i.e. even number of chars so do some length checks up
- * front.
+ * Wait for the main thread to signal before attempting to write.
*/
- numBytes = RingBufferLength(&handleInfoPtr->buffer);
- numBytes &= ~1; /* Copy integral number of WCHARs -> even number of bytes */
- if (numBytes == 0) {
- /* No data to write */
- if (handleInfoPtr->numRefs == 1) {
- /*
- * Sole reference. That's this thread. Exit since no clients
- * and no buffered output.
- */
- break;
- }
- /* Wake up any threads waiting synchronously. */
- WakeConditionVariable(&handleInfoPtr->interpThreadCV);
- success = SleepConditionVariableSRW(&handleInfoPtr->consoleThreadCV,
- &handleInfoPtr->lock, INFINITE, 0);
- /* Note: lock has been acquired again! */
- if (!success && GetLastError() != ERROR_TIMEOUT) {
- /* TODO - what can be done? Should not happen */
- /* For now keep going */
- }
- continue;
- }
- /* We have data to write */
- if ((size_t)numBytes > (sizeof(buffer) / sizeof(buffer[0]))) {
- numBytes = sizeof(buffer);
+ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
+
+ if (waitResult != (WAIT_OBJECT_0 + 1)) {
+ /*
+ * The start event was not signaled. It must be the stop event or
+ * an error, so exit this thread.
+ */
+
+ break;
}
- /* No need to check result, we already checked length bytes available */
- RingBufferOut(&handleInfoPtr->buffer, buffer, numBytes, 0);
-
- consoleHandle = handleInfoPtr->console;
- WakeConditionVariable(&handleInfoPtr->interpThreadCV);
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- offset = 0;
- while (numBytes > 0) {
- Tcl_Size numWChars = numBytes / sizeof(WCHAR);
- DWORD status;
- status = WriteConsoleChars(handleInfoPtr->console,
- (WCHAR *)(offset + buffer), numWChars, &numWChars);
- if (status != 0) {
- /* Only overwrite if no previous error */
- if (handleInfoPtr->lastError == 0) {
- handleInfoPtr->lastError = status;
- }
- if (status == ERROR_INVALID_HANDLE) {
- handleInfoPtr->console = INVALID_HANDLE_VALUE;
- }
- /* Assume this write is done but keep looping in case
- * it is a transient error. Not sure just closing handle
- * and exiting thread is a good idea until all references
- * from interp threads are gone.
- */
+
+ buf = infoPtr->writeBuf;
+ toWrite = infoPtr->toWrite;
+
+ /*
+ * Loop until all of the bytes are written or an error occurs.
+ */
+
+ while (toWrite > 0) {
+ if (writeConsoleBytes(handle, buf, (DWORD)toWrite,
+ &count) == FALSE) {
+ infoPtr->writeError = GetLastError();
break;
+ } else {
+ toWrite -= count;
+ buf += count;
}
- numBytes -= numWChars * sizeof(WCHAR);
- offset += numWChars * sizeof(WCHAR);
}
- /* Wake up any threads waiting synchronously. */
- WakeConditionVariable(&handleInfoPtr->interpThreadCV);
/*
- * Wake up all channels registered for file events. Note in
- * order to follow the locking hierarchy, we cannot hold any locks
- * when calling NudgeWatchers.
+ * Signal the main thread by signalling the writable event and then
+ * waking up the notifier thread.
*/
- NudgeWatchers(consoleHandle);
-
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
- }
- /*
- * Exiting:
- * - remove the console from global list
- * - release the structure
- * NOTE: we do not call CloseHandle(handleInfoPtr->console) here.
- * As per the GetStdHandle documentation, it need not be closed.
- * Other components may be directly using it. Note however that
- * an explicit chan close script command does close the handle
- * for all threads.
- */
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
- AcquireSRWLockExclusive(&gConsoleLock); /* Modifying - exclusive lock */
- for (iterator = &gConsoleHandleInfoList; *iterator;
- iterator = &(*iterator)->nextPtr) {
- if (*iterator == handleInfoPtr) {
- *iterator = handleInfoPtr->nextPtr;
- break;
- }
- }
- ReleaseSRWLockExclusive(&gConsoleLock);
+ SetEvent(infoPtr->writable);
- RingBufferClear(&handleInfoPtr->buffer);
+ /*
+ * Alert the foreground thread. Note that we need to treat this like a
+ * critical section so the foreground thread does not terminate this
+ * thread while we are holding a mutex in the notifier code.
+ */
- ckfree(handleInfoPtr);
+ Tcl_MutexLock(&consoleMutex);
+ if (infoPtr->threadId != NULL) {
+ /*
+ * TIP #218. When in flight ignore the event, no one will receive
+ * it anyway.
+ */
- return 0;
-}
-
-/*
- *------------------------------------------------------------------------
- *
- * AllocateConsoleHandleInfo --
- *
- * Allocates a ConsoleHandleInfo for the passed console handle. As
- * a side effect starts a console thread to handle i/o on the handle.
- *
- * Important: Caller must be holding an EXCLUSIVE lock on gConsoleLock
- * when calling this function. The lock continues to be held on return.
- *
- * Results:
- * Pointer to an unlocked ConsoleHandleInfo structure. The reference
- * count on the structure is 1. This corresponds to the common reference
- * from the console thread and the gConsoleHandleInfoList. Returns NULL
- * on error.
- *
- * Side effects:
- * A console reader or writer thread is started. The returned structure
- * is placed on the active console handler list gConsoleHandleInfoList.
- *
- *------------------------------------------------------------------------
- */
-static ConsoleHandleInfo *
-AllocateConsoleHandleInfo(
- HANDLE consoleHandle,
- int permissions) /* TCL_READABLE or TCL_WRITABLE */
-{
- ConsoleHandleInfo *handleInfoPtr;
- DWORD consoleMode;
-
- handleInfoPtr = (ConsoleHandleInfo *) ckalloc(sizeof(*handleInfoPtr));
- memset(handleInfoPtr, 0, sizeof(*handleInfoPtr));
- memset(handleInfoPtr, 0, sizeof(*handleInfoPtr));
- handleInfoPtr->console = consoleHandle;
- InitializeSRWLock(&handleInfoPtr->lock);
- InitializeConditionVariable(&handleInfoPtr->consoleThreadCV);
- InitializeConditionVariable(&handleInfoPtr->interpThreadCV);
- RingBufferInit(&handleInfoPtr->buffer, CONSOLE_BUFFER_SIZE);
- handleInfoPtr->lastError = 0;
- handleInfoPtr->permissions = permissions;
- handleInfoPtr->numRefs = 1; /* See function header */
- if (permissions == TCL_READABLE) {
- GetConsoleMode(consoleHandle, &handleInfoPtr->initMode);
- consoleMode = handleInfoPtr->initMode;
- consoleMode &= ~(ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
- consoleMode |= ENABLE_LINE_INPUT;
- SetConsoleMode(consoleHandle, consoleMode);
- }
- handleInfoPtr->consoleThread = CreateThread(
- NULL, /* default security descriptor */
- 2*CONSOLE_BUFFER_SIZE, /* Stack size - gets rounded up to granularity */
- permissions == TCL_READABLE ? ConsoleReaderThread : ConsoleWriterThread,
- handleInfoPtr, /* Pass to thread */
- 0, /* Flags - no special cases */
- NULL); /* Don't care about thread id */
- if (handleInfoPtr->consoleThread == NULL) {
- /* Note - SRWLock and condition variables do not need finalization */
- RingBufferClear(&handleInfoPtr->buffer);
- ckfree(handleInfoPtr);
- return NULL;
+ Tcl_ThreadAlert(infoPtr->threadId);
+ }
+ Tcl_MutexUnlock(&consoleMutex);
}
- /* Chain onto global list */
- handleInfoPtr->nextPtr = gConsoleHandleInfoList;
- gConsoleHandleInfoList = handleInfoPtr;
-
- return handleInfoPtr;
+ return 0;
}
/*
- *------------------------------------------------------------------------
- *
- * FindConsoleInfo --
- *
- * Finds the ConsoleHandleInfo record for a given ConsoleChannelInfo.
- * The found record must match the console handle. It is the caller's
- * responsibility to check the permissions (read/write) in the returned
- * ConsoleHandleInfo match permissions in chanInfoPtr. This function does
- * not check that.
- *
- * Important: Caller must be holding an shared or exclusive lock on
- * gConsoleMutex. That ensures the returned pointer stays valid on
- * return without risk of deallocation by other threads.
- *
- * Results:
- * Pointer to the found ConsoleHandleInfo or NULL if not found
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------
- */
-static ConsoleHandleInfo *
-FindConsoleInfo(const ConsoleChannelInfo *chanInfoPtr)
-{
- ConsoleHandleInfo *handleInfoPtr;
- for (handleInfoPtr = gConsoleHandleInfoList; handleInfoPtr; handleInfoPtr = handleInfoPtr->nextPtr) {
- if (handleInfoPtr->console == chanInfoPtr->handle) {
- return handleInfoPtr;
- }
- }
- return NULL;
-}
-
-/*
*----------------------------------------------------------------------
*
* TclWinOpenConsoleChannel --
@@ -2093,34 +1323,37 @@ FindConsoleInfo(const ConsoleChannelInfo *chanInfoPtr)
* Returns the new channel, or NULL.
*
* Side effects:
- * May open the channel.
+ * May open the channel
*
*----------------------------------------------------------------------
*/
+
Tcl_Channel
TclWinOpenConsoleChannel(
HANDLE handle,
char *channelName,
int permissions)
{
- ConsoleChannelInfo *chanInfoPtr;
- ConsoleHandleInfo *handleInfoPtr;
-
- /* A console handle can either be input or output, not both */
- if (permissions != TCL_READABLE && permissions != TCL_WRITABLE) {
- return NULL;
- }
+ char encoding[4 + TCL_INTEGER_SPACE];
+ ConsoleInfo *infoPtr;
+ DWORD id, modes;
ConsoleInit();
- chanInfoPtr = (ConsoleChannelInfo *)ckalloc(sizeof(*chanInfoPtr));
- memset(chanInfoPtr, 0, sizeof(*chanInfoPtr));
+ /*
+ * See if a channel with this handle already exists.
+ */
+
+ infoPtr = (ConsoleInfo *) ckalloc((unsigned) sizeof(ConsoleInfo));
+ memset(infoPtr, 0, sizeof(ConsoleInfo));
+
+ infoPtr->validMask = permissions;
+ infoPtr->handle = handle;
+ infoPtr->channel = (Tcl_Channel) NULL;
- chanInfoPtr->permissions = permissions;
- chanInfoPtr->handle = handle;
- chanInfoPtr->channel = (Tcl_Channel) NULL;
+ wsprintfA(encoding, "cp%d", GetConsoleCP());
- chanInfoPtr->threadId = Tcl_GetCurrentThread();
+ infoPtr->threadId = Tcl_GetCurrentThread();
/*
* Use the pointer for the name of the result channel. This keeps the
@@ -2128,7 +1361,10 @@ TclWinOpenConsoleChannel(
* for instance).
*/
- TclWinGenerateChannelName(channelName, "file", chanInfoPtr);
+ sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t)infoPtr);
+
+ infoPtr->channel = Tcl_CreateChannel(&consoleChannelType, channelName,
+ (ClientData) infoPtr, permissions);
if (permissions & TCL_READABLE) {
/*
@@ -2137,76 +1373,41 @@ TclWinOpenConsoleChannel(
* we only want to catch when complete lines are ready for reading.
*/
- chanInfoPtr->flags |= CONSOLE_READ_OPS;
- GetConsoleMode(handle, &chanInfoPtr->initMode);
-
-#ifdef OBSOLETE
- /* Why was priority being set on console input? Code smell */
- SetThreadPriority(infoPtr->reader.thread, THREAD_PRIORITY_HIGHEST);
-#endif
- } else {
- /* Already checked permissions is WRITABLE if not READABLE */
- /* TODO - enable ansi escape processing? */
+ GetConsoleMode(infoPtr->handle, &modes);
+ modes &= ~(ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
+ modes |= ENABLE_LINE_INPUT;
+ SetConsoleMode(infoPtr->handle, modes);
+
+ infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
+ infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL);
+ infoPtr->stopReader = CreateEvent(NULL, FALSE, FALSE, NULL);
+ infoPtr->readThread = CreateThread(NULL, 256, ConsoleReaderThread,
+ infoPtr, 0, &id);
+ SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
}
- /*
- * Global lock but that's ok. See comments top of file. Allocations
- * will happen only a few times in the life of a process and that too
- * generally at start up where only one thread is active.
- */
- AcquireSRWLockExclusive(&gConsoleLock); /*Allocate needs exclusive lock */
-
- handleInfoPtr = FindConsoleInfo(chanInfoPtr);
- if (handleInfoPtr == NULL) {
- /* Not found. Allocate one */
- handleInfoPtr = AllocateConsoleHandleInfo(handle, permissions);
- } else {
- /* Found. Its direction (read/write) better be the same */
- if (handleInfoPtr->permissions != permissions) {
- handleInfoPtr = NULL;
- }
+ if (permissions & TCL_WRITABLE) {
+ infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
+ infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
+ infoPtr->stopWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
+ infoPtr->writeThread = CreateThread(NULL, 256, ConsoleWriterThread,
+ infoPtr, 0, &id);
+ SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST);
}
- if (handleInfoPtr == NULL) {
- ReleaseSRWLockExclusive(&gConsoleLock);
- if (permissions == TCL_READABLE) {
- SetConsoleMode(handle, chanInfoPtr->initMode);
- }
- ckfree(chanInfoPtr);
- return NULL;
- }
-
- /*
- * There is effectively a reference to this structure from the Tcl
- * channel subsystem. So record that. This reference will be dropped
- * when the Tcl channel is closed.
- */
- chanInfoPtr->numRefs = 1;
-
- /*
- * Need to keep track of number of referencing channels for closing.
- * The pointer is safe since there is a reference held to it from
- * gConsoleHandleInfoList but still need to lock the structure itself
- */
- AcquireSRWLockExclusive(&handleInfoPtr->lock);
- handleInfoPtr->numRefs += 1;
- ReleaseSRWLockExclusive(&handleInfoPtr->lock);
-
- ReleaseSRWLockExclusive(&gConsoleLock);
-
- /* Note Tcl_CreateChannel never fails other than panic on error */
- chanInfoPtr->channel = Tcl_CreateChannel(&consoleChannelType, channelName,
- chanInfoPtr, permissions);
-
/*
- * Consoles have default translation of auto and ^Z eof char, which means
+ * Files have default translation of AUTO and ^Z eof char, which means
* that a ^Z will be accepted as EOF when reading.
*/
- Tcl_SetChannelOption(NULL, chanInfoPtr->channel, "-translation", "auto");
- Tcl_SetChannelOption(NULL, chanInfoPtr->channel, "-eofchar", "\x1A {}");
- Tcl_SetChannelOption(NULL, chanInfoPtr->channel, "-encoding", "utf-16");
- return chanInfoPtr->channel;
+ Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto");
+ Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}");
+ if (tclWinProcs->useWide)
+ Tcl_SetChannelOption(NULL, infoPtr->channel, "-encoding", "unicode");
+ else
+ Tcl_SetChannelOption(NULL, infoPtr->channel, "-encoding", encoding);
+
+ return infoPtr->channel;
}
/*
@@ -2227,221 +1428,35 @@ TclWinOpenConsoleChannel(
static void
ConsoleThreadActionProc(
- void *instanceData,
+ ClientData instanceData,
int action)
{
- ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
-
- /* No need for any locks as no other thread will be writing to it */
- if (action == TCL_CHANNEL_THREAD_INSERT) {
- ConsoleInit(); /* Needed to set up event source handlers for this thread */
- chanInfoPtr->threadId = Tcl_GetCurrentThread();
- } else {
- chanInfoPtr->threadId = NULL;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ConsoleSetOptionProc --
- *
- * Sets an option on a channel.
- *
- * Results:
- * A standard Tcl result. Also sets the interp's result on error if
- * interp is not NULL.
- *
- * Side effects:
- * May modify an option on a console. Sets Error message if needed (by
- * calling Tcl_BadChannelOption).
- *
- *----------------------------------------------------------------------
- */
-static int
-ConsoleSetOptionProc(
- void *instanceData, /* File state. */
- Tcl_Interp *interp, /* For error reporting - can be NULL. */
- const char *optionName, /* Which option to set? */
- const char *value) /* New value for option. */
-{
- ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
- int len = strlen(optionName);
- int vlen = strlen(value);
-
- /*
- * Option -inputmode normal|password|raw
- */
-
- if ((chanInfoPtr->flags & CONSOLE_READ_OPS) && (len > 1) &&
- (strncmp(optionName, "-inputmode", len) == 0)) {
- DWORD mode;
-
- if (GetConsoleMode(chanInfoPtr->handle, &mode) == 0) {
- Tcl_WinConvertError(GetLastError());
- if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't read console mode: %s",
- Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
- }
- if (strncasecmp(value, "NORMAL", vlen) == 0) {
- mode |=
- ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
- } else if (strncasecmp(value, "PASSWORD", vlen) == 0) {
- mode |= ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT;
- mode &= ~ENABLE_ECHO_INPUT;
- } else if (strncasecmp(value, "RAW", vlen) == 0) {
- mode &= ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
- } else if (strncasecmp(value, "RESET", vlen) == 0) {
- /*
- * Reset to the initial mode, whatever that is.
- */
- mode = chanInfoPtr->initMode;
- } 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", (char *)NULL);
- }
- return TCL_ERROR;
- }
- if (SetConsoleMode(chanInfoPtr->handle, mode) == 0) {
- Tcl_WinConvertError(GetLastError());
- if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't set console mode: %s",
- Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
- }
-
- return TCL_OK;
- }
-
- if (chanInfoPtr->flags & CONSOLE_READ_OPS) {
- return Tcl_BadChannelOption(interp, optionName, "inputmode");
- } else {
- return Tcl_BadChannelOption(interp, optionName, "");
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ConsoleGetOptionProc --
- *
- * Gets a mode associated with an IO channel. If the optionName arg is
- * non-NULL, retrieves the value of that option. If the optionName arg is
- * NULL, retrieves a list of alternating option names and values for the
- * given channel.
- *
- * Results:
- * A standard Tcl result. Also sets the supplied DString to the string
- * value of the option(s) returned. Sets error message if needed
- * (by calling Tcl_BadChannelOption).
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ConsoleGetOptionProc(
- void *instanceData, /* File state. */
- Tcl_Interp *interp, /* For error reporting - can be NULL. */
- const char *optionName, /* Option to get. */
- Tcl_DString *dsPtr) /* Where to store value(s). */
-{
- ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
- int valid = 0; /* Flag if valid option parsed. */
- unsigned int len;
- char buf[TCL_INTEGER_SPACE];
-
- if (optionName == NULL) {
- len = 0;
- } else {
- len = strlen(optionName);
- }
+ ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData;
- /*
- * Get option -inputmode
- *
- * This is a great simplification of the underlying reality, but actually
- * represents what almost all scripts really want to know.
+ /* We do not access firstConsolePtr in the thread structures. This is not
+ * for all serials managed by the thread, but only those we are watching.
+ * Removal of the filevent handlers before transfer thus takes care of
+ * this structure.
*/
- if (chanInfoPtr->flags & CONSOLE_READ_OPS) {
- if (len == 0) {
- Tcl_DStringAppendElement(dsPtr, "-inputmode");
- }
- if (len==0 || (len>1 && strncmp(optionName, "-inputmode", len)==0)) {
- DWORD mode;
-
- valid = 1;
- if (GetConsoleMode(chanInfoPtr->handle, &mode) == 0) {
- Tcl_WinConvertError(GetLastError());
- if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't read console mode: %s",
- Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
- }
- if (mode & ENABLE_LINE_INPUT) {
- if (mode & ENABLE_ECHO_INPUT) {
- Tcl_DStringAppendElement(dsPtr, "normal");
- } else {
- Tcl_DStringAppendElement(dsPtr, "password");
- }
- } else {
- Tcl_DStringAppendElement(dsPtr, "raw");
- }
- }
- } else {
+ Tcl_MutexLock(&consoleMutex);
+ if (action == TCL_CHANNEL_THREAD_INSERT) {
/*
- * Output channel. Get option -winsize
- * Option is readonly and returned by [fconfigure chan -winsize] but not
- * returned by [fconfigure chan] without explicit option name.
+ * We can't copy the thread information from the channel when the
+ * channel is created. At this time the channel back pointer has not
+ * been set yet. However in that case the threadId has already been
+ * set by TclpCreateCommandChannel itself, so the structure is still
+ * good.
*/
- if (len == 0) {
- Tcl_DStringAppendElement(dsPtr, "-winsize");
- }
- if (len == 0 || (len > 1 && strncmp(optionName, "-winsize", len) == 0)) {
- CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
-
- valid = 1;
- if (!GetConsoleScreenBufferInfo(chanInfoPtr->handle,
- &consoleInfo)) {
- Tcl_WinConvertError(GetLastError());
- if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't read console size: %s",
- Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
- }
- Tcl_DStringStartSublist(dsPtr);
- snprintf(buf, sizeof(buf), "%d",
- consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1);
- Tcl_DStringAppendElement(dsPtr, buf);
- snprintf(buf, sizeof(buf), "%d",
- consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1);
- Tcl_DStringAppendElement(dsPtr, buf);
- Tcl_DStringEndSublist(dsPtr);
+ ConsoleInit();
+ if (infoPtr->channel != NULL) {
+ infoPtr->threadId = Tcl_GetChannelThread(infoPtr->channel);
}
- }
-
- if (valid) {
- return TCL_OK;
- }
- if (chanInfoPtr->flags & CONSOLE_READ_OPS) {
- return Tcl_BadChannelOption(interp, optionName, "inputmode");
} else {
- return Tcl_BadChannelOption(interp, optionName, "winsize");
+ infoPtr->threadId = NULL;
}
+ Tcl_MutexUnlock(&consoleMutex);
}
/*
diff --git a/win/tclWinDde.c b/win/tclWinDde.c
index d883bac..eef5caa 100644
--- a/win/tclWinDde.c
+++ b/win/tclWinDde.c
@@ -10,20 +10,20 @@
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#undef STATIC_BUILD
-#ifndef USE_TCL_STUBS
-# define USE_TCL_STUBS
-#endif
#include "tclInt.h"
+#include "tclPort.h"
#include <dde.h>
#include <ddeml.h>
-#include <tchar.h>
-#if !defined(NDEBUG)
- /* test POKE server Implemented for debug mode only */
-# undef CBF_FAIL_POKES
-# define CBF_FAIL_POKES 0
-#endif
+/*
+ * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the Dde_Init
+ * declaration is in the source file itself, which is only accessed when we
+ * are building a library. DO NOT MOVE BEFORE ANY #include LINES. ONLY USE
+ * EXTERN TO INDICATE EXPORTED FUNCTIONS FROM NOW ON.
+ */
+
+#undef TCL_STORAGE_CLASS
+#define TCL_STORAGE_CLASS DLLEXPORT
/*
* The following structure is used to keep track of the interpreters
@@ -34,7 +34,7 @@ typedef struct RegisteredInterp {
struct RegisteredInterp *nextPtr;
/* The next interp this application knows
* about. */
- WCHAR *name; /* Interpreter's name (malloc-ed). */
+ char *name; /* Interpreter's name (malloc-ed). */
Tcl_Obj *handlerPtr; /* The server handler command */
Tcl_Interp *interp; /* The interpreter attached to this name. */
} RegisteredInterp;
@@ -51,7 +51,7 @@ typedef struct Conversation {
Tcl_Obj *returnPackagePtr; /* The result package for this conversation. */
} Conversation;
-typedef struct {
+typedef struct DdeEnumServices {
Tcl_Interp *interp;
int result;
ATOM service;
@@ -59,7 +59,7 @@ typedef struct {
HWND hwnd;
} DdeEnumServices;
-typedef struct {
+typedef struct ThreadSpecificData {
Conversation *currentConversations;
/* A list of conversations currently being
* processed. */
@@ -79,10 +79,9 @@ static DWORD ddeInstance; /* The application instance handle given to us
* by DdeInitialize. */
static int ddeIsServer = 0;
-#define TCL_DDE_VERSION "1.4.5"
#define TCL_DDE_PACKAGE_NAME "dde"
-#define TCL_DDE_SERVICE_NAME L"TclEval"
-#define TCL_DDE_EXECUTE_RESULT L"$TCLEVAL$EXECUTE$RESULT"
+#define TCL_DDE_SERVICE_NAME "TclEval"
+#define TCL_DDE_EXECUTE_RESULT "$TCLEVAL$EXECUTE$RESULT"
#define DDE_FLAG_ASYNC 1
#define DDE_FLAG_BINARY 2
@@ -90,62 +89,35 @@ static int ddeIsServer = 0;
TCL_DECLARE_MUTEX(ddeMutex)
-#if (TCL_MAJOR_VERSION < 9) && defined(TCL_MINOR_VERSION) && (TCL_MINOR_VERSION < 7)
-# if TCL_UTF_MAX > 3
-# define Tcl_WCharToUtfDString(a,b,c) Tcl_WinTCharToUtf((TCHAR *)(a),(b)*sizeof(WCHAR),c)
-# define Tcl_UtfToWCharDString(a,b,c) (WCHAR *)Tcl_WinUtfToTChar(a,b,c)
-# else
-# define Tcl_WCharToUtfDString Tcl_UniCharToUtfDString
-# define Tcl_UtfToWCharDString Tcl_UtfToUniCharDString
-# endif
-#ifndef Tcl_Size
-# define Tcl_Size int
-#endif
-#ifndef Tcl_CreateObjCommand2
-# define Tcl_CreateObjCommand2 Tcl_CreateObjCommand
-#endif
-#endif
-
/*
- * Declarations for functions defined in this file.
+ * Forward declarations for functions defined later in this file.
*/
static LRESULT CALLBACK DdeClientWindowProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam);
-static int DdeCreateClient(DdeEnumServices *es);
+static int DdeCreateClient(struct DdeEnumServices *es);
static BOOL CALLBACK DdeEnumWindowsCallback(HWND hwndTarget,
LPARAM lParam);
-static void DdeExitProc(void *clientData);
+static void DdeExitProc(ClientData clientData);
static int DdeGetServicesList(Tcl_Interp *interp,
- const WCHAR *serviceName, const WCHAR *topicName);
+ const char *serviceName, const char *topicName);
static HDDEDATA CALLBACK DdeServerProc(UINT uType, UINT uFmt, HCONV hConv,
HSZ ddeTopic, HSZ ddeItem, HDDEDATA hData,
DWORD dwData1, DWORD dwData2);
static LRESULT DdeServicesOnAck(HWND hwnd, WPARAM wParam,
LPARAM lParam);
-static void DeleteProc(void *clientData);
+static void DeleteProc(ClientData clientData);
static Tcl_Obj * ExecuteRemoteObject(RegisteredInterp *riPtr,
Tcl_Obj *ddeObjectPtr);
static int MakeDdeConnection(Tcl_Interp *interp,
- const WCHAR *name, HCONV *ddeConvPtr);
+ const char *name, HCONV *ddeConvPtr);
static void SetDdeError(Tcl_Interp *interp);
-static int DdeObjCmd(void *clientData,
- Tcl_Interp *interp, Tcl_Size objc,
+static int DdeObjCmd(ClientData clientData,
+ Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
-#ifdef __cplusplus
-extern "C" {
-#endif
-DLLEXPORT int Dde_Init(Tcl_Interp *interp);
-DLLEXPORT int Dde_SafeInit(Tcl_Interp *interp);
-#if TCL_MAJOR_VERSION < 9
-/* With those additional entries, "load tcldde14.dll" works without 3th argument */
-DLLEXPORT int Tcldde_Init(Tcl_Interp *interp);
-DLLEXPORT int Tcldde_SafeInit(Tcl_Interp *interp);
-#endif
-#ifdef __cplusplus
-}
-#endif
+EXTERN int Dde_Init(Tcl_Interp *interp);
+EXTERN int Dde_SafeInit(Tcl_Interp *interp);
/*
*----------------------------------------------------------------------
@@ -167,22 +139,14 @@ int
Dde_Init(
Tcl_Interp *interp)
{
- if (!Tcl_InitStubs(interp, "8.5-", 0)) {
+ if (!Tcl_InitStubs(interp, "8.1", 0)) {
return TCL_ERROR;
}
- Tcl_CreateObjCommand2(interp, "dde", DdeObjCmd, NULL, NULL);
+ Tcl_CreateObjCommand(interp, "dde", DdeObjCmd, NULL, NULL);
Tcl_CreateExitHandler(DdeExitProc, NULL);
- return Tcl_PkgProvideEx(interp, TCL_DDE_PACKAGE_NAME, TCL_DDE_VERSION, NULL);
+ return Tcl_PkgProvide(interp, TCL_DDE_PACKAGE_NAME, "1.3.3");
}
-#if TCL_MAJOR_VERSION < 9
-int
-Tcldde_Init(
- Tcl_Interp *interp)
-{
- return Dde_Init(interp);
-}
-#endif
/*
*----------------------------------------------------------------------
@@ -210,14 +174,6 @@ Dde_SafeInit(
}
return result;
}
-#if TCL_MAJOR_VERSION < 9
-int
-Tcldde_SafeInit(
- Tcl_Interp *interp)
-{
- return Dde_SafeInit(interp);
-}
-#endif
/*
*----------------------------------------------------------------------
@@ -259,7 +215,7 @@ Initialize(void)
if (ddeInstance == 0) {
Tcl_MutexLock(&ddeMutex);
if (ddeInstance == 0) {
- if (DdeInitializeW(&ddeInstance, (PFNCALLBACK)(void *)DdeServerProc,
+ if (DdeInitialize(&ddeInstance, (PFNCALLBACK) DdeServerProc,
CBF_SKIP_REGISTRATIONS | CBF_SKIP_UNREGISTRATIONS
| CBF_FAIL_POKES, 0) != DMLERR_NO_ERROR) {
ddeInstance = 0;
@@ -272,8 +228,8 @@ Initialize(void)
if ((ddeServiceGlobal == 0) && (nameFound != 0)) {
ddeIsServer = 1;
Tcl_CreateExitHandler(DdeExitProc, NULL);
- ddeServiceGlobal = DdeCreateStringHandleW(ddeInstance,
- TCL_DDE_SERVICE_NAME, CP_WINUNICODE);
+ ddeServiceGlobal = DdeCreateStringHandle(ddeInstance,
+ TCL_DDE_SERVICE_NAME, 0);
DdeNameService(ddeInstance, ddeServiceGlobal, 0L, DNS_REGISTER);
} else {
ddeIsServer = 0;
@@ -307,23 +263,22 @@ Initialize(void)
*----------------------------------------------------------------------
*/
-static const WCHAR *
+static const char *
DdeSetServerName(
Tcl_Interp *interp,
- const WCHAR *name, /* The name that will be used to refer to the
+ const char *name, /* The name that will be used to refer to the
* interpreter in later "send" commands. Must
* be globally unique. */
int flags, /* DDE_FLAG_FORCE or 0 */
Tcl_Obj *handlerPtr) /* Name of the optional proc/command to handle
* incoming Dde eval's */
{
- int suffix;
+ int suffix, offset;
RegisteredInterp *riPtr, *prevPtr;
Tcl_DString dString;
- const WCHAR *actualName;
+ const char *actualName;
Tcl_Obj *srvListPtr = NULL, **srvPtrPtr = NULL;
- Tcl_Size n, srvCount = 0, offset;
- int lastSuffix, r = TCL_OK;
+ int n, srvCount = 0, lastSuffix, r = TCL_OK;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
@@ -359,7 +314,7 @@ DdeSetServerName(
* current interp, but it doesn't have a name.
*/
- return L"";
+ return "";
}
/*
@@ -380,9 +335,7 @@ DdeSetServerName(
&srvPtrPtr);
}
if (r != TCL_OK) {
- Tcl_DStringInit(&dString);
- OutputDebugStringW(Tcl_UtfToWCharDString(Tcl_GetString(Tcl_GetObjResult(interp)), -1, &dString));
- Tcl_DStringFree(&dString);
+ OutputDebugString(Tcl_GetStringResult(interp));
return NULL;
}
@@ -399,14 +352,13 @@ DdeSetServerName(
lastSuffix = suffix;
if (suffix > 1) {
if (suffix == 2) {
- Tcl_DStringAppend(&dString, (char *)name, wcslen(name) * sizeof(WCHAR));
- Tcl_DStringAppend(&dString, (char *)L" #", 2 * sizeof(WCHAR));
+ Tcl_DStringAppend(&dString, name, -1);
+ Tcl_DStringAppend(&dString, " #", 2);
offset = Tcl_DStringLength(&dString);
- Tcl_DStringSetLength(&dString, offset + sizeof(WCHAR) * TCL_INTEGER_SPACE);
- actualName = (WCHAR *) Tcl_DStringValue(&dString);
+ Tcl_DStringSetLength(&dString, offset + TCL_INTEGER_SPACE);
+ actualName = Tcl_DStringValue(&dString);
}
- _snwprintf((WCHAR *) (Tcl_DStringValue(&dString) + offset),
- TCL_INTEGER_SPACE, L"%d", suffix);
+ sprintf(Tcl_DStringValue(&dString) + offset, "%d", suffix);
}
/*
@@ -415,42 +367,39 @@ DdeSetServerName(
for (n = 0; n < srvCount; ++n) {
Tcl_Obj* namePtr;
- Tcl_DString ds;
Tcl_ListObjIndex(interp, srvPtrPtr[n], 1, &namePtr);
- Tcl_DStringInit(&ds);
- Tcl_UtfToWCharDString(Tcl_GetString(namePtr), -1, &ds);
- if (wcscmp(actualName, (WCHAR *)Tcl_DStringValue(&ds)) == 0) {
+ if (strcmp(actualName, Tcl_GetString(namePtr)) == 0) {
suffix++;
- Tcl_DStringFree(&ds);
break;
}
- Tcl_DStringFree(&ds);
}
}
+ Tcl_DStringSetLength(&dString,
+ offset + (int)strlen(Tcl_DStringValue(&dString)+offset));
}
/*
* We have found a unique name. Now add it to the registry.
*/
- riPtr = (RegisteredInterp *) Tcl_Alloc(sizeof(RegisteredInterp));
+ riPtr = (RegisteredInterp *) ckalloc(sizeof(RegisteredInterp));
riPtr->interp = interp;
- riPtr->name = (WCHAR *) Tcl_Alloc((wcslen(actualName) + 1) * sizeof(WCHAR));
+ riPtr->name = ckalloc((unsigned int) strlen(actualName) + 1);
riPtr->nextPtr = tsdPtr->interpListPtr;
riPtr->handlerPtr = handlerPtr;
if (riPtr->handlerPtr != NULL) {
Tcl_IncrRefCount(riPtr->handlerPtr);
}
tsdPtr->interpListPtr = riPtr;
- wcscpy(riPtr->name, actualName);
+ strcpy(riPtr->name, actualName);
if (Tcl_IsSafe(interp)) {
Tcl_ExposeCommand(interp, "dde", "dde");
}
- Tcl_CreateObjCommand2(interp, "dde", DdeObjCmd,
- riPtr, DeleteProc);
+ Tcl_CreateObjCommand(interp, "dde", DdeObjCmd,
+ (ClientData) riPtr, DeleteProc);
if (Tcl_IsSafe(interp)) {
Tcl_HideCommand(interp, "dde", "dde");
}
@@ -515,7 +464,8 @@ DdeGetRegistrationPtr(
static void
DeleteProc(
- void *clientData) /* The interp we are deleting. */
+ ClientData clientData) /* The interp we are deleting passed as
+ * ClientData. */
{
RegisteredInterp *riPtr = (RegisteredInterp *) clientData;
RegisteredInterp *searchPtr, *prevPtr;
@@ -536,7 +486,7 @@ DeleteProc(
prevPtr->nextPtr = searchPtr->nextPtr;
}
}
- Tcl_Free((char *) riPtr->name);
+ ckfree(riPtr->name);
if (riPtr->handlerPtr) {
Tcl_DecrRefCount(riPtr->handlerPtr);
}
@@ -574,11 +524,10 @@ ExecuteRemoteObject(
Tcl_Obj *returnPackagePtr;
int result = TCL_OK;
- if ((riPtr->handlerPtr == NULL) && Tcl_IsSafe(riPtr->interp)) {
+ if (riPtr->handlerPtr == NULL && Tcl_IsSafe(riPtr->interp)) {
Tcl_SetObjResult(riPtr->interp, Tcl_NewStringObj("permission denied: "
"a handler procedure must be defined for use in a safe "
"interp", -1));
- Tcl_SetErrorCode(riPtr->interp, "TCL", "DDE", "SECURITY_CHECK", (void *)NULL);
result = TCL_ERROR;
}
@@ -652,20 +601,18 @@ DdeServerProc(
HSZ ddeTopic, HSZ ddeItem, /* String handles. Transaction-type
* dependent. */
HDDEDATA hData, /* DDE data. Transaction-type dependent. */
- DWORD unused1, DWORD unused2)
+ DWORD dwData1, DWORD dwData2)
/* Transaction-dependent data. */
{
Tcl_DString dString;
- Tcl_Size len;
+ int len;
DWORD dlen;
- WCHAR *utilString;
+ char *utilString;
Tcl_Obj *ddeObjectPtr;
HDDEDATA ddeReturn = NULL;
RegisteredInterp *riPtr;
Conversation *convPtr, *prevConvPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- (void)unused1;
- (void)unused2;
switch(uType) {
case XTYP_CONNECT:
@@ -674,16 +621,16 @@ DdeServerProc(
* sure we have a valid topic.
*/
- len = DdeQueryStringW(ddeInstance, ddeTopic, NULL, 0, CP_WINUNICODE);
+ len = DdeQueryString(ddeInstance, ddeTopic, NULL, 0, 0);
Tcl_DStringInit(&dString);
- Tcl_DStringSetLength(&dString, (len + 1) * sizeof(WCHAR) - 1);
- utilString = (WCHAR *) Tcl_DStringValue(&dString);
- DdeQueryStringW(ddeInstance, ddeTopic, utilString, (DWORD) len + 1,
- CP_WINUNICODE);
+ Tcl_DStringSetLength(&dString, len);
+ utilString = Tcl_DStringValue(&dString);
+ DdeQueryString(ddeInstance, ddeTopic, utilString, (DWORD) len + 1,
+ CP_WINANSI);
for (riPtr = tsdPtr->interpListPtr; riPtr != NULL;
riPtr = riPtr->nextPtr) {
- if (_wcsicmp(utilString, riPtr->name) == 0) {
+ if (stricmp(utilString, riPtr->name) == 0) {
Tcl_DStringFree(&dString);
return (HDDEDATA) TRUE;
}
@@ -699,16 +646,16 @@ DdeServerProc(
* result to return in an XTYP_REQUEST.
*/
- len = DdeQueryStringW(ddeInstance, ddeTopic, NULL, 0, CP_WINUNICODE);
+ len = DdeQueryString(ddeInstance, ddeTopic, NULL, 0, 0);
Tcl_DStringInit(&dString);
- Tcl_DStringSetLength(&dString, (len + 1) * sizeof(WCHAR) - 1);
- utilString = (WCHAR *) Tcl_DStringValue(&dString);
- DdeQueryStringW(ddeInstance, ddeTopic, utilString, (DWORD) len + 1,
- CP_WINUNICODE);
+ Tcl_DStringSetLength(&dString, len);
+ utilString = Tcl_DStringValue(&dString);
+ DdeQueryString(ddeInstance, ddeTopic, utilString, (DWORD) len + 1,
+ CP_WINANSI);
for (riPtr = tsdPtr->interpListPtr; riPtr != NULL;
riPtr = riPtr->nextPtr) {
- if (_wcsicmp(riPtr->name, utilString) == 0) {
- convPtr = (Conversation *) Tcl_Alloc(sizeof(Conversation));
+ if (stricmp(riPtr->name, utilString) == 0) {
+ convPtr = (Conversation *) ckalloc(sizeof(Conversation));
convPtr->nextPtr = tsdPtr->currentConversations;
convPtr->returnPackagePtr = NULL;
convPtr->hConv = hConv;
@@ -738,7 +685,7 @@ DdeServerProc(
if (convPtr->returnPackagePtr != NULL) {
Tcl_DecrRefCount(convPtr->returnPackagePtr);
}
- Tcl_Free((char *) convPtr);
+ ckfree((char *) convPtr);
break;
}
}
@@ -764,24 +711,22 @@ DdeServerProc(
}
if (convPtr != NULL) {
- Tcl_DString dsBuf;
char *returnString;
- len = DdeQueryStringW(ddeInstance, ddeItem, NULL, 0, CP_WINUNICODE);
+ len = DdeQueryString(ddeInstance, ddeItem, NULL, 0, CP_WINANSI);
Tcl_DStringInit(&dString);
- Tcl_DStringInit(&dsBuf);
- Tcl_DStringSetLength(&dString, (len + 1) * sizeof(WCHAR) - 1);
- utilString = (WCHAR *) Tcl_DStringValue(&dString);
- DdeQueryStringW(ddeInstance, ddeItem, utilString, (DWORD) len + 1,
- CP_WINUNICODE);
- if (_wcsicmp(utilString, TCL_DDE_EXECUTE_RESULT) == 0) {
- returnString =
- Tcl_GetStringFromObj(convPtr->returnPackagePtr, &len);
- if (uFmt != CF_TEXT) {
- Tcl_DStringInit(&dsBuf);
- Tcl_UtfToWCharDString(returnString, len, &dsBuf);
- returnString = Tcl_DStringValue(&dsBuf);
- len = Tcl_DStringLength(&dsBuf) + sizeof(WCHAR) - 1;
+ Tcl_DStringSetLength(&dString, len);
+ utilString = Tcl_DStringValue(&dString);
+ DdeQueryString(ddeInstance, ddeItem, utilString, (DWORD) len + 1,
+ CP_WINANSI);
+ if (stricmp(utilString, TCL_DDE_EXECUTE_RESULT) == 0) {
+ if (uFmt == CF_TEXT) {
+ returnString =
+ Tcl_GetStringFromObj(convPtr->returnPackagePtr, &len);
+ } else {
+ returnString = (char *)
+ Tcl_GetUnicodeFromObj(convPtr->returnPackagePtr, &len);
+ len = 2 * len + 1;
}
ddeReturn = DdeCreateDataHandle(ddeInstance, (BYTE *)returnString,
(DWORD) len+1, 0, ddeItem, uFmt, 0);
@@ -789,21 +734,17 @@ DdeServerProc(
if (Tcl_IsSafe(convPtr->riPtr->interp)) {
ddeReturn = NULL;
} else {
- Tcl_DString ds;
- Tcl_Obj *variableObjPtr;
-
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString(utilString, wcslen(utilString), &ds);
- variableObjPtr = Tcl_GetVar2Ex(
- convPtr->riPtr->interp, Tcl_DStringValue(&ds), NULL,
+ Tcl_Obj *variableObjPtr = Tcl_GetVar2Ex(
+ convPtr->riPtr->interp, utilString, NULL,
TCL_GLOBAL_ONLY);
if (variableObjPtr != NULL) {
- returnString = Tcl_GetStringFromObj(variableObjPtr, &len);
- if (uFmt != CF_TEXT) {
- Tcl_DStringInit(&dsBuf);
- Tcl_UtfToWCharDString(returnString, len, &dsBuf);
- returnString = Tcl_DStringValue(&dsBuf);
- len = Tcl_DStringLength(&dsBuf) + sizeof(WCHAR) - 1;
+ if (uFmt == CF_TEXT) {
+ returnString = Tcl_GetStringFromObj(
+ variableObjPtr, &len);
+ } else {
+ returnString = (char *) Tcl_GetUnicodeFromObj(
+ variableObjPtr, &len);
+ len = 2 * len + 1;
}
ddeReturn = DdeCreateDataHandle(ddeInstance,
(BYTE *)returnString, (DWORD) len+1, 0, ddeItem,
@@ -811,75 +752,20 @@ DdeServerProc(
} else {
ddeReturn = NULL;
}
- Tcl_DStringFree(&ds);
}
}
- Tcl_DStringFree(&dsBuf);
Tcl_DStringFree(&dString);
}
return ddeReturn;
-#if !CBF_FAIL_POKES
- case XTYP_POKE:
- /*
- * This is a poke for a Tcl variable, only implemented in
- * debug/UNICODE mode.
- */
- ddeReturn = DDE_FNOTPROCESSED;
-
- if ((uFmt != CF_TEXT) && (uFmt != CF_UNICODETEXT)) {
- return ddeReturn;
- }
-
- for (convPtr = tsdPtr->currentConversations; (convPtr != NULL)
- && (convPtr->hConv != hConv); convPtr = convPtr->nextPtr) {
- /*
- * Empty loop body.
- */
- }
-
- if (convPtr && !Tcl_IsSafe(convPtr->riPtr->interp)) {
- Tcl_DString ds, ds2;
- Tcl_Obj *variableObjPtr;
- DWORD len2;
-
- Tcl_DStringInit(&dString);
- Tcl_DStringInit(&ds2);
- len = DdeQueryStringW(ddeInstance, ddeItem, NULL, 0, CP_WINUNICODE);
- Tcl_DStringSetLength(&dString, (len + 1) * sizeof(WCHAR) - 1);
- utilString = (WCHAR *) Tcl_DStringValue(&dString);
- DdeQueryStringW(ddeInstance, ddeItem, utilString, (DWORD) len + 1,
- CP_WINUNICODE);
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString(utilString, wcslen(utilString), &ds);
- utilString = (WCHAR *) DdeAccessData(hData, &len2);
- len = len2;
- if (uFmt != CF_TEXT) {
- Tcl_DStringInit(&ds2);
- Tcl_WCharToUtfDString(utilString, wcslen(utilString), &ds2);
- utilString = (WCHAR *) Tcl_DStringValue(&ds2);
- }
- variableObjPtr = Tcl_NewStringObj((char *)utilString, -1);
-
- Tcl_SetVar2Ex(convPtr->riPtr->interp, Tcl_DStringValue(&ds), NULL,
- variableObjPtr, TCL_GLOBAL_ONLY);
-
- Tcl_DStringFree(&ds2);
- Tcl_DStringFree(&ds);
- Tcl_DStringFree(&dString);
- ddeReturn = (HDDEDATA) DDE_FACK;
- }
- return ddeReturn;
-
-#endif
case XTYP_EXECUTE: {
/*
* Execute this script. The results will be saved into a list object
- * which will be retrieved later. See ExecuteRemoteObject.
+ * which will be retreived later. See ExecuteRemoteObject.
*/
Tcl_Obj *returnPackagePtr;
- char *string;
+ Tcl_UniChar *uniStr;
for (convPtr = tsdPtr->currentConversations; (convPtr != NULL)
&& (convPtr->hConv != hConv); convPtr = convPtr->nextPtr) {
@@ -892,26 +778,21 @@ DdeServerProc(
return (HDDEDATA) DDE_FNOTPROCESSED;
}
- utilString = (WCHAR *) DdeAccessData(hData, &dlen);
- string = (char *) utilString;
+ utilString = (char *) DdeAccessData(hData, &dlen);
+ uniStr = (Tcl_UniChar *) utilString;
if (!dlen) {
/* Empty binary array. */
ddeObjectPtr = Tcl_NewObj();
- } else if ((dlen & 1) || utilString[(dlen>>1)-1]) {
- /* Cannot be Unicode, so assume utf-8 */
- if (!string[dlen-1]) {
+ } else if ((dlen & 1) || uniStr[(dlen>>1)-1]) {
+ /* Cannot be unicode, so assume utf-8 */
+ if (!utilString[dlen-1]) {
dlen--;
}
- ddeObjectPtr = Tcl_NewStringObj(string, dlen);
+ ddeObjectPtr = Tcl_NewStringObj(utilString, dlen);
} else {
- /* Unicode */
- Tcl_DString dsBuf;
-
- Tcl_DStringInit(&dsBuf);
- Tcl_WCharToUtfDString(utilString, (dlen>>1) - 1, &dsBuf);
- ddeObjectPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsBuf),
- Tcl_DStringLength(&dsBuf));
- Tcl_DStringFree(&dsBuf);
+ /* unicode */
+ dlen >>= 1;
+ ddeObjectPtr = Tcl_NewUnicodeObj(uniStr, dlen - 1);
}
Tcl_IncrRefCount(ddeObjectPtr);
DdeUnaccessData(hData);
@@ -946,8 +827,8 @@ DdeServerProc(
*/
HSZPAIR *returnPtr;
- Tcl_Size i;
- DWORD numItems;
+ int i;
+ int numItems;
for (i = 0, riPtr = tsdPtr->interpListPtr; riPtr != NULL;
i++, riPtr = riPtr->nextPtr) {
@@ -956,20 +837,17 @@ DdeServerProc(
*/
}
- if ((size_t)i >= UINT_MAX/sizeof(HSZPAIR)) {
- return NULL;
- }
- numItems = (DWORD)i;
+ numItems = i;
ddeReturn = DdeCreateDataHandle(ddeInstance, NULL,
- (numItems + 1) * (DWORD)sizeof(HSZPAIR), 0, 0, 0, 0);
+ (numItems + 1) * sizeof(HSZPAIR), 0, 0, 0, 0);
returnPtr = (HSZPAIR *) DdeAccessData(ddeReturn, &dlen);
len = dlen;
- for (i = 0, riPtr = tsdPtr->interpListPtr; i < (Tcl_Size)numItems;
+ for (i = 0, riPtr = tsdPtr->interpListPtr; i < numItems;
i++, riPtr = riPtr->nextPtr) {
- returnPtr[i].hszSvc = DdeCreateStringHandleW(ddeInstance,
- TCL_DDE_SERVICE_NAME, CP_WINUNICODE);
- returnPtr[i].hszTopic = DdeCreateStringHandleW(ddeInstance,
- riPtr->name, CP_WINUNICODE);
+ returnPtr[i].hszSvc = DdeCreateStringHandle(ddeInstance,
+ TCL_DDE_SERVICE_NAME, CP_WINANSI);
+ returnPtr[i].hszTopic = DdeCreateStringHandle(ddeInstance,
+ riPtr->name, CP_WINANSI);
}
returnPtr[i].hszSvc = NULL;
returnPtr[i].hszTopic = NULL;
@@ -1000,9 +878,8 @@ DdeServerProc(
static void
DdeExitProc(
- void *dummy) /* Not used. */
+ ClientData clientData) /* Not used in this handler. */
{
- (void)dummy;
DdeNameService(ddeInstance, NULL, 0, DNS_UNREGISTER);
DdeUninitialize(ddeInstance);
ddeInstance = 0;
@@ -1028,14 +905,14 @@ DdeExitProc(
static int
MakeDdeConnection(
Tcl_Interp *interp, /* Used to report errors. */
- const WCHAR *name, /* The connection to use. */
+ const char *name, /* The connection to use. */
HCONV *ddeConvPtr)
{
HSZ ddeTopic, ddeService;
HCONV ddeConv;
- ddeService = DdeCreateStringHandleW(ddeInstance, TCL_DDE_SERVICE_NAME, CP_WINUNICODE);
- ddeTopic = DdeCreateStringHandleW(ddeInstance, name, CP_WINUNICODE);
+ ddeService = DdeCreateStringHandle(ddeInstance, TCL_DDE_SERVICE_NAME, 0);
+ ddeTopic = DdeCreateStringHandle(ddeInstance, name, 0);
ddeConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);
DdeFreeStringHandle(ddeInstance, ddeService);
@@ -1043,14 +920,8 @@ MakeDdeConnection(
if (ddeConv == (HCONV) NULL) {
if (interp != NULL) {
- Tcl_DString dString;
-
- Tcl_DStringInit(&dString);
- Tcl_WCharToUtfDString(name, wcslen(name), &dString);
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "no registered server named \"%s\"", Tcl_DStringValue(&dString)));
- Tcl_DStringFree(&dString);
- Tcl_SetErrorCode(interp, "TCL", "DDE", "NO_SERVER", (void *)NULL);
+ Tcl_AppendResult(interp, "no registered server named \"",
+ name, "\"", NULL);
}
return TCL_ERROR;
}
@@ -1081,24 +952,24 @@ MakeDdeConnection(
static int
DdeCreateClient(
- DdeEnumServices *es)
+ struct DdeEnumServices *es)
{
- WNDCLASSEXW wc;
- static const WCHAR *szDdeClientClassName = L"TclEval client class";
- static const WCHAR *szDdeClientWindowName = L"TclEval client window";
+ WNDCLASSEX wc;
+ static const char *szDdeClientClassName = "TclEval client class";
+ static const char *szDdeClientWindowName = "TclEval client window";
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = DdeClientWindowProc;
wc.lpszClassName = szDdeClientClassName;
- wc.cbWndExtra = sizeof(DdeEnumServices *);
+ wc.cbWndExtra = sizeof(struct DdeEnumServices *);
/*
* Register and create the callback window.
*/
- RegisterClassExW(&wc);
- es->hwnd = CreateWindowExW(0, szDdeClientClassName, szDdeClientWindowName,
+ RegisterClassEx(&wc);
+ es->hwnd = CreateWindowEx(0, szDdeClientClassName, szDdeClientWindowName,
WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, (LPVOID)es);
return TCL_OK;
}
@@ -1113,20 +984,20 @@ DdeClientWindowProc(
switch (uMsg) {
case WM_CREATE: {
LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
- DdeEnumServices *es =
- (DdeEnumServices *) lpcs->lpCreateParams;
+ struct DdeEnumServices *es =
+ (struct DdeEnumServices *) lpcs->lpCreateParams;
#ifdef _WIN64
- SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) es);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) es);
#else
- SetWindowLongW(hwnd, GWL_USERDATA, (LONG) es);
+ SetWindowLong(hwnd, GWL_USERDATA, (LONG) es);
#endif
return (LRESULT) 0L;
}
case WM_DDE_ACK:
return DdeServicesOnAck(hwnd, wParam, lParam);
default:
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
@@ -1139,31 +1010,24 @@ DdeServicesOnAck(
HWND hwndRemote = (HWND)wParam;
ATOM service = (ATOM)LOWORD(lParam);
ATOM topic = (ATOM)HIWORD(lParam);
- DdeEnumServices *es;
- WCHAR sz[255];
- Tcl_DString dString;
+ struct DdeEnumServices *es;
+ char sz[255];
#ifdef _WIN64
- es = (DdeEnumServices *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
+ es = (struct DdeEnumServices *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
#else
- es = (DdeEnumServices *) GetWindowLongW(hwnd, GWL_USERDATA);
+ es = (struct DdeEnumServices *) GetWindowLong(hwnd, GWL_USERDATA);
#endif
- if (((es->service == (ATOM)0) || (es->service == service))
- && ((es->topic == (ATOM)0) || (es->topic == topic))) {
+ if ((es->service == (ATOM)0 || es->service == service)
+ && (es->topic == (ATOM)0 || es->topic == topic)) {
Tcl_Obj *matchPtr = Tcl_NewListObj(0, NULL);
Tcl_Obj *resultPtr = Tcl_GetObjResult(es->interp);
- GlobalGetAtomNameW(service, sz, 255);
- Tcl_DStringInit(&dString);
- Tcl_WCharToUtfDString(sz, wcslen(sz), &dString);
- Tcl_ListObjAppendElement(NULL, matchPtr, Tcl_NewStringObj(Tcl_DStringValue(&dString), -1));
- Tcl_DStringFree(&dString);
- GlobalGetAtomNameW(topic, sz, 255);
- Tcl_DStringInit(&dString);
- Tcl_WCharToUtfDString(sz, wcslen(sz), &dString);
- Tcl_ListObjAppendElement(NULL, matchPtr, Tcl_NewStringObj(Tcl_DStringValue(&dString), -1));
- Tcl_DStringFree(&dString);
+ GlobalGetAtomName(service, sz, 255);
+ Tcl_ListObjAppendElement(NULL, matchPtr, Tcl_NewStringObj(sz, -1));
+ GlobalGetAtomName(topic, sz, 255);
+ Tcl_ListObjAppendElement(NULL, matchPtr, Tcl_NewStringObj(sz, -1));
/*
* Adding the hwnd as a third list element provides a unique
@@ -1189,7 +1053,7 @@ DdeServicesOnAck(
* Tell the server we are no longer interested.
*/
- PostMessageW(hwndRemote, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L);
+ PostMessage(hwndRemote, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L);
return 0L;
}
@@ -1199,9 +1063,9 @@ DdeEnumWindowsCallback(
LPARAM lParam)
{
DWORD_PTR dwResult = 0;
- DdeEnumServices *es = (DdeEnumServices *) lParam;
+ struct DdeEnumServices *es = (struct DdeEnumServices *) lParam;
- SendMessageTimeoutW(hwndTarget, WM_DDE_INITIATE, (WPARAM)es->hwnd,
+ SendMessageTimeout(hwndTarget, WM_DDE_INITIATE, (WPARAM)es->hwnd,
MAKELONG(es->service, es->topic), SMTO_ABORTIFHUNG, 1000,
&dwResult);
return TRUE;
@@ -1210,16 +1074,16 @@ DdeEnumWindowsCallback(
static int
DdeGetServicesList(
Tcl_Interp *interp,
- const WCHAR *serviceName,
- const WCHAR *topicName)
+ const char *serviceName,
+ const char *topicName)
{
- DdeEnumServices es;
+ struct DdeEnumServices es;
es.interp = interp;
es.result = TCL_OK;
es.service = (serviceName == NULL)
- ? (ATOM)0 : GlobalAddAtomW(serviceName);
- es.topic = (topicName == NULL) ? (ATOM)0 : GlobalAddAtomW(topicName);
+ ? (ATOM)0 : GlobalAddAtom(serviceName);
+ es.topic = (topicName == NULL) ? (ATOM)0 : GlobalAddAtom(topicName);
Tcl_ResetResult(interp); /* our list is to be appended to result. */
DdeCreateClient(&es);
@@ -1258,30 +1122,25 @@ static void
SetDdeError(
Tcl_Interp *interp) /* The interp to put the message in. */
{
- const char *errorMessage, *errorCode;
+ const char *errorMessage;
switch (DdeGetLastError(ddeInstance)) {
case DMLERR_DATAACKTIMEOUT:
case DMLERR_EXECACKTIMEOUT:
case DMLERR_POKEACKTIMEOUT:
errorMessage = "remote interpreter did not respond";
- errorCode = "TIMEOUT";
break;
case DMLERR_BUSY:
errorMessage = "remote server is busy";
- errorCode = "BUSY";
break;
case DMLERR_NOTPROCESSED:
errorMessage = "remote server cannot handle this command";
- errorCode = "NOCANDO";
break;
default:
errorMessage = "dde command failed";
- errorCode = "FAILED";
}
Tcl_SetObjResult(interp, Tcl_NewStringObj(errorMessage, -1));
- Tcl_SetErrorCode(interp, "TCL", "DDE", errorCode, (void *)NULL);
}
/*
@@ -1303,48 +1162,39 @@ SetDdeError(
static int
DdeObjCmd(
- void *dummy, /* Not used. */
+ ClientData clientData, /* Used only for deletion */
Tcl_Interp *interp, /* The interp we are sending from */
- Tcl_Size objc, /* Number of arguments */
+ int objc, /* Number of arguments */
Tcl_Obj *const *objv) /* The arguments */
{
- static const char *const ddeCommands[] = {
- "servername", "execute", "poke", "request", "services", "eval", NULL};
+ static const char *ddeCommands[] = {
+ "servername", "execute", "poke", "request", "services", "eval",
+ (char *) NULL};
enum DdeSubcommands {
DDE_SERVERNAME, DDE_EXECUTE, DDE_POKE, DDE_REQUEST, DDE_SERVICES,
DDE_EVAL
};
- static const char *const ddeSrvOptions[] = {
+ static const char *ddeSrvOptions[] = {
"-force", "-handler", "--", NULL
};
enum DdeSrvOptions {
DDE_SERVERNAME_EXACT, DDE_SERVERNAME_HANDLER, DDE_SERVERNAME_LAST,
};
- static const char *const ddeExecOptions[] = {
- "-async", "-binary", NULL
- };
- enum DdeExecOptions {
- DDE_EXEC_ASYNC, DDE_EXEC_BINARY
- };
- static const char *const ddeEvalOptions[] = {
+ static const char *ddeExecOptions[] = {
"-async", NULL
};
- static const char *const ddeReqOptions[] = {
+ static const char *ddeReqOptions[] = {
"-binary", NULL
};
- int index, argIndex;
- Tcl_Size length, i;
+ int index, i, length, argIndex;
int flags = 0, result = TCL_OK, firstArg = 0;
HSZ ddeService = NULL, ddeTopic = NULL, ddeItem = NULL, ddeCookie = NULL;
HDDEDATA ddeData = NULL, ddeItemData = NULL, ddeReturn;
HCONV hConv = NULL;
- const WCHAR *serviceName = NULL, *topicName = NULL;
- const char *string;
+ const char *serviceName = NULL, *topicName = NULL, *string;
DWORD ddeResult;
Tcl_Obj *objPtr, *handlerPtr = NULL;
- Tcl_DString serviceBuf, topicBuf, itemBuf;
- (void)dummy;
/*
* Initialize DDE server/client
@@ -1360,9 +1210,6 @@ DdeObjCmd(
return TCL_ERROR;
}
- Tcl_DStringInit(&serviceBuf);
- Tcl_DStringInit(&topicBuf);
- Tcl_DStringInit(&itemBuf);
switch ((enum DdeSubcommands) index) {
case DDE_SERVERNAME:
for (i = 2; i < objc; i++) {
@@ -1412,53 +1259,38 @@ DdeObjCmd(
if (objc == 5) {
firstArg = 2;
break;
- } else if ((objc >= 6) && (objc <= 7)) {
- firstArg = objc - 3;
- for (i = 2; i < firstArg; i++) {
- if (Tcl_GetIndexFromObj(interp, objv[i], ddeExecOptions,
- "option", 0, &argIndex) != TCL_OK) {
- goto wrongDdeExecuteArgs;
- }
- if (argIndex == DDE_EXEC_ASYNC) {
- flags |= DDE_FLAG_ASYNC;
- } else {
- flags |= DDE_FLAG_BINARY;
- }
+ } else if (objc == 6) {
+ if (Tcl_GetIndexFromObj(NULL, objv[2], ddeExecOptions, "option", 0,
+ &argIndex) == TCL_OK) {
+ flags |= DDE_FLAG_ASYNC;
+ firstArg = 3;
+ break;
}
- break;
}
/* otherwise... */
- wrongDdeExecuteArgs:
Tcl_WrongNumArgs(interp, 2, objv,
- "?-async? ?-binary? serviceName topicName value");
+ "?-async? serviceName topicName value");
return TCL_ERROR;
case DDE_POKE:
- if (objc == 6) {
- firstArg = 2;
- break;
- } else if ((objc == 7) && (Tcl_GetIndexFromObj(NULL, objv[2],
- ddeReqOptions, "option", 0, &argIndex) == TCL_OK)) {
- flags |= DDE_FLAG_BINARY;
- firstArg = 3;
- break;
+ if (objc != 6) {
+ Tcl_WrongNumArgs(interp, 2, objv,
+ "serviceName topicName item value");
+ return TCL_ERROR;
}
-
- /*
- * Otherwise...
- */
-
- Tcl_WrongNumArgs(interp, 2, objv,
- "?-binary? serviceName topicName item value");
- return TCL_ERROR;
+ firstArg = 2;
+ break;
case DDE_REQUEST:
if (objc == 5) {
firstArg = 2;
break;
- } else if ((objc == 6) && (Tcl_GetIndexFromObj(NULL, objv[2],
- ddeReqOptions, "option", 0, &argIndex) == TCL_OK)) {
- flags |= DDE_FLAG_BINARY;
- firstArg = 3;
- break;
+ } else if (objc == 6) {
+ int dummy;
+ if (Tcl_GetIndexFromObj(NULL, objv[2], ddeReqOptions, "option", 0,
+ &dummy) == TCL_OK) {
+ flags |= DDE_FLAG_BINARY;
+ firstArg = 3;
+ break;
+ }
}
/*
@@ -1482,7 +1314,7 @@ DdeObjCmd(
return TCL_ERROR;
} else {
firstArg = 2;
- if (Tcl_GetIndexFromObj(NULL, objv[2], ddeEvalOptions, "option",
+ if (Tcl_GetIndexFromObj(NULL, objv[2], ddeExecOptions, "option",
0, &argIndex) == TCL_OK) {
if (objc < 5) {
goto wrongDdeEvalArgs;
@@ -1497,12 +1329,7 @@ DdeObjCmd(
Initialize();
if (firstArg != 1) {
- const char *src = Tcl_GetStringFromObj(objv[firstArg], &length);
-
- Tcl_DStringInit(&serviceBuf);
- Tcl_UtfToWCharDString(src, length, &serviceBuf);
- serviceName = (WCHAR *) Tcl_DStringValue(&serviceBuf);
- length = Tcl_DStringLength(&serviceBuf) / sizeof(WCHAR);
+ serviceName = Tcl_GetStringFromObj(objv[firstArg], &length);
} else {
length = 0;
}
@@ -1510,21 +1337,17 @@ DdeObjCmd(
if (length == 0) {
serviceName = NULL;
} else if ((index != DDE_SERVERNAME) && (index != DDE_EVAL)) {
- ddeService = DdeCreateStringHandleW(ddeInstance, serviceName,
- CP_WINUNICODE);
+ ddeService = DdeCreateStringHandle(ddeInstance, (void *) serviceName,
+ CP_WINANSI);
}
if ((index != DDE_SERVERNAME) && (index != DDE_EVAL)) {
- const char *src = Tcl_GetStringFromObj(objv[firstArg + 1], &length);
-
- Tcl_DStringInit(&topicBuf);
- topicName = Tcl_UtfToWCharDString(src, length, &topicBuf);
- length = Tcl_DStringLength(&topicBuf) / sizeof(WCHAR);
+ topicName = Tcl_GetStringFromObj(objv[firstArg + 1], &length);
if (length == 0) {
topicName = NULL;
} else {
- ddeTopic = DdeCreateStringHandleW(ddeInstance, topicName,
- CP_WINUNICODE);
+ ddeTopic = DdeCreateStringHandle(ddeInstance, (void *) topicName,
+ CP_WINANSI);
}
}
@@ -1533,42 +1356,20 @@ DdeObjCmd(
serviceName = DdeSetServerName(interp, serviceName, flags,
handlerPtr);
if (serviceName != NULL) {
- Tcl_DString dsBuf;
-
- Tcl_DStringInit(&dsBuf);
- Tcl_WCharToUtfDString(serviceName, wcslen(serviceName), &dsBuf);
- Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_DStringValue(&dsBuf),
- Tcl_DStringLength(&dsBuf)));
- Tcl_DStringFree(&dsBuf);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(serviceName, -1));
} else {
Tcl_ResetResult(interp);
}
break;
case DDE_EXECUTE: {
- Tcl_Size dataLength;
- const void *dataString;
- Tcl_DString dsBuf;
-
- Tcl_DStringInit(&dsBuf);
- if (flags & DDE_FLAG_BINARY) {
- dataString =
- Tcl_GetByteArrayFromObj(objv[firstArg + 2], &dataLength);
- } else {
- const char *src;
+ int dataLength;
+ BYTE *dataString = (BYTE *) Tcl_GetStringFromObj(
+ objv[firstArg + 2], &dataLength);
- src = Tcl_GetStringFromObj(objv[firstArg + 2], &dataLength);
- Tcl_DStringInit(&dsBuf);
- dataString =
- Tcl_UtfToWCharDString(src, dataLength, &dsBuf);
- dataLength = Tcl_DStringLength(&dsBuf) + sizeof(WCHAR);
- }
-
- if (dataLength + 1 < 2) {
+ if (dataLength == 0) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("cannot execute null data", -1));
- Tcl_DStringFree(&dsBuf);
- Tcl_SetErrorCode(interp, "TCL", "DDE", "NULL", (void *)NULL);
result = TCL_ERROR;
break;
}
@@ -1577,22 +1378,21 @@ DdeObjCmd(
DdeFreeStringHandle(ddeInstance, ddeTopic);
if (hConv == NULL) {
- Tcl_DStringFree(&dsBuf);
SetDdeError(interp);
result = TCL_ERROR;
break;
}
- ddeData = DdeCreateDataHandle(ddeInstance, (BYTE *) dataString,
- (DWORD) dataLength, 0, 0, (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, 0);
+ ddeData = DdeCreateDataHandle(ddeInstance, dataString,
+ (DWORD) dataLength+1, 0, 0, CF_TEXT, 0);
if (ddeData != NULL) {
if (flags & DDE_FLAG_ASYNC) {
DdeClientTransaction((LPBYTE) ddeData, 0xFFFFFFFF, hConv, 0,
- (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult);
+ CF_TEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult);
DdeAbandonTransaction(ddeInstance, hConv, ddeResult);
} else {
ddeReturn = DdeClientTransaction((LPBYTE) ddeData, 0xFFFFFFFF,
- hConv, 0, (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_EXECUTE, 30000, NULL);
+ hConv, 0, CF_TEXT, XTYP_EXECUTE, 30000, NULL);
if (ddeReturn == 0) {
SetDdeError(interp);
result = TCL_ERROR;
@@ -1603,22 +1403,15 @@ DdeObjCmd(
SetDdeError(interp);
result = TCL_ERROR;
}
- Tcl_DStringFree(&dsBuf);
break;
}
case DDE_REQUEST: {
- const WCHAR *itemString;
- const char *src;
-
- src = Tcl_GetStringFromObj(objv[firstArg + 2], &length);
- Tcl_DStringInit(&itemBuf);
- itemString = Tcl_UtfToWCharDString(src, length, &itemBuf);
- length = Tcl_DStringLength(&itemBuf) / sizeof(WCHAR);
+ const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2],
+ &length);
if (length == 0) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("cannot request value of null data", -1));
- Tcl_SetErrorCode(interp, "TCL", "DDE", "NULL", (void *)NULL);
result = TCL_ERROR;
goto cleanup;
}
@@ -1631,34 +1424,27 @@ DdeObjCmd(
result = TCL_ERROR;
} else {
Tcl_Obj *returnObjPtr;
- ddeItem = DdeCreateStringHandleW(ddeInstance, itemString,
- CP_WINUNICODE);
+ ddeItem = DdeCreateStringHandle(ddeInstance, (void *)itemString,
+ CP_WINANSI);
if (ddeItem != NULL) {
ddeData = DdeClientTransaction(NULL, 0, hConv, ddeItem,
- (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_REQUEST, 5000, NULL);
+ CF_TEXT, XTYP_REQUEST, 5000, NULL);
if (ddeData == NULL) {
SetDdeError(interp);
result = TCL_ERROR;
} else {
DWORD tmp;
- WCHAR *dataString = (WCHAR *) DdeAccessData(ddeData, &tmp);
+ const char *dataString = (const char *) DdeAccessData(ddeData, &tmp);
if (flags & DDE_FLAG_BINARY) {
returnObjPtr =
- Tcl_NewByteArrayObj((BYTE *) dataString, tmp);
+ Tcl_NewByteArrayObj((BYTE *) dataString, (int) tmp);
} else {
- Tcl_DString dsBuf;
-
- if ((tmp >= sizeof(WCHAR))
- && !dataString[tmp / sizeof(WCHAR) - 1]) {
- tmp -= (DWORD)sizeof(WCHAR);
+ if (tmp && !dataString[tmp-1]) {
+ --tmp;
}
- Tcl_DStringInit(&dsBuf);
- Tcl_WCharToUtfDString(dataString, tmp>>1, &dsBuf);
- returnObjPtr =
- Tcl_NewStringObj(Tcl_DStringValue(&dsBuf),
- Tcl_DStringLength(&dsBuf));
- Tcl_DStringFree(&dsBuf);
+ returnObjPtr = Tcl_NewStringObj(dataString,
+ (int) tmp);
}
DdeUnaccessData(ddeData);
DdeFreeDataHandle(ddeData);
@@ -1669,37 +1455,22 @@ DdeObjCmd(
result = TCL_ERROR;
}
}
+
break;
}
case DDE_POKE: {
- Tcl_DString dsBuf;
- const WCHAR *itemString;
+ const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2],
+ &length);
BYTE *dataString;
- const char *src;
- src = Tcl_GetStringFromObj(objv[firstArg + 2], &length);
- Tcl_DStringInit(&itemBuf);
- itemString = Tcl_UtfToWCharDString(src, length, &itemBuf);
- length = Tcl_DStringLength(&itemBuf) / sizeof(WCHAR);
if (length == 0) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("cannot have a null item", -1));
- Tcl_SetErrorCode(interp, "TCL", "DDE", "NULL", (void *)NULL);
result = TCL_ERROR;
goto cleanup;
}
- Tcl_DStringInit(&dsBuf);
- if (flags & DDE_FLAG_BINARY) {
- dataString = (BYTE *)
- Tcl_GetByteArrayFromObj(objv[firstArg + 3], &length);
- } else {
- const char *data =
- Tcl_GetStringFromObj(objv[firstArg + 3], &length);
- Tcl_DStringInit(&dsBuf);
- dataString = (BYTE *)
- Tcl_UtfToWCharDString(data, length, &dsBuf);
- length = Tcl_DStringLength(&dsBuf) + sizeof(WCHAR);
- }
+ dataString = (BYTE *) Tcl_GetStringFromObj(objv[firstArg + 3],
+ &length);
hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);
DdeFreeStringHandle(ddeInstance, ddeService);
@@ -1709,11 +1480,11 @@ DdeObjCmd(
SetDdeError(interp);
result = TCL_ERROR;
} else {
- ddeItem = DdeCreateStringHandleW(ddeInstance, itemString,
- CP_WINUNICODE);
+ ddeItem = DdeCreateStringHandle(ddeInstance, (void *) itemString,
+ CP_WINANSI);
if (ddeItem != NULL) {
- ddeData = DdeClientTransaction(dataString, (DWORD) length,
- hConv, ddeItem, (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_POKE, 5000, NULL);
+ ddeData = DdeClientTransaction(dataString, (DWORD) length+1,
+ hConv, ddeItem, CF_TEXT, XTYP_POKE, 5000, NULL);
if (ddeData == NULL) {
SetDdeError(interp);
result = TCL_ERROR;
@@ -1723,7 +1494,6 @@ DdeObjCmd(
result = TCL_ERROR;
}
}
- Tcl_DStringFree(&dsBuf);
break;
}
@@ -1738,7 +1508,6 @@ DdeObjCmd(
if (serviceName == NULL) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("invalid service name \"\"", -1));
- Tcl_SetErrorCode(interp, "TCL", "DDE", "NO_SERVER", (void *)NULL);
result = TCL_ERROR;
goto cleanup;
}
@@ -1757,7 +1526,7 @@ DdeObjCmd(
for (riPtr = tsdPtr->interpListPtr; riPtr != NULL;
riPtr = riPtr->nextPtr) {
- if (_wcsicmp(serviceName, riPtr->name) == 0) {
+ if (stricmp(serviceName, riPtr->name) == 0) {
break;
}
}
@@ -1770,9 +1539,9 @@ DdeObjCmd(
* server.
*/
- Tcl_Preserve(riPtr);
+ Tcl_Preserve((ClientData) riPtr);
sendInterp = riPtr->interp;
- Tcl_Preserve(sendInterp);
+ Tcl_Preserve((ClientData) sendInterp);
/*
* Don't exchange objects between interps. The target interp would
@@ -1782,19 +1551,17 @@ DdeObjCmd(
* referring to deallocated objects.
*/
- if (Tcl_IsSafe(riPtr->interp) && (riPtr->handlerPtr == NULL)) {
- Tcl_SetObjResult(riPtr->interp, Tcl_NewStringObj(
- "permission denied: a handler procedure must be"
- " defined for use in a safe interp", -1));
- Tcl_SetErrorCode(interp, "TCL", "DDE", "SECURITY_CHECK",
- (void *)NULL);
+ if (Tcl_IsSafe(riPtr->interp) && riPtr->handlerPtr == NULL) {
+ Tcl_SetResult(riPtr->interp, "permission denied: "
+ "a handler procedure must be defined for use in "
+ "a safe interp", TCL_STATIC);
result = TCL_ERROR;
}
if (result == TCL_OK) {
- if (objc == 1) {
+ if (objc == 1)
objPtr = objv[0];
- } else {
+ else {
objPtr = Tcl_ConcatObj(objc, objv);
}
if (riPtr->handlerPtr != NULL) {
@@ -1827,7 +1594,8 @@ DdeObjCmd(
objPtr = Tcl_GetVar2Ex(sendInterp, "errorInfo", NULL,
TCL_GLOBAL_ONLY);
if (objPtr) {
- Tcl_AppendObjToErrorInfo(interp, objPtr);
+ string = Tcl_GetStringFromObj(objPtr, &length);
+ Tcl_AddObjErrorInfo(interp, string, length);
}
objPtr = Tcl_GetVar2Ex(sendInterp, "errorCode", NULL,
@@ -1838,11 +1606,9 @@ DdeObjCmd(
}
Tcl_SetObjResult(interp, Tcl_GetObjResult(sendInterp));
}
- Tcl_Release(riPtr);
- Tcl_Release(sendInterp);
+ Tcl_Release((ClientData) riPtr);
+ Tcl_Release((ClientData) sendInterp);
} else {
- Tcl_DString dsBuf;
-
/*
* This is a non-local request. Send the script to the server and
* poll it for a result.
@@ -1851,36 +1617,31 @@ DdeObjCmd(
if (MakeDdeConnection(interp, serviceName, &hConv) != TCL_OK) {
invalidServerResponse:
Tcl_SetObjResult(interp,
- Tcl_NewStringObj("invalid data returned from server", -1));
- Tcl_SetErrorCode(interp, "TCL", "DDE", "BAD_RESPONSE", (void *)NULL);
+ Tcl_NewStringObj("invalid data returned from server",
+ -1));
result = TCL_ERROR;
goto cleanup;
}
objPtr = Tcl_ConcatObj(objc, objv);
string = Tcl_GetStringFromObj(objPtr, &length);
- Tcl_DStringInit(&dsBuf);
- Tcl_UtfToWCharDString(string, length, &dsBuf);
- string = Tcl_DStringValue(&dsBuf);
- length = Tcl_DStringLength(&dsBuf) + sizeof(WCHAR);
- ddeItemData = DdeCreateDataHandle(ddeInstance, (BYTE *) string,
- (DWORD) length, 0, 0, CF_UNICODETEXT, 0);
- Tcl_DStringFree(&dsBuf);
+ ddeItemData = DdeCreateDataHandle(ddeInstance,
+ (BYTE *) string, (DWORD) length+1, 0, 0, CF_TEXT, 0);
if (flags & DDE_FLAG_ASYNC) {
ddeData = DdeClientTransaction((LPBYTE) ddeItemData,
0xFFFFFFFF, hConv, 0,
- CF_UNICODETEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult);
+ CF_TEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult);
DdeAbandonTransaction(ddeInstance, hConv, ddeResult);
} else {
ddeData = DdeClientTransaction((LPBYTE) ddeItemData,
0xFFFFFFFF, hConv, 0,
- CF_UNICODETEXT, XTYP_EXECUTE, 30000, NULL);
+ CF_TEXT, XTYP_EXECUTE, 30000, NULL);
if (ddeData != 0) {
- ddeCookie = DdeCreateStringHandleW(ddeInstance,
- TCL_DDE_EXECUTE_RESULT, CP_WINUNICODE);
+ ddeCookie = DdeCreateStringHandle(ddeInstance,
+ TCL_DDE_EXECUTE_RESULT, CP_WINANSI);
ddeData = DdeClientTransaction(NULL, 0, hConv, ddeCookie,
- CF_UNICODETEXT, XTYP_REQUEST, 30000, NULL);
+ CF_TEXT, XTYP_REQUEST, 30000, NULL);
}
}
@@ -1889,12 +1650,10 @@ DdeObjCmd(
if (ddeData == 0) {
SetDdeError(interp);
result = TCL_ERROR;
- goto cleanup;
}
if (!(flags & DDE_FLAG_ASYNC)) {
Tcl_Obj *resultPtr;
- WCHAR *ddeDataString;
/*
* The return handle has a two or four element list in it. The
@@ -1905,18 +1664,12 @@ DdeObjCmd(
* variable "errorInfo".
*/
+ resultPtr = Tcl_NewObj();
length = DdeGetData(ddeData, NULL, 0, 0);
- ddeDataString = (WCHAR *) Tcl_Alloc(length);
- DdeGetData(ddeData, (BYTE *) ddeDataString, (DWORD) length, 0);
- if (length > (Tcl_Size)sizeof(WCHAR)) {
- length -= sizeof(WCHAR);
- }
- Tcl_DStringInit(&dsBuf);
- Tcl_WCharToUtfDString(ddeDataString, length>>1, &dsBuf);
- resultPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsBuf),
- Tcl_DStringLength(&dsBuf));
- Tcl_DStringFree(&dsBuf);
- Tcl_Free((char *) ddeDataString);
+ Tcl_SetObjLength(resultPtr, length);
+ string = Tcl_GetString(resultPtr);
+ DdeGetData(ddeData, (BYTE *) string, (DWORD) length, 0);
+ Tcl_SetObjLength(resultPtr, (int) strlen(string));
if (Tcl_ListObjIndex(NULL, resultPtr, 0, &objPtr) != TCL_OK) {
Tcl_DecrRefCount(resultPtr);
@@ -1934,7 +1687,9 @@ DdeObjCmd(
Tcl_DecrRefCount(resultPtr);
goto invalidServerResponse;
}
- Tcl_AppendObjToErrorInfo(interp, objPtr);
+ length = -1;
+ string = Tcl_GetStringFromObj(objPtr, &length);
+ Tcl_AddObjErrorInfo(interp, string, length);
Tcl_ListObjIndex(NULL, resultPtr, 2, &objPtr);
Tcl_SetObjErrorCode(interp, objPtr);
@@ -1966,9 +1721,6 @@ DdeObjCmd(
if (hConv != NULL) {
DdeDisconnect(hConv);
}
- Tcl_DStringFree(&itemBuf);
- Tcl_DStringFree(&topicBuf);
- Tcl_DStringFree(&serviceBuf);
return result;
}
diff --git a/win/tclWinError.c b/win/tclWinError.c
index 7e5898b..a74d2e2 100644
--- a/win/tclWinError.c
+++ b/win/tclWinError.c
@@ -4,18 +4,20 @@
* This file contains code for converting from Win32 errors to errno
* errors.
*
- * Copyright © 1995-1996 Sun Microsystems, Inc.
+ * Copyright (c) 1995-1996 by Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
+#include "tclPort.h"
+
/*
* The following table contains the mapping from Win32 errors to errno errors.
*/
-static const unsigned char errorTable[] = {
+static CONST unsigned char errorTable[] = {
0,
EINVAL, /* ERROR_INVALID_FUNCTION 1 */
ENOENT, /* ERROR_FILE_NOT_FOUND 2 */
@@ -30,7 +32,7 @@ static const unsigned char errorTable[] = {
ENOEXEC, /* ERROR_BAD_FORMAT 11 */
EACCES, /* ERROR_INVALID_ACCESS 12 */
EINVAL, /* ERROR_INVALID_DATA 13 */
- ENOMEM, /* ERROR_OUT_OF_MEMORY 14 */
+ EFAULT, /* ERROR_OUT_OF_MEMORY 14 */
ENOENT, /* ERROR_INVALID_DRIVE 15 */
EACCES, /* ERROR_CURRENT_DIRECTORY 16 */
EXDEV, /* ERROR_NOT_SAME_DEVICE 17 */
@@ -291,7 +293,7 @@ static const unsigned char errorTable[] = {
* errno errors.
*/
-static const unsigned char wsaErrorTable[] = {
+static CONST int wsaErrorTable[] = {
EWOULDBLOCK, /* WSAEWOULDBLOCK */
EINPROGRESS, /* WSAEINPROGRESS */
EALREADY, /* WSAEALREADY */
@@ -334,7 +336,7 @@ static const unsigned char wsaErrorTable[] = {
/*
*----------------------------------------------------------------------
*
- * Tcl_WinConvertError --
+ * TclWinConvertError --
*
* This routine converts a Win32 error into an errno value.
*
@@ -348,8 +350,8 @@ static const unsigned char wsaErrorTable[] = {
*/
void
-Tcl_WinConvertError(
- unsigned errCode) /* Win32 error code. */
+TclWinConvertError(
+ DWORD errCode) /* Win32 error code. */
{
if (errCode >= sizeof(errorTable)/sizeof(errorTable[0])) {
errCode -= WSAEWOULDBLOCK;
@@ -362,65 +364,39 @@ Tcl_WinConvertError(
Tcl_SetErrno(errorTable[errCode]);
}
}
-
-#ifdef __CYGWIN__
+
/*
*----------------------------------------------------------------------
*
- * tclWinDebugPanic --
+ * TclWinConvertWSAError --
*
- * Display a message. If a debugger is present, present it directly to
- * the debugger, otherwise send it to stderr.
+ * This routine converts a WinSock error into an errno value.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * Sets the errno global variable.
*
*----------------------------------------------------------------------
*/
-TCL_NORETURN void
-tclWinDebugPanic(
- const char *format, ...)
+void
+TclWinConvertWSAError(
+ DWORD errCode) /* Win32 error code. */
{
-#define TCL_MAX_WARN_LEN 1024
- va_list argList;
- va_start(argList, format);
-
- if (IsDebuggerPresent()) {
- WCHAR msgString[TCL_MAX_WARN_LEN];
- char buf[TCL_MAX_WARN_LEN * 3];
-
- vsnprintf(buf, sizeof(buf), format, argList);
- msgString[TCL_MAX_WARN_LEN-1] = '\0';
- MultiByteToWideChar(CP_UTF8, 0, buf, -1, msgString, TCL_MAX_WARN_LEN);
-
- /*
- * Truncate MessageBox string if it is too long to not overflow the buffer.
- */
-
- if (msgString[TCL_MAX_WARN_LEN-1] != '\0') {
- memcpy(msgString + (TCL_MAX_WARN_LEN - 5), L" ...", 5 * sizeof(WCHAR));
+ if (errCode >= sizeof(errorTable)/sizeof(errorTable[0])) {
+ errCode -= WSAEWOULDBLOCK;
+ if (errCode >= sizeof(wsaErrorTable)/sizeof(wsaErrorTable[0])) {
+ Tcl_SetErrno(errorTable[1]);
+ } else {
+ Tcl_SetErrno(wsaErrorTable[errCode]);
}
- OutputDebugStringW(msgString);
} else {
- if (!isatty(fileno(stderr))) {
- fprintf(stderr, "\xEF\xBB\xBF");
- }
- vfprintf(stderr, format, argList);
- fprintf(stderr, "\n");
- fflush(stderr);
+ Tcl_SetErrno(errorTable[errCode]);
}
-# if defined(__GNUC__)
- __builtin_trap();
-# else
- DebugBreak();
-# endif
- abort();
}
-#endif
+
/*
* Local Variables:
* mode: c
diff --git a/win/tclWinFCmd.c b/win/tclWinFCmd.c
index 5d45fe1..441337e 100644
--- a/win/tclWinFCmd.c
+++ b/win/tclWinFCmd.c
@@ -4,7 +4,7 @@
* This file implements the Windows specific portion of file manipulation
* subcommands of the "file" command.
*
- * Copyright © 1996-1998 Sun Microsystems, Inc.
+ * Copyright (c) 1996-1998 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -54,12 +54,12 @@ static const int attributeArray[] = {FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_HIDD
0, FILE_ATTRIBUTE_READONLY, 0, FILE_ATTRIBUTE_SYSTEM};
-const char *const tclpFileAttrStrings[] = {
+CONST char *tclpFileAttrStrings[] = {
"-archive", "-hidden", "-longname", "-readonly",
- "-shortname", "-system", NULL
+ "-shortname", "-system", (char *) NULL
};
-const TclFileAttrProcs tclpFileAttrProcs[] = {
+CONST TclFileAttrProcs tclpFileAttrProcs[] = {
{GetWinFileAttributes, SetWinFileAttributes},
{GetWinFileAttributes, SetWinFileAttributes},
{GetWinFileLongName, CannotSetAttribute},
@@ -71,7 +71,7 @@ const TclFileAttrProcs tclpFileAttrProcs[] = {
* Prototype for the TraverseWinTree callback function.
*/
-typedef int (TraversalProc)(const WCHAR *srcPtr, const WCHAR *dstPtr,
+typedef int (TraversalProc)(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr,
int type, Tcl_DString *errorPtr);
/*
@@ -82,18 +82,18 @@ static void StatError(Tcl_Interp *interp, Tcl_Obj *fileName);
static int ConvertFileNameFormat(Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName, int longShort,
Tcl_Obj **attributePtrPtr);
-static int DoCopyFile(const WCHAR *srcPtr, const WCHAR *dstPtr);
-static int DoCreateDirectory(const WCHAR *pathPtr);
-static int DoRemoveJustDirectory(const WCHAR *nativeSrc,
+static int DoCopyFile(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr);
+static int DoCreateDirectory(CONST TCHAR *pathPtr);
+static int DoRemoveJustDirectory(CONST TCHAR *nativeSrc,
int ignoreError, Tcl_DString *errorPtr);
static int DoRemoveDirectory(Tcl_DString *pathPtr, int recursive,
Tcl_DString *errorPtr);
-static int DoRenameFile(const WCHAR *nativeSrc,
- const WCHAR *dstPtr);
-static int TraversalCopy(const WCHAR *srcPtr, const WCHAR *dstPtr,
+static int DoRenameFile(CONST TCHAR *nativeSrc,
+ CONST TCHAR *dstPtr);
+static int TraversalCopy(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr,
int type, Tcl_DString *errorPtr);
-static int TraversalDelete(const WCHAR *srcPtr,
- const WCHAR *dstPtr, int type,
+static int TraversalDelete(CONST TCHAR *srcPtr,
+ CONST TCHAR *dstPtr, int type,
Tcl_DString *errorPtr);
static int TraverseWinTree(TraversalProc *traverseProc,
Tcl_DString *sourcePtr, Tcl_DString *dstPtr,
@@ -145,15 +145,15 @@ TclpObjRenameFile(
Tcl_Obj *srcPathPtr,
Tcl_Obj *destPathPtr)
{
- return DoRenameFile((const WCHAR *)Tcl_FSGetNativePath(srcPathPtr),
- (const WCHAR *)Tcl_FSGetNativePath(destPathPtr));
+ return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr),
+ Tcl_FSGetNativePath(destPathPtr));
}
static int
DoRenameFile(
- const WCHAR *nativeSrc, /* Pathname of file or dir to be renamed
+ CONST TCHAR *nativeSrc, /* Pathname of file or dir to be renamed
* (native). */
- const WCHAR *nativeDst) /* New pathname for file or directory
+ CONST TCHAR *nativeDst) /* New pathname for file or directory
* (native). */
{
#if defined(HAVE_NO_SEH) && !defined(_WIN64)
@@ -204,7 +204,7 @@ DoRenameFile(
"leal 1f, %%eax" "\n\t"
"movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
"movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
- "movl %%esp, 0xC(%%edx)" "\n\t" /* esp */
+ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
"movl $0, 0x10(%%edx)" "\n\t" /* status */
/*
@@ -214,12 +214,12 @@ DoRenameFile(
"movl %%edx, %%fs:0" "\n\t"
/*
- * Call MoveFileW(nativeSrc, nativeDst)
+ * Call MoveFile(nativeSrc, nativeDst)
*/
"pushl %%ebx" "\n\t"
"pushl %%ecx" "\n\t"
- "movl %[moveFileW], %%eax" "\n\t"
+ "movl %[moveFile], %%eax" "\n\t"
"call *%%eax" "\n\t"
/*
@@ -245,7 +245,7 @@ DoRenameFile(
*/
"2:" "\t"
- "movl 0xC(%%edx), %%esp" "\n\t"
+ "movl 0xc(%%edx), %%esp" "\n\t"
"movl 0x8(%%edx), %%ebp" "\n\t"
"movl 0x0(%%edx), %%eax" "\n\t"
"movl %%eax, %%fs:0" "\n\t"
@@ -256,7 +256,7 @@ DoRenameFile(
[registration] "m" (registration),
[nativeDst] "m" (nativeDst),
[nativeSrc] "m" (nativeSrc),
- [moveFileW] "r" (MoveFileW)
+ [moveFile] "r" (tclWinProcs->moveFileProc)
:
"%eax", "%ebx", "%ecx", "%edx", "memory"
);
@@ -267,7 +267,7 @@ DoRenameFile(
#ifndef HAVE_NO_SEH
__try {
#endif
- if ((*MoveFileW)(nativeSrc, nativeDst) != FALSE) {
+ if ((*tclWinProcs->moveFileProc)(nativeSrc, nativeDst) != FALSE) {
retval = TCL_OK;
}
#ifndef HAVE_NO_SEH
@@ -279,20 +279,20 @@ DoRenameFile(
return retval;
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
- srcAttr = GetFileAttributesW(nativeSrc);
- dstAttr = GetFileAttributesW(nativeDst);
- if (srcAttr == 0xFFFFFFFF) {
- if (GetFullPathNameW(nativeSrc, 0, NULL,
+ srcAttr = (*tclWinProcs->getFileAttributesProc)(nativeSrc);
+ dstAttr = (*tclWinProcs->getFileAttributesProc)(nativeDst);
+ if (srcAttr == 0xffffffff) {
+ if ((*tclWinProcs->getFullPathNameProc)(nativeSrc, 0, NULL,
NULL) >= MAX_PATH) {
errno = ENAMETOOLONG;
return TCL_ERROR;
}
srcAttr = 0;
}
- if (dstAttr == 0xFFFFFFFF) {
- if (GetFullPathNameW(nativeDst, 0, NULL,
+ if (dstAttr == 0xffffffff) {
+ if ((*tclWinProcs->getFullPathNameProc)(nativeDst, 0, NULL,
NULL) >= MAX_PATH) {
errno = ENAMETOOLONG;
return TCL_ERROR;
@@ -307,31 +307,29 @@ DoRenameFile(
if (errno == EACCES) {
decode:
if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) {
- WCHAR *nativeSrcRest, *nativeDstRest;
- const char **srcArgv, **dstArgv;
- Tcl_Size size, srcArgc, dstArgc;
+ TCHAR *nativeSrcRest, *nativeDstRest;
+ CONST char **srcArgv, **dstArgv;
+ int size, srcArgc, dstArgc;
WCHAR nativeSrcPath[MAX_PATH];
WCHAR nativeDstPath[MAX_PATH];
Tcl_DString srcString, dstString;
- const char *src, *dst;
+ CONST char *src, *dst;
- size = GetFullPathNameW(nativeSrc, MAX_PATH,
+ size = (*tclWinProcs->getFullPathNameProc)(nativeSrc, MAX_PATH,
nativeSrcPath, &nativeSrcRest);
- if ((size <= 0) || (size > MAX_PATH)) {
+ if ((size == 0) || (size > MAX_PATH)) {
return TCL_ERROR;
}
- size = GetFullPathNameW(nativeDst, MAX_PATH,
+ size = (*tclWinProcs->getFullPathNameProc)(nativeDst, MAX_PATH,
nativeDstPath, &nativeDstRest);
if ((size == 0) || (size > MAX_PATH)) {
return TCL_ERROR;
}
- CharLowerW(nativeSrcPath);
- CharLowerW(nativeDstPath);
+ (*tclWinProcs->charLowerProc)((TCHAR *) nativeSrcPath);
+ (*tclWinProcs->charLowerProc)((TCHAR *) nativeDstPath);
- Tcl_DStringInit(&srcString);
- Tcl_DStringInit(&dstString);
- src = Tcl_WCharToUtfDString(nativeSrcPath, TCL_INDEX_NONE, &srcString);
- dst = Tcl_WCharToUtfDString(nativeDstPath, TCL_INDEX_NONE, &dstString);
+ src = Tcl_WinTCharToUtf((TCHAR *) nativeSrcPath, -1, &srcString);
+ dst = Tcl_WinTCharToUtf((TCHAR *) nativeDstPath, -1, &dstString);
/*
* Check whether the destination path is actually inside the
@@ -339,7 +337,7 @@ DoRenameFile(
* character is either end-of-string or a directory separator
*/
- if ((strncmp(src, dst, Tcl_DStringLength(&srcString))==0)
+ if ((strncmp(src, dst, (size_t) Tcl_DStringLength(&srcString))==0)
&& (dst[Tcl_DStringLength(&srcString)] == '\\'
|| dst[Tcl_DStringLength(&srcString)] == '/'
|| dst[Tcl_DStringLength(&srcString)] == '\0')) {
@@ -378,8 +376,8 @@ DoRenameFile(
Tcl_SetErrno(EXDEV);
}
- ckfree(srcArgv);
- ckfree(dstArgv);
+ ckfree((char *) srcArgv);
+ ckfree((char *) dstArgv);
}
/*
@@ -410,7 +408,8 @@ DoRenameFile(
* directory back, for completeness.
*/
- if (MoveFileW(nativeSrc, nativeDst) != FALSE) {
+ if ((*tclWinProcs->moveFileProc)(nativeSrc,
+ nativeDst) != FALSE) {
return TCL_OK;
}
@@ -419,9 +418,9 @@ DoRenameFile(
* be, but report this one.
*/
- Tcl_WinConvertError(GetLastError());
- CreateDirectoryW(nativeDst, NULL);
- SetFileAttributesW(nativeDst, dstAttr);
+ TclWinConvertError(GetLastError());
+ (*tclWinProcs->createDirectoryProc)(nativeDst, NULL);
+ (*tclWinProcs->setFileAttributesProc)(nativeDst, dstAttr);
if (Tcl_GetErrno() == EACCES) {
/*
* Decode the EACCES to a more meaningful error.
@@ -446,22 +445,24 @@ DoRenameFile(
* back to old name.
*/
- WCHAR *nativeRest, *nativeTmp, *nativePrefix;
+ TCHAR *nativeRest, *nativeTmp, *nativePrefix;
int result, size;
WCHAR tempBuf[MAX_PATH];
- size = GetFullPathNameW(nativeDst, MAX_PATH,
+ size = (*tclWinProcs->getFullPathNameProc)(nativeDst, MAX_PATH,
tempBuf, &nativeRest);
if ((size == 0) || (size > MAX_PATH) || (nativeRest == NULL)) {
return TCL_ERROR;
}
- nativeTmp = (WCHAR *) tempBuf;
- nativeRest[0] = '\0';
+ nativeTmp = (TCHAR *) tempBuf;
+ ((char *) nativeRest)[0] = '\0';
+ ((char *) nativeRest)[1] = '\0'; /* In case it's Unicode. */
result = TCL_ERROR;
- nativePrefix = (WCHAR *)L"tclr";
- if (GetTempFileNameW(nativeTmp, nativePrefix,
- 0, tempBuf) != 0) {
+ nativePrefix = (tclWinProcs->useWide)
+ ? (TCHAR *) L"tclr" : (TCHAR *) "tclr";
+ if ((*tclWinProcs->getTempFileNameProc)(nativeTmp,
+ nativePrefix, 0, tempBuf) != 0) {
/*
* Strictly speaking, need the following DeleteFile and
* MoveFile to be joined as an atomic operation so no
@@ -469,16 +470,19 @@ DoRenameFile(
* same temp file.
*/
- nativeTmp = tempBuf;
- DeleteFileW(nativeTmp);
- if (MoveFileW(nativeDst, nativeTmp) != FALSE) {
- if (MoveFileW(nativeSrc, nativeDst) != FALSE) {
- SetFileAttributesW(nativeTmp, FILE_ATTRIBUTE_NORMAL);
- DeleteFileW(nativeTmp);
+ nativeTmp = (TCHAR *) tempBuf;
+ (*tclWinProcs->deleteFileProc)(nativeTmp);
+ if ((*tclWinProcs->moveFileProc)(nativeDst,
+ nativeTmp) != FALSE) {
+ if ((*tclWinProcs->moveFileProc)(nativeSrc,
+ nativeDst) != FALSE) {
+ (*tclWinProcs->setFileAttributesProc)(nativeTmp,
+ FILE_ATTRIBUTE_NORMAL);
+ (*tclWinProcs->deleteFileProc)(nativeTmp);
return TCL_OK;
} else {
- DeleteFileW(nativeDst);
- MoveFileW(nativeTmp, nativeDst);
+ (*tclWinProcs->deleteFileProc)(nativeDst);
+ (*tclWinProcs->moveFileProc)(nativeTmp, nativeDst);
}
}
@@ -487,7 +491,7 @@ DoRenameFile(
* error. Could happen if an open file refers to dst.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
if (Tcl_GetErrno() == EACCES) {
/*
* Decode the EACCES to a more meaningful error.
@@ -535,14 +539,14 @@ TclpObjCopyFile(
Tcl_Obj *srcPathPtr,
Tcl_Obj *destPathPtr)
{
- return DoCopyFile((const WCHAR *)Tcl_FSGetNativePath(srcPathPtr),
- (const WCHAR *)Tcl_FSGetNativePath(destPathPtr));
+ return DoCopyFile(Tcl_FSGetNativePath(srcPathPtr),
+ Tcl_FSGetNativePath(destPathPtr));
}
static int
DoCopyFile(
- const WCHAR *nativeSrc, /* Pathname of file to be copied (native). */
- const WCHAR *nativeDst) /* Pathname of file to copy to (native). */
+ CONST TCHAR *nativeSrc, /* Pathname of file to be copied (native). */
+ CONST TCHAR *nativeDst) /* Pathname of file to copy to (native). */
{
#if defined(HAVE_NO_SEH) && !defined(_WIN64)
TCLEXCEPTION_REGISTRATION registration;
@@ -592,7 +596,7 @@ DoCopyFile(
"leal 1f, %%eax" "\n\t"
"movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
"movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
- "movl %%esp, 0xC(%%edx)" "\n\t" /* esp */
+ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
"movl $0, 0x10(%%edx)" "\n\t" /* status */
/*
@@ -602,10 +606,10 @@ DoCopyFile(
"movl %%edx, %%fs:0" "\n\t"
/*
- * Call CopyFileW(nativeSrc, nativeDst, 0)
+ * Call CopyFile(nativeSrc, nativeDst, 0)
*/
- "movl %[copyFileW], %%eax" "\n\t"
+ "movl %[copyFile], %%eax" "\n\t"
"pushl $0" "\n\t"
"pushl %%ebx" "\n\t"
"pushl %%ecx" "\n\t"
@@ -634,7 +638,7 @@ DoCopyFile(
*/
"2:" "\t"
- "movl 0xC(%%edx), %%esp" "\n\t"
+ "movl 0xc(%%edx), %%esp" "\n\t"
"movl 0x8(%%edx), %%ebp" "\n\t"
"movl 0x0(%%edx), %%eax" "\n\t"
"movl %%eax, %%fs:0" "\n\t"
@@ -645,7 +649,7 @@ DoCopyFile(
[registration] "m" (registration),
[nativeDst] "m" (nativeDst),
[nativeSrc] "m" (nativeSrc),
- [copyFileW] "r" (CopyFileW)
+ [copyFile] "r" (tclWinProcs->copyFileProc)
:
"%eax", "%ebx", "%ecx", "%edx", "memory"
);
@@ -656,7 +660,7 @@ DoCopyFile(
#ifndef HAVE_NO_SEH
__try {
#endif
- if (CopyFileW(nativeSrc, nativeDst, 0) != FALSE) {
+ if ((*tclWinProcs->copyFileProc)(nativeSrc, nativeDst, 0) != FALSE) {
retval = TCL_OK;
}
#ifndef HAVE_NO_SEH
@@ -668,7 +672,7 @@ DoCopyFile(
return retval;
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
if (Tcl_GetErrno() == EBADF) {
Tcl_SetErrno(EACCES);
return TCL_ERROR;
@@ -676,10 +680,10 @@ DoCopyFile(
if (Tcl_GetErrno() == EACCES) {
DWORD srcAttr, dstAttr;
- srcAttr = GetFileAttributesW(nativeSrc);
- dstAttr = GetFileAttributesW(nativeDst);
- if (srcAttr != 0xFFFFFFFF) {
- if (dstAttr == 0xFFFFFFFF) {
+ srcAttr = (*tclWinProcs->getFileAttributesProc)(nativeSrc);
+ dstAttr = (*tclWinProcs->getFileAttributesProc)(nativeDst);
+ if (srcAttr != 0xffffffff) {
+ if (dstAttr == 0xffffffff) {
dstAttr = 0;
}
if ((srcAttr & FILE_ATTRIBUTE_DIRECTORY) ||
@@ -693,9 +697,10 @@ DoCopyFile(
Tcl_SetErrno(EISDIR);
}
if (dstAttr & FILE_ATTRIBUTE_READONLY) {
- SetFileAttributesW(nativeDst,
+ (*tclWinProcs->setFileAttributesProc)(nativeDst,
dstAttr & ~((DWORD)FILE_ATTRIBUTE_READONLY));
- if (CopyFileW(nativeSrc, nativeDst, 0) != FALSE) {
+ if ((*tclWinProcs->copyFileProc)(nativeSrc, nativeDst,
+ 0) != FALSE) {
return TCL_OK;
}
@@ -704,8 +709,8 @@ DoCopyFile(
* attributes of dst.
*/
- Tcl_WinConvertError(GetLastError());
- SetFileAttributesW(nativeDst, dstAttr);
+ TclWinConvertError(GetLastError());
+ (*tclWinProcs->setFileAttributesProc)(nativeDst, dstAttr);
}
}
}
@@ -746,35 +751,34 @@ TclpObjDeleteFile(
int
TclpDeleteFile(
- const void *nativePath) /* Pathname of file to be removed (native). */
+ CONST TCHAR *nativePath) /* Pathname of file to be removed (native). */
{
DWORD attr;
- const WCHAR *path = (const WCHAR *)nativePath;
/*
* The DeleteFile API acts differently under Win95/98 and NT WRT NULL and
* "". Avoid passing these values.
*/
- if (path == NULL || path[0] == '\0') {
+ if (nativePath == NULL || nativePath[0] == '\0') {
Tcl_SetErrno(ENOENT);
return TCL_ERROR;
}
- if (DeleteFileW(path) != FALSE) {
+ if ((*tclWinProcs->deleteFileProc)(nativePath) != FALSE) {
return TCL_OK;
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
if (Tcl_GetErrno() == EACCES) {
- attr = GetFileAttributesW(path);
- if (attr != 0xFFFFFFFF) {
+ attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ if (attr != 0xffffffff) {
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
/*
* It is a symbolic link - remove it.
*/
- if (TclWinSymLinkDelete(path, 0) == 0) {
+ if (TclWinSymLinkDelete(nativePath, 0) == 0) {
return TCL_OK;
}
}
@@ -788,21 +792,22 @@ TclpDeleteFile(
Tcl_SetErrno(EISDIR);
} else if (attr & FILE_ATTRIBUTE_READONLY) {
- int res = SetFileAttributesW(path,
- attr & ~((DWORD) FILE_ATTRIBUTE_READONLY));
+ int res = (*tclWinProcs->setFileAttributesProc)(nativePath,
+ attr & ~((DWORD)FILE_ATTRIBUTE_READONLY));
- if ((res != 0) && (DeleteFileW(path) != FALSE)) {
+ if ((res != 0) && ((*tclWinProcs->deleteFileProc)(nativePath)
+ != FALSE)) {
return TCL_OK;
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
if (res != 0) {
- SetFileAttributesW(path, attr);
+ (*tclWinProcs->setFileAttributesProc)(nativePath, attr);
}
}
}
} else if (Tcl_GetErrno() == ENOENT) {
- attr = GetFileAttributesW(path);
- if (attr != 0xFFFFFFFF) {
+ attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ if (attr != 0xffffffff) {
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
/*
* Windows 95 reports removing a directory as ENOENT instead
@@ -853,17 +858,17 @@ int
TclpObjCreateDirectory(
Tcl_Obj *pathPtr)
{
- return DoCreateDirectory((const WCHAR *)Tcl_FSGetNativePath(pathPtr));
+ return DoCreateDirectory(Tcl_FSGetNativePath(pathPtr));
}
static int
DoCreateDirectory(
- const WCHAR *nativePath) /* Pathname of directory to create (native). */
+ CONST TCHAR *nativePath) /* Pathname of directory to create (native). */
{
- if (CreateDirectoryW(nativePath, NULL) == 0) {
- DWORD error = GetLastError();
-
- Tcl_WinConvertError(error);
+ DWORD error;
+ if ((*tclWinProcs->createDirectoryProc)(nativePath, NULL) == 0) {
+ error = GetLastError();
+ TclWinConvertError(error);
return TCL_ERROR;
}
return TCL_OK;
@@ -876,7 +881,7 @@ DoCreateDirectory(
*
* Recursively copies a directory. The target directory dst must not
* already exist. Note that this function does not merge two directory
- * hierarchies, even if the target directory is an empty directory.
+ * hierarchies, even if the target directory is an an empty directory.
*
* Results:
* If the directory was successfully copied, returns TCL_OK. Otherwise
@@ -910,10 +915,8 @@ TclpObjCopyDirectory(
return TCL_ERROR;
}
- Tcl_DStringInit(&srcString);
- Tcl_DStringInit(&dstString);
- Tcl_UtfToWCharDString(TclGetString(normSrcPtr), TCL_INDEX_NONE, &srcString);
- Tcl_UtfToWCharDString(TclGetString(normDestPtr), TCL_INDEX_NONE, &dstString);
+ Tcl_WinUtfToTChar(Tcl_GetString(normSrcPtr), -1, &srcString);
+ Tcl_WinUtfToTChar(Tcl_GetString(normDestPtr), -1, &dstString);
ret = TraverseWinTree(TraversalCopy, &srcString, &dstString, &ds);
@@ -926,7 +929,7 @@ TclpObjCopyDirectory(
} else if (!strcmp(Tcl_DStringValue(&ds), TclGetString(normDestPtr))) {
*errorPtr = destPathPtr;
} else {
- *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), TCL_INDEX_NONE);
+ *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
}
Tcl_DStringFree(&ds);
Tcl_IncrRefCount(*errorPtr);
@@ -985,21 +988,21 @@ TclpObjRemoveDirectory(
if (normPtr == NULL) {
return TCL_ERROR;
}
- Tcl_DStringInit(&native);
- Tcl_UtfToWCharDString(TclGetString(normPtr), TCL_INDEX_NONE, &native);
+ Tcl_WinUtfToTChar(Tcl_GetString(normPtr), -1, &native);
ret = DoRemoveDirectory(&native, recursive, &ds);
Tcl_DStringFree(&native);
} else {
- ret = DoRemoveJustDirectory((const WCHAR *)Tcl_FSGetNativePath(pathPtr), 0, &ds);
+ ret = DoRemoveJustDirectory(Tcl_FSGetNativePath(pathPtr), 0, &ds);
}
if (ret != TCL_OK) {
- if (Tcl_DStringLength(&ds) > 0) {
+ int len = Tcl_DStringLength(&ds);
+ if (len > 0) {
if (normPtr != NULL &&
!strcmp(Tcl_DStringValue(&ds), TclGetString(normPtr))) {
*errorPtr = pathPtr;
} else {
- *errorPtr = Tcl_DStringToObj(&ds);
+ *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
}
Tcl_IncrRefCount(*errorPtr);
}
@@ -1011,7 +1014,7 @@ TclpObjRemoveDirectory(
static int
DoRemoveJustDirectory(
- const WCHAR *nativePath, /* Pathname of directory to be removed
+ CONST TCHAR *nativePath, /* Pathname of directory to be removed
* (native). */
int ignoreError, /* If non-zero, don't initialize the errorPtr
* under some circumstances on return. */
@@ -1028,11 +1031,10 @@ DoRemoveJustDirectory(
if (nativePath == NULL || nativePath[0] == '\0') {
Tcl_SetErrno(ENOENT);
- Tcl_DStringInit(errorPtr);
- return TCL_ERROR;
+ goto end;
}
- attr = GetFileAttributesW(nativePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
/*
@@ -1046,16 +1048,16 @@ DoRemoveJustDirectory(
* Ordinary directory.
*/
- if (RemoveDirectoryW(nativePath) != FALSE) {
+ if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) {
return TCL_OK;
}
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
if (Tcl_GetErrno() == EACCES) {
- attr = GetFileAttributesW(nativePath);
- if (attr != 0xFFFFFFFF) {
+ attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ if (attr != 0xffffffff) {
if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
/*
* Windows 95 reports calling RemoveDirectory on a file as an
@@ -1078,16 +1080,60 @@ DoRemoveJustDirectory(
if (attr & FILE_ATTRIBUTE_READONLY) {
attr &= ~FILE_ATTRIBUTE_READONLY;
- if (SetFileAttributesW(nativePath, attr) == FALSE) {
+ if ((*tclWinProcs->setFileAttributesProc)(nativePath,
+ attr) == FALSE) {
goto end;
}
- if (RemoveDirectoryW(nativePath) != FALSE) {
+ if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) {
return TCL_OK;
}
- Tcl_WinConvertError(GetLastError());
- SetFileAttributesW(nativePath,
+ TclWinConvertError(GetLastError());
+ (*tclWinProcs->setFileAttributesProc)(nativePath,
attr | FILE_ATTRIBUTE_READONLY);
}
+
+ /*
+ * Windows 95 and Win32s report removing a non-empty directory as
+ * EACCES, not EEXIST. If the directory is not empty, change errno
+ * so caller knows what's going on.
+ */
+
+ if (TclWinGetPlatformId() != VER_PLATFORM_WIN32_NT) {
+ CONST char *path, *find;
+ HANDLE handle;
+ WIN32_FIND_DATAA data;
+ Tcl_DString buffer;
+ int len;
+
+ path = (CONST char *) nativePath;
+
+ Tcl_DStringInit(&buffer);
+ len = strlen(path);
+ find = Tcl_DStringAppend(&buffer, path, len);
+ if ((len > 0) && (find[len - 1] != '\\')) {
+ Tcl_DStringAppend(&buffer, "\\", 1);
+ }
+ find = Tcl_DStringAppend(&buffer, "*.*", 3);
+ handle = FindFirstFileA(find, &data);
+ if (handle != INVALID_HANDLE_VALUE) {
+ while (1) {
+ if ((strcmp(data.cFileName, ".") != 0)
+ && (strcmp(data.cFileName, "..") != 0)) {
+ /*
+ * Found something in this directory.
+ */
+
+ Tcl_SetErrno(EEXIST);
+ break;
+ }
+ if (FindNextFileA(handle, &data) == FALSE) {
+ break;
+ }
+ }
+ FindClose(handle);
+ }
+ Tcl_DStringFree(&buffer);
+ }
}
}
@@ -1111,13 +1157,10 @@ DoRemoveJustDirectory(
end:
if (errorPtr != NULL) {
char *p;
-
- Tcl_DStringInit(errorPtr);
- p = Tcl_WCharToUtfDString(nativePath, TCL_INDEX_NONE, errorPtr);
+ Tcl_WinTCharToUtf(nativePath, -1, errorPtr);
+ p = Tcl_DStringValue(errorPtr);
for (; *p; ++p) {
- if (*p == '\\') {
- *p = '/';
- }
+ if (*p == '\\') *p = '/';
}
}
return TCL_ERROR;
@@ -1135,7 +1178,7 @@ DoRemoveDirectory(
* filled with UTF-8 name of file causing
* error. */
{
- int res = DoRemoveJustDirectory((const WCHAR *)Tcl_DStringValue(pathPtr), recursive,
+ int res = DoRemoveJustDirectory(Tcl_DStringValue(pathPtr), recursive,
errorPtr);
if ((res == TCL_ERROR) && (recursive != 0) && (Tcl_GetErrno() == EEXIST)) {
@@ -1186,22 +1229,22 @@ TraverseWinTree(
* error. */
{
DWORD sourceAttr;
- WCHAR *nativeSource, *nativeTarget, *nativeErrfile;
+ TCHAR *nativeSource, *nativeTarget, *nativeErrfile;
int result, found, sourceLen, targetLen = 0, oldSourceLen, oldTargetLen;
HANDLE handle;
- WIN32_FIND_DATAW data;
+ WIN32_FIND_DATAT data;
nativeErrfile = NULL;
result = TCL_OK;
- oldTargetLen = 0;
+ oldTargetLen = 0; /* lint. */
- nativeSource = (WCHAR *) Tcl_DStringValue(sourcePtr);
- nativeTarget = (WCHAR *)
+ nativeSource = (TCHAR *) Tcl_DStringValue(sourcePtr);
+ nativeTarget = (TCHAR *)
(targetPtr == NULL ? NULL : Tcl_DStringValue(targetPtr));
oldSourceLen = Tcl_DStringLength(sourcePtr);
- sourceAttr = GetFileAttributesW(nativeSource);
- if (sourceAttr == 0xFFFFFFFF) {
+ sourceAttr = (*tclWinProcs->getFileAttributesProc)(nativeSource);
+ if (sourceAttr == 0xffffffff) {
nativeErrfile = nativeSource;
goto end;
}
@@ -1211,7 +1254,7 @@ TraverseWinTree(
* Process the symbolic link
*/
- return traverseProc(nativeSource, nativeTarget, DOTREE_LINK,
+ return (*traverseProc)(nativeSource, nativeTarget, DOTREE_LINK,
errorPtr);
}
@@ -1220,62 +1263,89 @@ TraverseWinTree(
* Process the regular file
*/
- return traverseProc(nativeSource, nativeTarget, DOTREE_F, errorPtr);
+ return (*traverseProc)(nativeSource, nativeTarget, DOTREE_F, errorPtr);
}
- Tcl_DStringAppend(sourcePtr, (char *) L"\\*.*", 4 * sizeof(WCHAR) + 1);
- Tcl_DStringSetLength(sourcePtr, Tcl_DStringLength(sourcePtr) - 1);
+ if (tclWinProcs->useWide) {
+ Tcl_DStringAppend(sourcePtr, (char *) L"\\*.*", 4 * sizeof(WCHAR) + 1);
+ Tcl_DStringSetLength(sourcePtr, Tcl_DStringLength(sourcePtr) - 1);
+ } else {
+ Tcl_DStringAppend(sourcePtr, "\\*.*", 4);
+ }
- nativeSource = (WCHAR *) Tcl_DStringValue(sourcePtr);
- handle = FindFirstFileW(nativeSource, &data);
+ nativeSource = (TCHAR *) Tcl_DStringValue(sourcePtr);
+ handle = (*tclWinProcs->findFirstFileProc)(nativeSource, &data);
if (handle == INVALID_HANDLE_VALUE) {
/*
* Can't read directory.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
nativeErrfile = nativeSource;
goto end;
}
- Tcl_DStringSetLength(sourcePtr, oldSourceLen + 1);
+ nativeSource[oldSourceLen + 1] = '\0';
Tcl_DStringSetLength(sourcePtr, oldSourceLen);
- result = traverseProc(nativeSource, nativeTarget, DOTREE_PRED,
+ result = (*traverseProc)(nativeSource, nativeTarget, DOTREE_PRED,
errorPtr);
if (result != TCL_OK) {
FindClose(handle);
return result;
}
- sourceLen = oldSourceLen + sizeof(WCHAR);
- Tcl_DStringAppend(sourcePtr, (char *) L"\\", sizeof(WCHAR) + 1);
- Tcl_DStringSetLength(sourcePtr, sourceLen);
+ sourceLen = oldSourceLen;
+
+ if (tclWinProcs->useWide) {
+ sourceLen += sizeof(WCHAR);
+ Tcl_DStringAppend(sourcePtr, (char *) L"\\", sizeof(WCHAR) + 1);
+ Tcl_DStringSetLength(sourcePtr, sourceLen);
+ } else {
+ sourceLen += 1;
+ Tcl_DStringAppend(sourcePtr, "\\", 1);
+ }
if (targetPtr != NULL) {
oldTargetLen = Tcl_DStringLength(targetPtr);
targetLen = oldTargetLen;
- targetLen += sizeof(WCHAR);
- Tcl_DStringAppend(targetPtr, (char *) L"\\", sizeof(WCHAR) + 1);
- Tcl_DStringSetLength(targetPtr, targetLen);
+ if (tclWinProcs->useWide) {
+ targetLen += sizeof(WCHAR);
+ Tcl_DStringAppend(targetPtr, (char *) L"\\", sizeof(WCHAR) + 1);
+ Tcl_DStringSetLength(targetPtr, targetLen);
+ } else {
+ targetLen += 1;
+ Tcl_DStringAppend(targetPtr, "\\", 1);
+ }
}
found = 1;
- for (; found; found = FindNextFileW(handle, &data)) {
- WCHAR *nativeName;
+ for (; found; found = (*tclWinProcs->findNextFileProc)(handle, &data)) {
+ TCHAR *nativeName;
int len;
- WCHAR *wp = data.cFileName;
- if (*wp == '.') {
- wp++;
+ if (tclWinProcs->useWide) {
+ WCHAR *wp;
+
+ wp = data.w.cFileName;
if (*wp == '.') {
wp++;
+ if (*wp == '.') {
+ wp++;
+ }
+ if (*wp == '\0') {
+ continue;
+ }
}
- if (*wp == '\0') {
+ nativeName = (TCHAR *) data.w.cFileName;
+ len = wcslen(data.w.cFileName) * sizeof(WCHAR);
+ } else {
+ if ((strcmp(data.a.cFileName, ".") == 0)
+ || (strcmp(data.a.cFileName, "..") == 0)) {
continue;
}
+ nativeName = (TCHAR *) data.a.cFileName;
+ len = strlen(data.a.cFileName);
}
- nativeName = (WCHAR *) data.cFileName;
- len = wcslen(data.cFileName) * sizeof(WCHAR);
/*
* Append name after slash, and recurse on the file.
@@ -1320,17 +1390,16 @@ TraverseWinTree(
* files in that directory.
*/
- result = traverseProc((const WCHAR *)Tcl_DStringValue(sourcePtr),
- (const WCHAR *)(targetPtr == NULL ? NULL : Tcl_DStringValue(targetPtr)),
+ result = (*traverseProc)(Tcl_DStringValue(sourcePtr),
+ (targetPtr == NULL ? NULL : Tcl_DStringValue(targetPtr)),
DOTREE_POSTD, errorPtr);
}
end:
if (nativeErrfile != NULL) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
if (errorPtr != NULL) {
- Tcl_DStringInit(errorPtr);
- Tcl_WCharToUtfDString(nativeErrfile, TCL_INDEX_NONE, errorPtr);
+ Tcl_WinTCharToUtf(nativeErrfile, -1, errorPtr);
}
result = TCL_ERROR;
}
@@ -1357,8 +1426,8 @@ TraverseWinTree(
static int
TraversalCopy(
- const WCHAR *nativeSrc, /* Source pathname to copy. */
- const WCHAR *nativeDst, /* Destination pathname of copy. */
+ CONST TCHAR *nativeSrc, /* Source pathname to copy. */
+ CONST TCHAR *nativeDst, /* Destination pathname of copy. */
int type, /* Reason for call - see TraverseWinTree() */
Tcl_DString *errorPtr) /* If non-NULL, initialized DString filled
* with UTF-8 name of file causing error. */
@@ -1376,12 +1445,13 @@ TraversalCopy(
break;
case DOTREE_PRED:
if (DoCreateDirectory(nativeDst) == TCL_OK) {
- DWORD attr = GetFileAttributesW(nativeSrc);
+ DWORD attr = (tclWinProcs->getFileAttributesProc)(nativeSrc);
- if (SetFileAttributesW(nativeDst, attr) != FALSE) {
+ if ((tclWinProcs->setFileAttributesProc)(nativeDst,
+ attr) != FALSE) {
return TCL_OK;
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
}
break;
case DOTREE_POSTD:
@@ -1394,8 +1464,7 @@ TraversalCopy(
*/
if (errorPtr != NULL) {
- Tcl_DStringInit(errorPtr);
- Tcl_WCharToUtfDString(nativeDst, TCL_INDEX_NONE, errorPtr);
+ Tcl_WinTCharToUtf(nativeDst, -1, errorPtr);
}
return TCL_ERROR;
}
@@ -1423,8 +1492,8 @@ TraversalCopy(
static int
TraversalDelete(
- const WCHAR *nativeSrc, /* Source pathname to delete. */
- TCL_UNUSED(const WCHAR *) /*dstPtr*/,
+ CONST TCHAR *nativeSrc, /* Source pathname to delete. */
+ CONST TCHAR *dstPtr, /* Not used. */
int type, /* Reason for call - see TraverseWinTree() */
Tcl_DString *errorPtr) /* If non-NULL, initialized DString filled
* with UTF-8 name of file causing error. */
@@ -1450,8 +1519,7 @@ TraversalDelete(
}
if (errorPtr != NULL) {
- Tcl_DStringInit(errorPtr);
- Tcl_WCharToUtfDString(nativeSrc, TCL_INDEX_NONE, errorPtr);
+ Tcl_WinTCharToUtf(nativeSrc, -1, errorPtr);
}
return TCL_ERROR;
}
@@ -1479,9 +1547,9 @@ StatError(
Tcl_Obj *fileName) /* The name of the file which caused the
* error. */
{
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not read \"%s\": %s",
- TclGetString(fileName), Tcl_PosixError(interp)));
+ TclWinConvertError(GetLastError());
+ Tcl_AppendResult(interp, "could not read \"", TclGetString(fileName),
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
}
/*
@@ -1511,13 +1579,13 @@ GetWinFileAttributes(
Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */
{
DWORD result;
- const WCHAR *nativeName;
+ CONST TCHAR *nativeName;
int attr;
- nativeName = (const WCHAR *)Tcl_FSGetNativePath(fileName);
- result = GetFileAttributesW(nativeName);
+ nativeName = Tcl_FSGetNativePath(fileName);
+ result = (*tclWinProcs->getFileAttributesProc)(nativeName);
- if (result == 0xFFFFFFFF) {
+ if (result == 0xffffffff) {
StatError(interp, fileName);
return TCL_ERROR;
}
@@ -1532,8 +1600,8 @@ GetWinFileAttributes(
* We test for, and fix that case, here.
*/
- Tcl_Size len;
- const char *str = TclGetStringFromObj(fileName, &len);
+ int len;
+ char *str = Tcl_GetStringFromObj(fileName,&len);
if (len < 4) {
if (len == 0) {
@@ -1557,7 +1625,7 @@ GetWinFileAttributes(
}
}
- TclNewIntObj(*attributePtrPtr, attr != 0);
+ *attributePtrPtr = Tcl_NewBooleanObj(attr);
return TCL_OK;
}
@@ -1587,23 +1655,21 @@ GetWinFileAttributes(
static int
ConvertFileNameFormat(
Tcl_Interp *interp, /* The interp we are using for errors. */
- TCL_UNUSED(int) /*objIndex*/,
+ int objIndex, /* The index of the attribute. */
Tcl_Obj *fileName, /* The name of the file. */
int longShort, /* 0 to short name, 1 to long name. */
Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */
{
- Tcl_Size pathc, i, length;
+ int pathc, i;
Tcl_Obj *splitPath;
splitPath = Tcl_FSSplitPath(fileName, &pathc);
if (splitPath == NULL || pathc == 0) {
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "could not read \"%s\": no such file or directory",
- TclGetString(fileName)));
- errno = ENOENT;
- Tcl_PosixError(interp);
+ Tcl_AppendResult(interp, "could not read \"",
+ Tcl_GetString(fileName), "\": no such file or directory",
+ (char *) NULL);
}
goto cleanup;
}
@@ -1618,11 +1684,12 @@ ConvertFileNameFormat(
for (i = 0; i < pathc; i++) {
Tcl_Obj *elt;
char *pathv;
+ int pathLen;
Tcl_ListObjIndex(NULL, splitPath, i, &elt);
- pathv = TclGetStringFromObj(elt, &length);
- if ((pathv[0] == '/') || ((length == 3) && (pathv[1] == ':'))
+ pathv = Tcl_GetStringFromObj(elt, &pathLen);
+ if ((pathv[0] == '/') || ((pathLen == 3) && (pathv[1] == ':'))
|| (strcmp(pathv, ".") == 0) || (strcmp(pathv, "..") == 0)) {
/*
* Handle "/", "//machine/export", "c:/", "." or ".." by just
@@ -1643,9 +1710,10 @@ ConvertFileNameFormat(
Tcl_Obj *tempPath;
Tcl_DString ds;
Tcl_DString dsTemp;
- const WCHAR *nativeName;
- const char *tempString;
- WIN32_FIND_DATAW data;
+ TCHAR *nativeName;
+ char *tempString;
+ int tempLen;
+ WIN32_FIND_DATAT data;
HANDLE handle;
DWORD attr;
@@ -1657,20 +1725,20 @@ ConvertFileNameFormat(
* likely to lead to infinite loops.
*/
- tempString = TclGetStringFromObj(tempPath, &length);
Tcl_DStringInit(&ds);
- nativeName = Tcl_UtfToWCharDString(tempString, length, &ds);
+ tempString = Tcl_GetStringFromObj(tempPath,&tempLen);
+ nativeName = Tcl_WinUtfToTChar(tempString, tempLen, &ds);
Tcl_DecrRefCount(tempPath);
- handle = FindFirstFileW(nativeName, &data);
+ handle = (*tclWinProcs->findFirstFileProc)(nativeName, &data);
if (handle == INVALID_HANDLE_VALUE) {
/*
- * FindFirstFileW() doesn't like root directories. We would
+ * FindFirstFile() doesn't like root directories. We would
* only get a root directory here if the caller specified "c:"
* or "c:." and the current directory on the drive was the
* root directory
*/
- attr = GetFileAttributesW(nativeName);
+ attr = (*tclWinProcs->getFileAttributesProc)(nativeName);
if ((attr!=0xFFFFFFFF) && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
Tcl_DStringFree(&ds);
goto simple;
@@ -1684,19 +1752,32 @@ ConvertFileNameFormat(
}
goto cleanup;
}
- nativeName = data.cAlternateFileName;
- if (longShort) {
- if (data.cFileName[0] != '\0') {
- nativeName = data.cFileName;
+ if (tclWinProcs->useWide) {
+ nativeName = (TCHAR *) data.w.cAlternateFileName;
+ if (longShort) {
+ if (data.w.cFileName[0] != '\0') {
+ nativeName = (TCHAR *) data.w.cFileName;
+ }
+ } else {
+ if (data.w.cAlternateFileName[0] == '\0') {
+ nativeName = (TCHAR *) data.w.cFileName;
+ }
}
} else {
- if (data.cAlternateFileName[0] == '\0') {
- nativeName = (WCHAR *) data.cFileName;
+ nativeName = (TCHAR *) data.a.cAlternateFileName;
+ if (longShort) {
+ if (data.a.cFileName[0] != '\0') {
+ nativeName = (TCHAR *) data.a.cFileName;
+ }
+ } else {
+ if (data.a.cAlternateFileName[0] == '\0') {
+ nativeName = (TCHAR *) data.a.cFileName;
+ }
}
}
/*
- * Purify reports a extraneous UMR in Tcl_WCharToUtfDString() trying
+ * Purify reports a extraneous UMR in Tcl_WinTCharToUtf() trying
* to dereference nativeName as a Unicode string. I have proven to
* myself that purify is wrong by running the following example
* when nativeName == data.w.cAlternateFileName and noting that
@@ -1708,27 +1789,28 @@ ConvertFileNameFormat(
*/
Tcl_DStringInit(&dsTemp);
- Tcl_WCharToUtfDString(nativeName, TCL_INDEX_NONE, &dsTemp);
- Tcl_DStringFree(&ds);
+ Tcl_WinTCharToUtf(nativeName, -1, &dsTemp);
/*
* Deal with issues of tildes being absolute.
*/
if (Tcl_DStringValue(&dsTemp)[0] == '~') {
- TclNewLiteralStringObj(tempPath, "./");
+ tempPath = Tcl_NewStringObj("./",2);
Tcl_AppendToObj(tempPath, Tcl_DStringValue(&dsTemp),
Tcl_DStringLength(&dsTemp));
- Tcl_DStringFree(&dsTemp);
} else {
- tempPath = Tcl_DStringToObj(&dsTemp);
+ tempPath = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp),
+ Tcl_DStringLength(&dsTemp));
}
Tcl_ListObjReplace(NULL, splitPath, i, 1, 1, &tempPath);
+ Tcl_DStringFree(&ds);
+ Tcl_DStringFree(&dsTemp);
FindClose(handle);
}
}
- *attributePtrPtr = Tcl_FSJoinPath(splitPath, TCL_INDEX_NONE);
+ *attributePtrPtr = Tcl_FSJoinPath(splitPath, -1);
if (splitPath != NULL) {
/*
@@ -1835,14 +1917,15 @@ SetWinFileAttributes(
Tcl_Obj *fileName, /* The name of the file. */
Tcl_Obj *attributePtr) /* The new value of the attribute. */
{
- DWORD fileAttributes, old;
- int yesNo, result;
- const WCHAR *nativeName;
+ DWORD fileAttributes;
+ int yesNo;
+ int result;
+ CONST TCHAR *nativeName;
- nativeName = (const WCHAR *)Tcl_FSGetNativePath(fileName);
- fileAttributes = old = GetFileAttributesW(nativeName);
+ nativeName = Tcl_FSGetNativePath(fileName);
+ fileAttributes = (*tclWinProcs->getFileAttributesProc)(nativeName);
- if (fileAttributes == 0xFFFFFFFF) {
+ if (fileAttributes == 0xffffffff) {
StatError(interp, fileName);
return TCL_ERROR;
}
@@ -1858,8 +1941,7 @@ SetWinFileAttributes(
fileAttributes &= ~(attributeArray[objIndex]);
}
- if ((fileAttributes != old)
- && !SetFileAttributesW(nativeName, fileAttributes)) {
+ if (!(*tclWinProcs->setFileAttributesProc)(nativeName, fileAttributes)) {
StatError(interp, fileName);
return TCL_ERROR;
}
@@ -1888,15 +1970,15 @@ CannotSetAttribute(
Tcl_Interp *interp, /* The interp we are using for errors. */
int objIndex, /* The index of the attribute. */
Tcl_Obj *fileName, /* The name of the file. */
- TCL_UNUSED(Tcl_Obj *) /*attributePtr*/)
+ Tcl_Obj *attributePtr) /* The new value of the attribute. */
{
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "cannot set attribute \"%s\" for file \"%s\": attribute is readonly",
- tclpFileAttrStrings[objIndex], TclGetString(fileName)));
- errno = EINVAL;
- Tcl_PosixError(interp);
+ Tcl_AppendResult(interp, "cannot set attribute \"",
+ tclpFileAttrStrings[objIndex], "\" for file \"",
+ Tcl_GetString(fileName), "\": attribute is readonly",
+ (char *) NULL);
return TCL_ERROR;
}
+
/*
*---------------------------------------------------------------------------
@@ -1914,7 +1996,7 @@ CannotSetAttribute(
*---------------------------------------------------------------------------
*/
-Tcl_Obj *
+Tcl_Obj*
TclpObjListVolumes(void)
{
Tcl_Obj *resultPtr, *elemPtr;
@@ -1922,7 +2004,7 @@ TclpObjListVolumes(void)
int i;
char *p;
- TclNewObj(resultPtr);
+ resultPtr = Tcl_NewObj();
/*
* On Win32s:
@@ -1932,10 +2014,10 @@ TclpObjListVolumes(void)
if (GetLogicalDriveStringsA(sizeof(buf), buf) == 0) {
/*
- * GetVolumeInformationW() will detects all drives, but causes
+ * GetVolumeInformation() will detects all drives, but causes
* chattering on empty floppy drives. We only do this if
* GetLogicalDriveStrings() didn't work. It has also been reported
- * that on some laptops it takes a while for GetVolumeInformationW() to
+ * that on some laptops it takes a while for GetVolumeInformation() to
* return when pinging an empty floppy drive, another reason to try to
* avoid calling it.
*/
@@ -1948,14 +2030,14 @@ TclpObjListVolumes(void)
buf[0] = (char) ('a' + i);
if (GetVolumeInformationA(buf, NULL, 0, NULL, NULL, NULL, NULL, 0)
|| (GetLastError() == ERROR_NOT_READY)) {
- elemPtr = Tcl_NewStringObj(buf, TCL_INDEX_NONE);
+ elemPtr = Tcl_NewStringObj(buf, -1);
Tcl_ListObjAppendElement(NULL, resultPtr, elemPtr);
}
}
} else {
for (p = buf; *p != '\0'; p += 4) {
p[2] = '/';
- elemPtr = Tcl_NewStringObj(p, TCL_INDEX_NONE);
+ elemPtr = Tcl_NewStringObj(p, -1);
Tcl_ListObjAppendElement(NULL, resultPtr, elemPtr);
}
}
@@ -1965,121 +2047,6 @@ TclpObjListVolumes(void)
}
/*
- *----------------------------------------------------------------------
- *
- * TclpCreateTemporaryDirectory --
- *
- * Creates a temporary directory, possibly based on the supplied bits and
- * pieces of template supplied in the arguments.
- *
- * Results:
- * An object (refcount 0) containing the name of the newly-created
- * directory, or NULL on failure.
- *
- * Side effects:
- * Accesses the native filesystem. Makes a directory.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Obj *
-TclpCreateTemporaryDirectory(
- Tcl_Obj *dirObj,
- Tcl_Obj *basenameObj)
-{
- Tcl_DString base, name; /* Contains WCHARs */
- int baseLen;
- DWORD error;
- WCHAR tempBuf[MAX_PATH + 1];
- DWORD len = GetTempPathW(MAX_PATH, tempBuf);
-
- /*
- * Build the path in writable memory from the user-supplied pieces and
- * some defaults. First, the parent temporary directory.
- */
-
- if (dirObj) {
- TclGetString(dirObj);
- if (dirObj->length < 1) {
- goto useSystemTemp;
- }
- Tcl_DStringInit(&base);
- Tcl_UtfToWCharDString(TclGetString(dirObj), TCL_INDEX_NONE, &base);
- if (dirObj->bytes[dirObj->length - 1] != '\\') {
- Tcl_UtfToWCharDString("\\", TCL_INDEX_NONE, &base);
- }
- } else {
- useSystemTemp:
- Tcl_DStringInit(&base);
- Tcl_DStringAppend(&base, (char *) tempBuf, len * sizeof(WCHAR));
- }
-
- /*
- * Next, the base of the directory name.
- */
-
-#define DEFAULT_TEMP_DIR_PREFIX "tcl"
-#define SUFFIX_LENGTH 8
-
- if (basenameObj) {
- Tcl_UtfToWCharDString(TclGetString(basenameObj), TCL_INDEX_NONE, &base);
- } else {
- Tcl_UtfToWCharDString(DEFAULT_TEMP_DIR_PREFIX, TCL_INDEX_NONE, &base);
- }
- Tcl_UtfToWCharDString("_", TCL_INDEX_NONE, &base);
-
- /*
- * Now we keep on trying random suffixes until we get one that works
- * (i.e., that doesn't trigger the ERROR_ALREADY_EXISTS error). Note that
- * SUFFIX_LENGTH is longer than on Unix because we expect to be not on a
- * case-sensitive filesystem.
- */
-
- baseLen = Tcl_DStringLength(&base);
- do {
- char tempbuf[SUFFIX_LENGTH + 1];
- int i;
- static const char randChars[] =
- "QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
- static const int numRandChars = sizeof(randChars) - 1;
-
- /*
- * Put a random suffix on the end.
- */
-
- error = ERROR_SUCCESS;
- tempbuf[SUFFIX_LENGTH] = '\0';
- for (i = 0 ; i < SUFFIX_LENGTH; i++) {
- tempbuf[i] = randChars[(int) (rand() % numRandChars)];
- }
- Tcl_DStringSetLength(&base, baseLen);
- Tcl_UtfToWCharDString(tempbuf, TCL_INDEX_NONE, &base);
- } while (!CreateDirectoryW((LPCWSTR) Tcl_DStringValue(&base), NULL)
- && (error = GetLastError()) == ERROR_ALREADY_EXISTS);
-
- /*
- * Check for other errors. The big ones are ERROR_PATH_NOT_FOUND and
- * ERROR_ACCESS_DENIED.
- */
-
- if (error != ERROR_SUCCESS) {
- Tcl_WinConvertError(error);
- Tcl_DStringFree(&base);
- return NULL;
- }
-
- /*
- * We actually made the directory, so we're done! Report what we made back
- * as a (clean) Tcl_Obj.
- */
-
- Tcl_DStringInit(&name);
- Tcl_WCharToUtfDString((LPCWSTR) Tcl_DStringValue(&base), TCL_INDEX_NONE, &name);
- Tcl_DStringFree(&base);
- return Tcl_DStringToObj(&name);
-}
-
-/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff --git a/win/tclWinFile.c b/win/tclWinFile.c
index b27487f..41de4a8 100644..100755
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -6,7 +6,7 @@
* files, which can be manipulated through the Win32 console redirection
* interfaces.
*
- * Copyright © 1995-1998 Sun Microsystems, Inc.
+ * Copyright (c) 1995-1998 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -16,20 +16,16 @@
#include "tclFileSystem.h"
#include <winioctl.h>
#include <shlobj.h>
-#include <lm.h> /* For TclpGetUserHome(). */
+#include <lmaccess.h> /* For TclpGetUserHome(). */
#include <userenv.h> /* For TclpGetUserHome(). */
-#include <aclapi.h> /* For GetNamedSecurityInfo */
-#ifdef _MSC_VER
-# pragma comment(lib, "userenv.lib")
-#endif
/*
* The number of 100-ns intervals between the Windows system epoch (1601-01-01
* on the proleptic Gregorian calendar) and the Posix epoch (1970-01-01).
*/
#define POSIX_EPOCH_AS_FILETIME \
- ((long long) 116444736 * (long long) 1000000000)
+ ((Tcl_WideInt) 116444736 * (Tcl_WideInt) 1000000000)
/*
* Declarations for 'link' related information. This information should come
@@ -145,39 +141,72 @@ typedef struct {
WCHAR dummyBuf[MAX_PATH * 3];
} DUMMY_REPARSE_BUFFER;
+#if defined(_MSC_VER) && (_MSC_VER <= 1100)
+#undef HAVE_NO_FINDEX_ENUMS
+#define HAVE_NO_FINDEX_ENUMS
+#elif !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0400)
+#undef HAVE_NO_FINDEX_ENUMS
+#define HAVE_NO_FINDEX_ENUMS
+#endif
+
+#ifdef HAVE_NO_FINDEX_ENUMS
+/* These two aren't in VC++ 5.2 headers */
+typedef enum _FINDEX_INFO_LEVELS {
+ FindExInfoStandard,
+ FindExInfoMaxInfoLevel
+} FINDEX_INFO_LEVELS;
+typedef enum _FINDEX_SEARCH_OPS {
+ FindExSearchNameMatch,
+ FindExSearchLimitToDirectories,
+ FindExSearchLimitToDevices,
+ FindExSearchMaxSearchOp
+} FINDEX_SEARCH_OPS;
+#endif /* HAVE_NO_FINDEX_ENUMS */
+
/*
* Other typedefs required by this code.
*/
-static __time64_t ToCTime(FILETIME fileTime);
-static void FromCTime(__time64_t posixTime, FILETIME *fileTime);
+static time_t ToCTime(FILETIME fileTime);
+static void FromCTime(time_t posixTime, FILETIME *fileTime);
+
+typedef NET_API_STATUS NET_API_FUNCTION NETUSERGETINFOPROC(
+ LPWSTR servername, LPWSTR username, DWORD level, LPBYTE *bufptr);
+
+typedef NET_API_STATUS NET_API_FUNCTION NETAPIBUFFERFREEPROC(LPVOID Buffer);
+
+typedef NET_API_STATUS NET_API_FUNCTION NETGETDCNAMEPROC(
+ LPWSTR servername, LPWSTR domainname, LPBYTE *bufptr);
+
+typedef BOOL WINAPI GETPROFILESDIRECTORYPROC(
+ LPWSTR lpProfilesDir, LPDWORD lpcchSize
+);
/*
* Declarations for local functions defined in this file:
*/
-static int NativeAccess(const WCHAR *path, int mode);
-static int NativeDev(const WCHAR *path);
-static int NativeStat(const WCHAR *path, Tcl_StatBuf *statPtr,
+static int NativeAccess(const TCHAR *path, int mode);
+static int NativeDev(const TCHAR *path);
+static int NativeStat(const TCHAR *path, Tcl_StatBuf *statPtr,
int checkLinks);
static unsigned short NativeStatMode(DWORD attr, int checkLinks,
int isExec);
-static int NativeIsExec(const WCHAR *path);
-static int NativeReadReparse(const WCHAR *LinkDirectory,
+static int NativeIsExec(const TCHAR *path);
+static int NativeReadReparse(const TCHAR *LinkDirectory,
REPARSE_DATA_BUFFER *buffer, DWORD desiredAccess);
-static int NativeWriteReparse(const WCHAR *LinkDirectory,
+static int NativeWriteReparse(const TCHAR *LinkDirectory,
REPARSE_DATA_BUFFER *buffer);
static int NativeMatchType(int isDrive, DWORD attr,
- const WCHAR *nativeName, Tcl_GlobTypeData *types);
-static int WinIsDrive(const char *name, size_t nameLen);
-static size_t WinIsReserved(const char *path);
-static Tcl_Obj * WinReadLink(const WCHAR *LinkSource);
-static Tcl_Obj * WinReadLinkDirectory(const WCHAR *LinkDirectory);
-static int WinLink(const WCHAR *LinkSource,
- const WCHAR *LinkTarget, int linkAction);
-static int WinSymLinkDirectory(const WCHAR *LinkDirectory,
- const WCHAR *LinkTarget);
-MODULE_SCOPE TCL_NORETURN void tclWinDebugPanic(const char *format, ...);
+ const TCHAR *nativeName, Tcl_GlobTypeData *types);
+static int WinIsDrive(const char *name, int nameLen);
+static int WinIsReserved(const char *path);
+static Tcl_Obj * WinReadLink(const TCHAR *LinkSource);
+static Tcl_Obj * WinReadLinkDirectory(const TCHAR *LinkDirectory);
+static int WinLink(const TCHAR *LinkSource,
+ const TCHAR *LinkTarget, int linkAction);
+static int WinSymLinkDirectory(const TCHAR *LinkDirectory,
+ const TCHAR *LinkTarget);
/*
*--------------------------------------------------------------------
@@ -191,25 +220,25 @@ MODULE_SCOPE TCL_NORETURN void tclWinDebugPanic(const char *format, ...);
static int
WinLink(
- const WCHAR *linkSourcePath,
- const WCHAR *linkTargetPath,
+ const TCHAR *linkSourcePath,
+ const TCHAR *linkTargetPath,
int linkAction)
{
WCHAR tempFileName[MAX_PATH];
- WCHAR *tempFilePart;
+ TCHAR *tempFilePart;
DWORD attr;
/*
* Get the full path referenced by the target.
*/
- if (!GetFullPathNameW(linkTargetPath, MAX_PATH, tempFileName,
- &tempFilePart)) {
+ if (!(*tclWinProcs->getFullPathNameProc)(linkTargetPath, MAX_PATH,
+ tempFileName, &tempFilePart)) {
/*
* Invalid file.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
@@ -217,7 +246,7 @@ WinLink(
* Make sure source file doesn't exist.
*/
- attr = GetFileAttributesW(linkSourcePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath);
if (attr != INVALID_FILE_ATTRIBUTES) {
Tcl_SetErrno(EEXIST);
return -1;
@@ -227,13 +256,13 @@ WinLink(
* Get the full path referenced by the source file/directory.
*/
- if (!GetFullPathNameW(linkSourcePath, MAX_PATH, tempFileName,
- &tempFilePart)) {
+ if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, MAX_PATH,
+ tempFileName, &tempFilePart)) {
/*
* Invalid file.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
@@ -241,41 +270,43 @@ WinLink(
* Check the target.
*/
- attr = GetFileAttributesW(linkTargetPath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkTargetPath);
if (attr == INVALID_FILE_ATTRIBUTES) {
/*
* The target doesn't exist.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
+ return -1;
+
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
/*
* It is a file.
*/
- if (linkAction & TCL_CREATE_HARD_LINK) {
- if (CreateHardLinkW(linkSourcePath, linkTargetPath, NULL)) {
- /*
- * Success!
- */
+ if (tclWinProcs->createHardLinkProc == NULL) {
+ Tcl_SetErrno(ENOTDIR);
+ return -1;
+ }
- return 0;
+ if (linkAction & TCL_CREATE_HARD_LINK) {
+ if (!(*tclWinProcs->createHardLinkProc)(linkSourcePath,
+ linkTargetPath, NULL)) {
+ TclWinConvertError(GetLastError());
+ return -1;
}
+ return 0;
- Tcl_WinConvertError(GetLastError());
} else if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
- if (CreateSymbolicLinkW(linkSourcePath, linkTargetPath,
- 0x2 /* SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE */)) {
- /*
- * Success!
- */
+ /*
+ * Can't symlink files.
+ */
- return 0;
- } else {
- Tcl_WinConvertError(GetLastError());
- }
+ Tcl_SetErrno(ENOTDIR);
+ return -1;
} else {
Tcl_SetErrno(ENODEV);
+ return -1;
}
} else {
/*
@@ -292,11 +323,12 @@ WinLink(
*/
Tcl_SetErrno(EISDIR);
+ return -1;
} else {
Tcl_SetErrno(ENODEV);
+ return -1;
}
}
- return -1;
}
/*
@@ -311,23 +343,23 @@ WinLink(
static Tcl_Obj *
WinReadLink(
- const WCHAR *linkSourcePath)
+ const TCHAR *linkSourcePath)
{
WCHAR tempFileName[MAX_PATH];
- WCHAR *tempFilePart;
+ TCHAR *tempFilePart;
DWORD attr;
/*
* Get the full path referenced by the target.
*/
- if (!GetFullPathNameW(linkSourcePath, MAX_PATH, tempFileName,
- &tempFilePart)) {
+ if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, MAX_PATH,
+ tempFileName, &tempFilePart)) {
/*
* Invalid file.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return NULL;
}
@@ -335,13 +367,13 @@ WinReadLink(
* Make sure source file does exist.
*/
- attr = GetFileAttributesW(linkSourcePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath);
if (attr == INVALID_FILE_ATTRIBUTES) {
/*
* The source doesn't exist.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return NULL;
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
@@ -351,9 +383,9 @@ WinReadLink(
Tcl_SetErrno(ENOTDIR);
return NULL;
+ } else {
+ return WinReadLinkDirectory(linkSourcePath);
}
-
- return WinReadLinkDirectory(linkSourcePath);
}
/*
@@ -375,8 +407,8 @@ WinReadLink(
static int
WinSymLinkDirectory(
- const WCHAR *linkDirPath,
- const WCHAR *linkTargetPath)
+ const TCHAR *linkDirPath,
+ const TCHAR *linkTargetPath)
{
DUMMY_REPARSE_BUFFER dummy;
REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;
@@ -400,11 +432,11 @@ WinSymLinkDirectory(
*/
for (loop = nativeTarget; *loop != 0; loop++) {
- if (*loop == '/') {
- *loop = '\\';
+ if (*loop == L'/') {
+ *loop = L'\\';
}
}
- if ((nativeTarget[len-1] == '\\') && (nativeTarget[len-2] != ':')) {
+ if ((nativeTarget[len-1] == L'\\') && (nativeTarget[len-2] != L':')) {
nativeTarget[len-1] = 0;
}
@@ -447,8 +479,8 @@ WinSymLinkDirectory(
int
TclWinSymLinkCopyDirectory(
- const WCHAR *linkOrigPath, /* Existing junction - reparse point */
- const WCHAR *linkCopyPath) /* Will become a duplicate junction */
+ const TCHAR *linkOrigPath, /* Existing junction - reparse point */
+ const TCHAR *linkCopyPath) /* Will become a duplicate junction */
{
DUMMY_REPARSE_BUFFER dummy;
REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;
@@ -478,7 +510,7 @@ TclWinSymLinkCopyDirectory(
int
TclWinSymLinkDelete(
- const WCHAR *linkOrigPath,
+ const TCHAR *linkOrigPath,
int linkOnly)
{
/*
@@ -492,8 +524,9 @@ TclWinSymLinkDelete(
memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER));
reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
- hFile = CreateFileW(linkOrigPath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ hFile = (*tclWinProcs->createFileProc)(linkOrigPath, GENERIC_WRITE, 0,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
if (!DeviceIoControl(hFile, FSCTL_DELETE_REPARSE_POINT, reparseBuffer,
@@ -502,12 +535,12 @@ TclWinSymLinkDelete(
* Error setting junction.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
CloseHandle(hFile);
} else {
CloseHandle(hFile);
if (!linkOnly) {
- RemoveDirectoryW(linkOrigPath);
+ (*tclWinProcs->removeDirectoryProc)(linkOrigPath);
}
return 0;
}
@@ -536,14 +569,9 @@ TclWinSymLinkDelete(
*--------------------------------------------------------------------
*/
-#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warray-bounds"
-#endif
-
static Tcl_Obj *
WinReadLinkDirectory(
- const WCHAR *linkDirPath)
+ const TCHAR *linkDirPath)
{
int attr, len, offset;
DUMMY_REPARSE_BUFFER dummy;
@@ -552,7 +580,7 @@ WinReadLinkDirectory(
Tcl_DString ds;
const char *copy;
- attr = GetFileAttributesW(linkDirPath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkDirPath);
if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) {
goto invalidError;
}
@@ -577,7 +605,7 @@ WinReadLinkDirectory(
*/
offset = 0;
- if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == '\\') {
+ if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') {
/*
* Check whether this is a mounted volume.
*/
@@ -591,7 +619,7 @@ WinReadLinkDirectory(
* to fix here. It doesn't seem very well documented.
*/
- reparseBuffer->MountPointReparseBuffer.PathBuffer[1] = '\\';
+ reparseBuffer->MountPointReparseBuffer.PathBuffer[1]=L'\\';
/*
* Check if a corresponding drive letter exists, and use that
@@ -639,11 +667,10 @@ WinReadLinkDirectory(
}
}
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString(
+ Tcl_WinTCharToUtf((const char *)
reparseBuffer->MountPointReparseBuffer.PathBuffer,
- reparseBuffer->MountPointReparseBuffer
- .SubstituteNameLength>>1, &ds);
+ (int) reparseBuffer->MountPointReparseBuffer
+ .SubstituteNameLength, &ds);
copy = Tcl_DStringValue(&ds)+offset;
len = Tcl_DStringLength(&ds)-offset;
@@ -657,10 +684,6 @@ WinReadLinkDirectory(
Tcl_SetErrno(EINVAL);
return NULL;
}
-
-#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
-#pragma GCC diagnostic pop
-#endif
/*
*--------------------------------------------------------------------
@@ -679,23 +702,23 @@ WinReadLinkDirectory(
static int
NativeReadReparse(
- const WCHAR *linkDirPath, /* The junction to read */
+ const TCHAR *linkDirPath, /* The junction to read */
REPARSE_DATA_BUFFER *buffer,/* Pointer to buffer. Cannot be NULL */
DWORD desiredAccess)
{
HANDLE hFile;
DWORD returnedLength;
- hFile = CreateFileW(linkDirPath, desiredAccess, FILE_SHARE_READ, NULL,
- OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ hFile = (*tclWinProcs->createFileProc)(linkDirPath, desiredAccess, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
/*
* Error creating directory.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
@@ -709,7 +732,7 @@ NativeReadReparse(
* Error setting junction.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
CloseHandle(hFile);
return -1;
}
@@ -736,7 +759,7 @@ NativeReadReparse(
static int
NativeWriteReparse(
- const WCHAR *linkDirPath,
+ const TCHAR *linkDirPath,
REPARSE_DATA_BUFFER *buffer)
{
HANDLE hFile;
@@ -746,23 +769,23 @@ NativeWriteReparse(
* Create the directory - it must not already exist.
*/
- if (CreateDirectoryW(linkDirPath, NULL) == 0) {
+ if ((*tclWinProcs->createDirectoryProc)(linkDirPath, NULL) == 0) {
/*
* Error creating directory.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
- hFile = CreateFileW(linkDirPath, GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT
- | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ hFile = (*tclWinProcs->createFileProc)(linkDirPath, GENERIC_WRITE, 0,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
/*
* Error creating directory.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
@@ -777,9 +800,9 @@ NativeWriteReparse(
* Error setting junction.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
CloseHandle(hFile);
- RemoveDirectoryW(linkDirPath);
+ (*tclWinProcs->removeDirectoryProc)(linkDirPath);
return -1;
}
CloseHandle(hFile);
@@ -792,65 +815,6 @@ NativeWriteReparse(
}
/*
- *----------------------------------------------------------------------
- *
- * tclWinDebugPanic --
- *
- * Display a message. If a debugger is present, present it directly to
- * the debugger, otherwise use a MessageBox.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-TCL_NORETURN void
-tclWinDebugPanic(
- const char *format, ...)
-{
-#define TCL_MAX_WARN_LEN 1024
- va_list argList;
- char buf[TCL_MAX_WARN_LEN * 3];
- WCHAR msgString[TCL_MAX_WARN_LEN];
-
- va_start(argList, format);
- vsnprintf(buf, sizeof(buf), format, argList);
-
- msgString[TCL_MAX_WARN_LEN-1] = '\0';
- MultiByteToWideChar(CP_UTF8, 0, buf, -1, msgString, TCL_MAX_WARN_LEN);
-
- /*
- * Truncate MessageBox string if it is too long to not overflow the screen
- * and cause possible oversized window error.
- */
-
- if (msgString[TCL_MAX_WARN_LEN-1] != '\0') {
- memcpy(msgString + (TCL_MAX_WARN_LEN - 5), L" ...", 5 * sizeof(WCHAR));
- }
- if (IsDebuggerPresent()) {
- OutputDebugStringW(msgString);
- } else {
- MessageBeep(MB_ICONEXCLAMATION);
- MessageBoxW(NULL, msgString, L"Fatal Error",
- MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
- }
-#if defined(__GNUC__)
- __builtin_trap();
-#elif defined(_WIN64)
- __debugbreak();
-#elif defined(_MSC_VER) && defined (_M_IX86)
- _asm {int 3}
-#else
- DebugBreak();
-#endif
- abort();
-}
-
-/*
*---------------------------------------------------------------------------
*
* TclpFindExecutable --
@@ -869,26 +833,30 @@ tclWinDebugPanic(
void
TclpFindExecutable(
- const char *argv0) /* If NULL, install PanicMessageBox, otherwise
- * ignore. */
+ const char *argv0) /* The value of the application's argv[0]
+ * (native). */
{
WCHAR wName[MAX_PATH];
- char name[MAX_PATH * 3];
+ char name[MAX_PATH * TCL_UTF_MAX];
/*
* Under Windows we ignore argv0, and return the path for the file used to
- * create this process. Only if it is NULL, install a new panic handler.
+ * create this process.
*/
- if (argv0 == NULL) {
-# undef Tcl_SetPanicProc
- Tcl_SetPanicProc(tclWinDebugPanic);
+ if (GetModuleFileNameW(NULL, wName, MAX_PATH) == 0) {
+ GetModuleFileNameA(NULL, name, sizeof(name));
+
+ /*
+ * Convert to WCHAR to get out of ANSI codepage
+ */
+
+ MultiByteToWideChar(CP_ACP, 0, name, -1, wName, MAX_PATH);
}
- GetModuleFileNameW(NULL, wName, sizeof(wName)/sizeof(WCHAR));
- WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL, NULL);
+ WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL,NULL);
TclWinNoBackslash(name);
- TclSetObjNameOfExecutable(Tcl_NewStringObj(name, TCL_INDEX_NONE), NULL);
+ TclSetObjNameOfExecutable(Tcl_NewStringObj(name, -1), NULL);
}
/*
@@ -920,7 +888,7 @@ TclpMatchInDirectory(
* May be NULL. In particular the directory
* flag is very important. */
{
- const WCHAR *native;
+ const TCHAR *native;
if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) {
/*
@@ -932,26 +900,32 @@ TclpMatchInDirectory(
if (pattern == NULL || (*pattern == '\0')) {
Tcl_Obj *norm = Tcl_FSGetNormalizedPath(NULL, pathPtr);
-
if (norm != NULL) {
/*
* Match a single file directly.
*/
+ int len;
DWORD attr;
- WIN32_FILE_ATTRIBUTE_DATA data;
- Tcl_Size len = 0;
- const char *str = TclGetStringFromObj(norm, &len);
+ const char *str = Tcl_GetStringFromObj(norm,&len);
- native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ native = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
- if (GetFileAttributesExW(native,
- GetFileExInfoStandard, &data) != TRUE) {
- return TCL_OK;
+ if (tclWinProcs->getFileAttributesExProc == NULL) {
+ attr = (*tclWinProcs->getFileAttributesProc)(native);
+ if (attr == 0xffffffff) {
+ return TCL_OK;
+ }
+ } else {
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ if ((*tclWinProcs->getFileAttributesExProc)(native,
+ GetFileExInfoStandard, &data) != TRUE) {
+ return TCL_OK;
+ }
+ attr = data.dwFileAttributes;
}
- attr = data.dwFileAttributes;
- if (NativeMatchType(WinIsDrive(str, len), attr, native, types)) {
+ if (NativeMatchType(WinIsDrive(str,len), attr, native, types)) {
Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
}
}
@@ -959,10 +933,10 @@ TclpMatchInDirectory(
} else {
DWORD attr;
HANDLE handle;
- WIN32_FIND_DATAW data;
+ WIN32_FIND_DATAT data;
const char *dirName; /* UTF-8 dir name, later with pattern
* appended. */
- Tcl_Size dirLength;
+ int dirLength;
int matchSpecialDots;
Tcl_DString ds; /* Native encoding of dir, also used
* temporarily for other things. */
@@ -984,14 +958,13 @@ TclpMatchInDirectory(
* Verify that the specified path exists and is actually a directory.
*/
- native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ native = Tcl_FSGetNativePath(pathPtr);
if (native == NULL) {
return TCL_OK;
}
- attr = GetFileAttributesW(native);
+ attr = (*tclWinProcs->getFileAttributesProc)(native);
- if ((attr == INVALID_FILE_ATTRIBUTES)
- || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
+ if ((attr == 0xffffffff) || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
return TCL_OK;
}
@@ -1001,12 +974,12 @@ TclpMatchInDirectory(
*/
Tcl_DStringInit(&dsOrig);
- dirName = TclGetStringFromObj(fileNamePtr, &dirLength);
+ dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength);
Tcl_DStringAppend(&dsOrig, dirName, dirLength);
lastChar = dirName[dirLength -1];
if ((lastChar != '\\') && (lastChar != '/') && (lastChar != ':')) {
- TclDStringAppendLiteral(&dsOrig, "/");
+ Tcl_DStringAppend(&dsOrig, "/", 1);
dirLength++;
}
dirName = Tcl_DStringValue(&dsOrig);
@@ -1024,28 +997,27 @@ TclpMatchInDirectory(
* pattern.
*/
- dirName = Tcl_DStringAppend(&dsOrig, pattern, TCL_INDEX_NONE);
+ dirName = Tcl_DStringAppend(&dsOrig, pattern, -1);
} else {
- dirName = TclDStringAppendLiteral(&dsOrig, "*.*");
+ dirName = Tcl_DStringAppend(&dsOrig, "*.*", 3);
}
- Tcl_DStringInit(&ds);
- native = Tcl_UtfToWCharDString(dirName, TCL_INDEX_NONE, &ds);
- if ((types == NULL) || (types->type != TCL_GLOB_TYPE_DIR)) {
- handle = FindFirstFileW(native, &data);
+ native = Tcl_WinUtfToTChar(dirName, -1, &ds);
+ if (tclWinProcs->findFirstFileExProc == NULL || (types == NULL)
+ || (types->type != TCL_GLOB_TYPE_DIR)) {
+ handle = (*tclWinProcs->findFirstFileProc)(native, &data);
} else {
/*
* We can be more efficient, for pure directory requests.
*/
- handle = FindFirstFileExW(native,
+ handle = (*tclWinProcs->findFirstFileExProc)(native,
FindExInfoStandard, &data,
FindExSearchLimitToDirectories, NULL, 0);
}
if (handle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
-
Tcl_DStringFree(&ds);
if (err == ERROR_FILE_NOT_FOUND) {
/*
@@ -1057,11 +1029,12 @@ TclpMatchInDirectory(
return TCL_OK;
}
- Tcl_WinConvertError(err);
+ TclWinConvertError(err);
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't read directory \"%s\": %s",
- Tcl_DStringValue(&dsOrig), Tcl_PosixError(interp)));
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "couldn't read directory \"",
+ Tcl_DStringValue(&dsOrig), "\": ",
+ Tcl_PosixError(interp), NULL);
}
Tcl_DStringFree(&dsOrig);
return TCL_ERROR;
@@ -1099,11 +1072,17 @@ TclpMatchInDirectory(
do {
const char *utfname;
int checkDrive = 0, isDrive;
+ DWORD attr;
+
+ if (tclWinProcs->useWide) {
+ native = (const TCHAR *) data.w.cFileName;
+ attr = data.w.dwFileAttributes;
+ } else {
+ native = (const TCHAR *) data.a.cFileName;
+ attr = data.a.dwFileAttributes;
+ }
- native = data.cFileName;
- attr = data.dwFileAttributes;
- Tcl_DStringInit(&ds);
- utfname = Tcl_WCharToUtfDString(native, TCL_INDEX_NONE, &ds);
+ utfname = Tcl_WinTCharToUtf(native, -1, &ds);
if (!matchSpecialDots) {
/*
@@ -1145,7 +1124,6 @@ TclpMatchInDirectory(
if (checkDrive) {
const char *fullname = Tcl_DStringAppend(&dsOrig, utfname,
Tcl_DStringLength(&ds));
-
isDrive = WinIsDrive(fullname, Tcl_DStringLength(&dsOrig));
Tcl_DStringSetLength(&dsOrig, dirLength);
} else {
@@ -1163,7 +1141,7 @@ TclpMatchInDirectory(
*/
Tcl_DStringFree(&ds);
- } while (FindNextFileW(handle, &data) == TRUE);
+ } while ((*tclWinProcs->findNextFileProc)(handle, &data) == TRUE);
FindClose(handle);
Tcl_DStringFree(&dsOrig);
@@ -1180,7 +1158,7 @@ TclpMatchInDirectory(
static int
WinIsDrive(
const char *name, /* Name (UTF-8) */
- size_t len) /* Length of name */
+ int len) /* Length of name */
{
int remove = 0;
@@ -1245,7 +1223,7 @@ WinIsDrive(
* (not any trailing :).
*/
-static size_t
+static int
WinIsReserved(
const char *path) /* Path in UTF-8 */
{
@@ -1259,7 +1237,7 @@ WinIsReserved(
if (path[4] == '\0') {
return 4;
- } else if (path[4] == ':' && path[5] == '\0') {
+ } else if (path [4] == ':' && path[5] == '\0') {
return 4;
}
} else if ((path[2] == 'n' || path[2] == 'N') && path[3] == '\0') {
@@ -1280,7 +1258,7 @@ WinIsReserved(
if (path[4] == '\0') {
return 4;
- } else if (path[4] == ':' && path[5] == '\0') {
+ } else if (path [4] == ':' && path[5] == '\0') {
return 4;
}
}
@@ -1321,7 +1299,7 @@ NativeMatchType(
int isDrive, /* Is this a drive. */
DWORD attr, /* We already know the attributes for the
* file. */
- const WCHAR *nativeName, /* Native path to check. */
+ const TCHAR *nativeName, /* Native path to check. */
Tcl_GlobTypeData *types) /* Type description to match against. */
{
/*
@@ -1336,80 +1314,81 @@ NativeMatchType(
* If invisible, don't return the file.
*/
- return !(attr & FILE_ATTRIBUTE_HIDDEN && !isDrive);
- }
-
- if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) {
- /*
- * If invisible.
- */
-
- if ((types->perm == 0) || !(types->perm & TCL_GLOB_PERM_HIDDEN)) {
+ if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) {
return 0;
}
} else {
- /*
- * Visible.
- */
+ if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) {
+ /*
+ * If invisible.
+ */
- if (types->perm & TCL_GLOB_PERM_HIDDEN) {
- return 0;
- }
- }
+ if ((types->perm == 0) || !(types->perm & TCL_GLOB_PERM_HIDDEN)) {
+ return 0;
+ }
+ } else {
+ /*
+ * Visible.
+ */
- if (types->perm != 0) {
- if (((types->perm & TCL_GLOB_PERM_RONLY) &&
- !(attr & FILE_ATTRIBUTE_READONLY)) ||
- ((types->perm & TCL_GLOB_PERM_R) &&
- (0 /* File exists => R_OK on Windows */)) ||
- ((types->perm & TCL_GLOB_PERM_W) &&
- (attr & FILE_ATTRIBUTE_READONLY)) ||
- ((types->perm & TCL_GLOB_PERM_X) &&
- (!(attr & FILE_ATTRIBUTE_DIRECTORY)
- && !NativeIsExec(nativeName)))) {
- return 0;
+ if (types->perm & TCL_GLOB_PERM_HIDDEN) {
+ return 0;
+ }
}
- }
- if ((types->type & TCL_GLOB_TYPE_DIR)
- && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
- /*
- * Quicker test for directory, which is a common case.
- */
+ if (types->perm != 0) {
+ if (((types->perm & TCL_GLOB_PERM_RONLY) &&
+ !(attr & FILE_ATTRIBUTE_READONLY)) ||
+ ((types->perm & TCL_GLOB_PERM_R) &&
+ (0 /* File exists => R_OK on Windows */)) ||
+ ((types->perm & TCL_GLOB_PERM_W) &&
+ (attr & FILE_ATTRIBUTE_READONLY)) ||
+ ((types->perm & TCL_GLOB_PERM_X) &&
+ (!(attr & FILE_ATTRIBUTE_DIRECTORY)
+ && !NativeIsExec(nativeName)))) {
+ return 0;
+ }
+ }
+ if ((types->type & TCL_GLOB_TYPE_DIR)
+ && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ /*
+ * Quicker test for directory, which is a common case.
+ */
- return 1;
+ return 1;
- } else if (types->type != 0) {
- unsigned short st_mode;
- int isExec = NativeIsExec(nativeName);
+ } else if (types->type != 0) {
+ unsigned short st_mode;
+ int isExec = NativeIsExec(nativeName);
- st_mode = NativeStatMode(attr, 0, isExec);
+ st_mode = NativeStatMode(attr, 0, isExec);
- /*
- * In order bcdpfls as in 'find -t'
- */
+ /*
+ * In order bcdpfls as in 'find -t'
+ */
- if (((types->type&TCL_GLOB_TYPE_BLOCK) && S_ISBLK(st_mode)) ||
- ((types->type&TCL_GLOB_TYPE_CHAR) && S_ISCHR(st_mode)) ||
- ((types->type&TCL_GLOB_TYPE_DIR) && S_ISDIR(st_mode)) ||
- ((types->type&TCL_GLOB_TYPE_PIPE) && S_ISFIFO(st_mode)) ||
+ if (((types->type&TCL_GLOB_TYPE_BLOCK) && S_ISBLK(st_mode)) ||
+ ((types->type&TCL_GLOB_TYPE_CHAR) && S_ISCHR(st_mode)) ||
+ ((types->type&TCL_GLOB_TYPE_DIR) && S_ISDIR(st_mode)) ||
+ ((types->type&TCL_GLOB_TYPE_PIPE) && S_ISFIFO(st_mode)) ||
#ifdef S_ISSOCK
- ((types->type&TCL_GLOB_TYPE_SOCK) && S_ISSOCK(st_mode)) ||
+ ((types->type&TCL_GLOB_TYPE_SOCK) && S_ISSOCK(st_mode)) ||
#endif
- ((types->type&TCL_GLOB_TYPE_FILE) && S_ISREG(st_mode))) {
- /*
- * Do nothing - this file is ok.
- */
- } else {
+ ((types->type&TCL_GLOB_TYPE_FILE) && S_ISREG(st_mode))) {
+ /*
+ * Do nothing - this file is ok.
+ */
+ } else {
#ifdef S_ISLNK
- if (types->type & TCL_GLOB_TYPE_LINK) {
- st_mode = NativeStatMode(attr, 1, isExec);
- if (S_ISLNK(st_mode)) {
- return 1;
+ if (types->type & TCL_GLOB_TYPE_LINK) {
+ st_mode = NativeStatMode(attr, 1, isExec);
+ if (S_ISLNK(st_mode)) {
+ return 1;
+ }
}
+#endif
+ return 0;
}
-#endif /* S_ISLNK */
- return 0;
}
}
return 1;
@@ -1436,130 +1415,114 @@ NativeMatchType(
*----------------------------------------------------------------------
*/
-const char *
+char *
TclpGetUserHome(
const char *name, /* User name for desired home directory. */
Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
* name of user's home directory. */
{
- char *result = NULL;
- USER_INFO_1 *uiPtr;
- Tcl_DString ds;
- int nameLen = -1;
- int rc = 0;
- const char *domain;
- WCHAR *wName, *wHomeDir, *wDomain;
+ char *result;
+ HINSTANCE netapiInst;
+ HINSTANCE userenvInst;
+ result = NULL;
Tcl_DStringInit(bufferPtr);
- wDomain = NULL;
- domain = Tcl_UtfFindFirst(name, '@');
- if (domain == NULL) {
- const char *ptr;
-
- /*
- * Treat the current user as a special case because the general case
- * below does not properly retrieve the path. The NetUserGetInfo
- * call returns an empty path and the code defaults to the user's
- * name in the profiles directory. On modern Windows systems, this
- * is generally wrong as when the account is a Microsoft account,
- * for example abcdefghi@outlook.com, the directory name is
- * abcde and not abcdefghi.
- *
- * Note we could have just used env(USERPROFILE) here but
- * the intent is to retrieve (as on Unix) the system's view
- * of the home irrespective of environment settings of HOME
- * and USERPROFILE.
- *
- * Fixing this for the general user needs more investigating but
- * at least for the current user we can use a direct call.
- */
- ptr = TclpGetUserName(&ds);
- if (ptr != NULL && strcasecmp(name, ptr) == 0) {
- HANDLE hProcess;
+ netapiInst = LoadLibraryA("netapi32.dll");
+ userenvInst = LoadLibraryA("userenv.dll");
+ if (netapiInst != NULL && userenvInst != NULL) {
+ NETAPIBUFFERFREEPROC *netApiBufferFreeProc;
+ NETGETDCNAMEPROC *netGetDCNameProc;
+ NETUSERGETINFOPROC *netUserGetInfoProc;
+ GETPROFILESDIRECTORYPROC *getProfilesDirectoryProc;
+
+ netApiBufferFreeProc = (NETAPIBUFFERFREEPROC *)
+ GetProcAddress(netapiInst, "NetApiBufferFree");
+ netGetDCNameProc = (NETGETDCNAMEPROC *)
+ GetProcAddress(netapiInst, "NetGetDCName");
+ netUserGetInfoProc = (NETUSERGETINFOPROC *)
+ GetProcAddress(netapiInst, "NetUserGetInfo");
+ getProfilesDirectoryProc = (GETPROFILESDIRECTORYPROC *)
+ GetProcAddress(userenvInst, "GetProfilesDirectoryW");
+ if ((netUserGetInfoProc != NULL) && (netGetDCNameProc != NULL)
+ && (netApiBufferFreeProc != NULL) && (getProfilesDirectoryProc != NULL)) {
+ USER_INFO_1 *uiPtr, **uiPtrPtr = &uiPtr;
+ Tcl_DString ds;
+ int nameLen, badDomain;
+ char *domain;
+ WCHAR *wName, *wHomeDir, *wDomain, **wDomainPtr = &wDomain;
WCHAR buf[MAX_PATH];
- DWORD nChars = sizeof(buf) / sizeof(buf[0]);
- /* Sadly GetCurrentProcessToken not in Win 7 so slightly longer */
- hProcess = GetCurrentProcess(); /* Need not be closed */
- if (hProcess) {
- HANDLE hToken;
- if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
- if (GetUserProfileDirectoryW(hToken, buf, &nChars)) {
- result = Tcl_WCharToUtfDString(buf, nChars-1, (bufferPtr));
- rc = 1;
+
+ badDomain = 0;
+ nameLen = -1;
+ wDomain = NULL;
+ domain = strchr(name, '@');
+ if (domain != NULL) {
+ Tcl_DStringInit(&ds);
+ wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds);
+ badDomain = (netGetDCNameProc)(NULL, wName,
+ (LPBYTE *) wDomainPtr);
+ Tcl_DStringFree(&ds);
+ nameLen = domain - name;
+ }
+ if (badDomain == 0) {
+ Tcl_DStringInit(&ds);
+ wName = Tcl_UtfToUniCharDString(name, nameLen, &ds);
+ if ((netUserGetInfoProc)(wDomain, wName, 1,
+ (LPBYTE *) uiPtrPtr) == 0) {
+ wHomeDir = uiPtr->usri1_home_dir;
+ if ((wHomeDir != NULL) && (wHomeDir[0] != L'\0')) {
+ Tcl_UniCharToUtfDString(wHomeDir, lstrlenW(wHomeDir),
+ bufferPtr);
+ } else {
+ /*
+ * User exists but has no home dir. Return
+ * "{GetProfilesDirectory}/<user>".
+ */
+ DWORD i, size = MAX_PATH;
+ getProfilesDirectoryProc(buf, &size);
+ for (i = 0; i < size; ++i){
+ if (buf[i] == '\\') buf[i] = '/';
+ }
+ Tcl_UniCharToUtfDString(buf, size-1, bufferPtr);
+ Tcl_DStringAppend(bufferPtr, "/", -1);
+ Tcl_DStringAppend(bufferPtr, name, -1);
}
- CloseHandle(hToken);
+ result = Tcl_DStringValue(bufferPtr);
+ (*netApiBufferFreeProc)((void *) uiPtr);
}
+ Tcl_DStringFree(&ds);
+ }
+ if (wDomain != NULL) {
+ (*netApiBufferFreeProc)((void *) wDomain);
}
}
- Tcl_DStringFree(&ds);
- } else {
- Tcl_DStringInit(&ds);
- wName = Tcl_UtfToWCharDString(domain + 1, TCL_INDEX_NONE, &ds);
- rc = NetGetDCName(NULL, wName, (LPBYTE *) &wDomain);
- Tcl_DStringFree(&ds);
- nameLen = domain - name;
+ FreeLibrary(userenvInst);
+ FreeLibrary(netapiInst);
}
- if (rc == 0) {
- Tcl_DStringInit(&ds);
- wName = Tcl_UtfToWCharDString(name, nameLen, &ds);
- while (NetUserGetInfo(wDomain, wName, 1, (LPBYTE *) &uiPtr) != 0) {
- /*
- * User does not exist; if domain was not specified, try again
- * using current domain.
- */
-
- rc = 1;
- if (domain != NULL) {
- break;
- }
-
- /*
- * Get current domain
- */
+ if (result == NULL) {
+ /*
+ * Look in the "Password Lists" section of system.ini for the local
+ * user. There are also entries in that section that begin with a "*"
+ * character that are used by Windows for other purposes; ignore user
+ * names beginning with a "*".
+ */
- rc = NetGetDCName(NULL, NULL, (LPBYTE *) &wDomain);
- if (rc != 0) {
- break;
- }
- domain = (const char *)INT2PTR(-1); /* repeat once */
- }
- if (rc == 0) {
- DWORD i, size = MAX_PATH;
+ char buf[MAX_PATH];
- wHomeDir = uiPtr->usri1_home_dir;
- if ((wHomeDir != NULL) && (wHomeDir[0] != '\0')) {
- size = lstrlenW(wHomeDir);
- Tcl_WCharToUtfDString(wHomeDir, size, bufferPtr);
- } else {
- WCHAR buf[MAX_PATH];
+ if (name[0] != '*') {
+ if (GetPrivateProfileStringA("Password Lists", name, "", buf,
+ MAX_PATH, "system.ini") > 0) {
/*
- * User exists but has no home dir. Return
- * "{GetProfilesDirectory}/<user>".
+ * User exists, but there is no such thing as a home directory
+ * in system.ini. Return "{Windows drive}:/".
*/
- GetProfilesDirectoryW(buf, &size);
- Tcl_WCharToUtfDString(buf, size-1, bufferPtr);
- Tcl_DStringAppend(bufferPtr, "/", 1);
- Tcl_DStringAppend(bufferPtr, name, nameLen);
- }
- result = Tcl_DStringValue(bufferPtr);
-
- /*
- * Be sure we return normalized path
- */
-
- for (i = 0; i < size; ++i) {
- if (result[i] == '\\') {
- result[i] = '/';
- }
+ GetWindowsDirectoryA(buf, MAX_PATH);
+ Tcl_DStringAppend(bufferPtr, buf, 3);
+ result = Tcl_DStringValue(bufferPtr);
}
- NetApiBufferFree((void *) uiPtr);
}
- Tcl_DStringFree(&ds);
- }
- if (wDomain != NULL) {
- NetApiBufferFree((void *) wDomain);
}
return result;
@@ -1586,21 +1549,21 @@ TclpGetUserHome(
static int
NativeAccess(
- const WCHAR *nativePath, /* Path of file to access, native encoding. */
+ const TCHAR *nativePath, /* Path of file to access, native encoding. */
int mode) /* Permission setting. */
{
DWORD attr;
- attr = GetFileAttributesW(nativePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
- if (attr == INVALID_FILE_ATTRIBUTES) {
+ if (attr == 0xffffffff) {
/*
* File might not exist.
*/
DWORD lasterror = GetLastError();
if (lasterror != ERROR_SHARING_VIOLATION) {
- Tcl_WinConvertError(lasterror);
+ TclWinConvertError(lasterror);
return -1;
}
}
@@ -1613,75 +1576,33 @@ NativeAccess(
return 0;
}
- /*
- * If it's not a directory (assume file), do several fast checks:
- */
-
- if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ if ((mode & W_OK)
+ && (attr & FILE_ATTRIBUTE_READONLY)
+ && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
/*
- * If the attributes say this is not writable at all. The file is a
+ * The attributes say the file is not writable. If the file is a
* regular file (i.e., not a directory), then the file is not
- * writable, full stop. For directories, the read-only bit is
+ * writable, full stop. For directories, the read-only bit is
* (mostly) ignored by Windows, so we can't ascertain anything about
* directory access from the attrib data. However, if we have the
- * advanced 'getFileSecurityProc', then more robust ACL checks will be
- * done below.
- */
-
- if ((mode & W_OK) && (attr & FILE_ATTRIBUTE_READONLY)) {
- Tcl_SetErrno(EACCES);
- return -1;
- }
-
- /*
- * If doesn't have the correct extension, it can't be executable
- */
-
- if ((mode & X_OK) && !NativeIsExec(nativePath)) {
- Tcl_SetErrno(EACCES);
- return -1;
- }
-
- /*
- * Special case for read/write/executable check on file
+ * advanced 'getFileSecurityProc', then more robust ACL checks
+ * will be done below.
*/
- if ((mode & (R_OK|W_OK|X_OK)) && !(mode & ~(R_OK|W_OK|X_OK))) {
- DWORD mask = 0;
- HANDLE hFile;
-
- if (mode & R_OK) {
- mask |= GENERIC_READ;
- }
- if (mode & W_OK) {
- mask |= GENERIC_WRITE;
- }
- if (mode & X_OK) {
- mask |= GENERIC_EXECUTE;
- }
-
- hFile = CreateFileW(nativePath, mask,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL);
- if (hFile != INVALID_HANDLE_VALUE) {
- CloseHandle(hFile);
- return 0;
- }
+ Tcl_SetErrno(EACCES);
+ return -1;
+ }
+ if (mode & X_OK) {
+ if (!(attr & FILE_ATTRIBUTE_DIRECTORY) && !NativeIsExec(nativePath)) {
/*
- * Fast exit if access was denied
+ * It's not a directory and doesn't have the correct extension.
+ * Therefore it can't be executable
*/
- if (GetLastError() == ERROR_ACCESS_DENIED) {
- Tcl_SetErrno(EACCES);
- return -1;
- }
+ Tcl_SetErrno(EACCES);
+ return -1;
}
-
- /*
- * We cannot verify the access fast, check it below using security
- * info.
- */
}
/*
@@ -1691,7 +1612,7 @@ NativeAccess(
* what permissions the OS has set for a file.
*/
- {
+ if (tclWinProcs->getFileSecurityProc != NULL) {
SECURITY_DESCRIPTOR *sdPtr = NULL;
unsigned long size;
PSID pSid = 0;
@@ -1706,11 +1627,11 @@ NativeAccess(
int error;
/*
- * First find out how big the buffer needs to be.
+ * First find out how big the buffer needs to be
*/
size = 0;
- GetFileSecurityW(nativePath,
+ (*tclWinProcs->getFileSecurityProc)(nativePath,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
0, 0, &size);
@@ -1726,7 +1647,7 @@ NativeAccess(
* to EACCES - just what we want!
*/
- Tcl_WinConvertError((DWORD) error);
+ TclWinConvertError((DWORD) error);
return -1;
}
@@ -1741,10 +1662,10 @@ NativeAccess(
}
/*
- * Call GetFileSecurityW() for real.
+ * Call GetFileSecurity() for real.
*/
- if (!GetFileSecurityW(nativePath,
+ if (!(*tclWinProcs->getFileSecurityProc)(nativePath,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
sdPtr, size, &size)) {
@@ -1780,14 +1701,14 @@ NativeAccess(
* thread token.
*/
- if (!ImpersonateSelf(SecurityImpersonation)) {
+ if (!(*tclWinProcs->impersonateSelfProc)(SecurityImpersonation)) {
/*
* Unable to perform security impersonation.
*/
goto accessError;
}
- if (!OpenThreadToken(GetCurrentThread(),
+ if (!(*tclWinProcs->openThreadTokenProc)(GetCurrentThread(),
TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken)) {
/*
* Unable to get current thread's token.
@@ -1796,10 +1717,10 @@ NativeAccess(
goto accessError;
}
- RevertToSelf();
+ (*tclWinProcs->revertToSelfProc)();
/*
- * Setup desiredAccess according to the access privileges we are
+ * Setup desiredAccess according to the access priveleges we are
* checking.
*/
@@ -1823,7 +1744,7 @@ NativeAccess(
* Perform access check using the token.
*/
- if (!AccessCheck(sdPtr, hToken, desiredAccess,
+ if (!(*tclWinProcs->accessCheckProc)(sdPtr, hToken, desiredAccess,
&genMap, &privSet, &privSetSize, &grantedAccess,
&accessYesNo)) {
/*
@@ -1831,7 +1752,7 @@ NativeAccess(
*/
accessError:
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
if (sdPtr != NULL) {
HeapFree(GetProcessHeap(), 0, sdPtr);
}
@@ -1862,7 +1783,7 @@ NativeAccess(
* NativeIsExec --
*
* Determines if a path is executable. On windows this is simply defined
- * by whether the path ends in a standard executable extension.
+ * by whether the path ends in any of ".exe", ".com", or ".bat"
*
* Results:
* 1 = executable, 0 = not.
@@ -1872,24 +1793,55 @@ NativeAccess(
static int
NativeIsExec(
- const WCHAR *path)
+ const TCHAR *nativePath)
{
- int len = wcslen(path);
+ if (tclWinProcs->useWide) {
+ const WCHAR *path = (const WCHAR *) nativePath;
+ int len = wcslen(path);
- if (len < 5) {
- return 0;
- }
+ if (len < 5) {
+ return 0;
+ }
- if (path[len-4] != '.') {
- return 0;
- }
+ if (path[len-4] != L'.') {
+ return 0;
+ }
+
+ /*
+ * Use wide-char case-insensitive comparison
+ */
+
+ if ((_wcsicmp(path+len-3, L"exe") == 0)
+ || (_wcsicmp(path+len-3, L"com") == 0)
+ || (_wcsicmp(path+len-3, L"bat") == 0)) {
+ return 1;
+ }
+ } else {
+ const char *p;
+
+ /*
+ * We are only looking for pure ascii.
+ */
+
+ p = strrchr((const char *) nativePath, '.');
+ if (p != NULL) {
+ p++;
+
+ /*
+ * Note: in the old code, stat considered '.pif' files as
+ * executable, whereas access did not.
+ */
- path += len-3;
- if ((_wcsicmp(path, L"exe") == 0)
- || (_wcsicmp(path, L"com") == 0)
- || (_wcsicmp(path, L"cmd") == 0)
- || (_wcsicmp(path, L"bat") == 0)) {
- return 1;
+ if ((strcasecmp(p, "exe") == 0)
+ || (strcasecmp(p, "com") == 0)
+ || (strcasecmp(p, "bat") == 0)) {
+ /*
+ * File that ends with .exe, .com, or .bat is executable.
+ */
+
+ return 1;
+ }
+ }
}
return 0;
}
@@ -1915,17 +1867,17 @@ TclpObjChdir(
Tcl_Obj *pathPtr) /* Path to new working directory. */
{
int result;
- const WCHAR *nativePath;
+ const TCHAR *nativePath;
- nativePath = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ nativePath = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
if (!nativePath) {
return -1;
}
- result = SetCurrentDirectoryW(nativePath);
+ result = (*tclWinProcs->setCurrentDirectoryProc)(nativePath);
if (result == 0) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
return 0;
@@ -1961,14 +1913,12 @@ TclpGetCwd(
{
WCHAR buffer[MAX_PATH];
char *p;
- WCHAR *native;
- if (GetCurrentDirectoryW(MAX_PATH, buffer) == 0) {
- Tcl_WinConvertError(GetLastError());
+ if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) {
+ TclWinConvertError(GetLastError());
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "error getting working directory name: %s",
- Tcl_PosixError(interp)));
+ Tcl_AppendResult(interp, "error getting working directory name: ",
+ Tcl_PosixError(interp), NULL);
}
return NULL;
}
@@ -1977,13 +1927,25 @@ TclpGetCwd(
* Watch for the weird Windows c:\\UNC syntax.
*/
- native = (WCHAR *) buffer;
- if ((native[0] != '\0') && (native[1] == ':')
- && (native[2] == '\\') && (native[3] == '\\')) {
- native += 2;
+ if (tclWinProcs->useWide) {
+ WCHAR *native;
+
+ native = (WCHAR *) buffer;
+ if ((native[0] != '\0') && (native[1] == ':')
+ && (native[2] == '\\') && (native[3] == '\\')) {
+ native += 2;
+ }
+ Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr);
+ } else {
+ char *native;
+
+ native = (char *) buffer;
+ if ((native[0] != '\0') && (native[1] == ':')
+ && (native[2] == '\\') && (native[3] == '\\')) {
+ native += 2;
+ }
+ Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr);
}
- Tcl_DStringInit(bufferPtr);
- Tcl_WCharToUtfDString(native, TCL_INDEX_NONE, bufferPtr);
/*
* Convert to forward slashes for easier use in scripts.
@@ -2010,7 +1972,8 @@ TclpObjStat(
TclWinFlushDirtyChannels();
- return NativeStat((const WCHAR *)Tcl_FSGetNativePath(pathPtr), statPtr, 0);
+ return NativeStat((const TCHAR *) Tcl_FSGetNativePath(pathPtr),
+ statPtr, 0);
}
/*
@@ -2038,7 +2001,7 @@ TclpObjStat(
static int
NativeStat(
- const WCHAR *nativePath, /* Path of file to stat */
+ const TCHAR *nativePath, /* Path of file to stat */
Tcl_StatBuf *statPtr, /* Filled with results of stat call. */
int checkLinks) /* If non-zero, behave like 'lstat' */
{
@@ -2047,7 +2010,6 @@ NativeStat(
unsigned short mode;
unsigned int inode = 0;
HANDLE fileHandle;
- DWORD fileType = FILE_TYPE_UNKNOWN;
/*
* If we can use 'createFile' on this, then we can use the resulting
@@ -2055,48 +2017,29 @@ NativeStat(
* other attributes reading APIs. If not, then we try to fall back on the
* 'getFileAttributesExProc', and if that isn't available, then on even
* simpler routines.
- *
- * Special consideration must be given to Windows hard-coded names like
- * CON, NULL, COM1, LPT1 etc. For these, we still need to do the
- * CreateFile as some may not exist (e.g. there is no CON in wish by
- * default). However the subsequent GetFileInformationByHandle will
- * fail. We do a WinIsReserved to see if it is one of the special names,
- * and if successful, mock up a BY_HANDLE_FILE_INFORMATION structure.
*/
- fileHandle = CreateFileW(nativePath, GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING,
+ fileHandle = (tclWinProcs->createFileProc)(nativePath, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (fileHandle != INVALID_HANDLE_VALUE) {
BY_HANDLE_FILE_INFORMATION data;
if (GetFileInformationByHandle(fileHandle,&data) != TRUE) {
- fileType = GetFileType(fileHandle);
- CloseHandle(fileHandle);
- if (fileType != FILE_TYPE_CHAR && fileType != FILE_TYPE_DISK) {
- Tcl_SetErrno(ENOENT);
- return -1;
- }
-
- /*
- * Mock up the expected structure
- */
+ CloseHandle(fileHandle);
+ Tcl_SetErrno(ENOENT);
+ return -1;
+ }
+ CloseHandle(fileHandle);
- memset(&data, 0, sizeof(data));
- statPtr->st_atime = 0;
- statPtr->st_mtime = 0;
- statPtr->st_ctime = 0;
- } else {
- CloseHandle(fileHandle);
- statPtr->st_atime = ToCTime(data.ftLastAccessTime);
- statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
- statPtr->st_ctime = ToCTime(data.ftCreationTime);
- }
attr = data.dwFileAttributes;
- statPtr->st_size = ((long long) data.nFileSizeLow) |
- (((long long) data.nFileSizeHigh) << 32);
+
+ statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) |
+ (((Tcl_WideInt) data.nFileSizeHigh) << 32);
+ statPtr->st_atime = ToCTime(data.ftLastAccessTime);
+ statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
+ statPtr->st_ctime = ToCTime(data.ftCreationTime);
/*
* On Unix, for directories, nlink apparently depends on the number of
@@ -2115,26 +2058,26 @@ NativeStat(
*/
inode = data.nFileIndexHigh | data.nFileIndexLow;
- } else {
+ } else if (tclWinProcs->getFileAttributesExProc != NULL) {
/*
* Fall back on the less capable routines. This means no nlink or ino.
*/
WIN32_FILE_ATTRIBUTE_DATA data;
- if (GetFileAttributesExW(nativePath,
+ if ((*tclWinProcs->getFileAttributesExProc)(nativePath,
GetFileExInfoStandard, &data) != TRUE) {
HANDLE hFind;
- WIN32_FIND_DATAW ffd;
+ WIN32_FIND_DATAT ffd;
DWORD lasterror = GetLastError();
if (lasterror != ERROR_SHARING_VIOLATION) {
- Tcl_WinConvertError(lasterror);
+ TclWinConvertError(lasterror);
return -1;
}
- hFind = FindFirstFileW(nativePath, &ffd);
+ hFind = (*tclWinProcs->findFirstFileProc)(nativePath, &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
memcpy(&data, &ffd, sizeof(data));
@@ -2143,22 +2086,55 @@ NativeStat(
attr = data.dwFileAttributes;
- statPtr->st_size = ((long long) data.nFileSizeLow) |
- (((long long) data.nFileSizeHigh) << 32);
+ statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) |
+ (((Tcl_WideInt) data.nFileSizeHigh) << 32);
statPtr->st_atime = ToCTime(data.ftLastAccessTime);
statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
statPtr->st_ctime = ToCTime(data.ftCreationTime);
+ } else {
+ /*
+ * We don't have the faster attributes proc, so we're probably running
+ * on Win95.
+ */
+
+ WIN32_FIND_DATAT data;
+ HANDLE handle;
+
+ handle = (*tclWinProcs->findFirstFileProc)(nativePath, &data);
+ if (handle == INVALID_HANDLE_VALUE) {
+ /*
+ * FindFirstFile() doesn't work on root directories, so call
+ * GetFileAttributes() to see if the specified file exists.
+ */
+
+ attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ Tcl_SetErrno(ENOENT);
+ return -1;
+ }
+
+ /*
+ * Make up some fake information for this file. It has the correct
+ * file attributes and a time of 0.
+ */
+
+ memset(&data, 0, sizeof(data));
+ data.a.dwFileAttributes = attr;
+ } else {
+ FindClose(handle);
+ }
+
+ attr = data.a.dwFileAttributes;
+
+ statPtr->st_size = ((Tcl_WideInt) data.a.nFileSizeLow) |
+ (((Tcl_WideInt) data.a.nFileSizeHigh) << 32);
+ statPtr->st_atime = ToCTime(data.a.ftLastAccessTime);
+ statPtr->st_mtime = ToCTime(data.a.ftLastWriteTime);
+ statPtr->st_ctime = ToCTime(data.a.ftCreationTime);
}
dev = NativeDev(nativePath);
mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath));
- if (fileType == FILE_TYPE_CHAR) {
- mode &= ~S_IFMT;
- mode |= S_IFCHR;
- } else if (fileType == FILE_TYPE_DISK) {
- mode &= ~S_IFMT;
- mode |= S_IFBLK;
- }
statPtr->st_dev = (dev_t) dev;
statPtr->st_ino = inode;
@@ -2182,45 +2158,46 @@ NativeStat(
static int
NativeDev(
- const WCHAR *nativePath) /* Full path of file to stat */
+ const TCHAR *nativePath) /* Full path of file to stat */
{
int dev;
Tcl_DString ds;
WCHAR nativeFullPath[MAX_PATH];
- WCHAR *nativePart;
+ TCHAR *nativePart;
const char *fullPath;
- GetFullPathNameW(nativePath, MAX_PATH, nativeFullPath, &nativePart);
- Tcl_DStringInit(&ds);
- fullPath = Tcl_WCharToUtfDString(nativeFullPath, TCL_INDEX_NONE, &ds);
+ (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH,
+ nativeFullPath, &nativePart);
+
+ fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds);
if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) {
const char *p;
DWORD dw;
- const WCHAR *nativeVol;
+ const TCHAR *nativeVol;
Tcl_DString volString;
p = strchr(fullPath + 2, '\\');
p = strchr(p + 1, '\\');
if (p == NULL) {
/*
- * Add terminating backslash to fullpath or GetVolumeInformationW()
+ * Add terminating backslash to fullpath or GetVolumeInformation()
* won't work.
*/
- fullPath = TclDStringAppendLiteral(&ds, "\\");
+ fullPath = Tcl_DStringAppend(&ds, "\\", 1);
p = fullPath + Tcl_DStringLength(&ds);
} else {
p++;
}
- Tcl_DStringInit(&volString);
- nativeVol = Tcl_UtfToWCharDString(fullPath, p - fullPath, &volString);
+ nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString);
dw = (DWORD) -1;
- GetVolumeInformationW(nativeVol, NULL, 0, &dw, NULL, NULL, NULL, 0);
+ (*tclWinProcs->getVolumeInformationProc)(nativeVol, NULL, 0, &dw,
+ NULL, NULL, NULL, 0);
/*
- * GetFullPathNameW() turns special devices like "NUL" into "\\.\NUL",
- * but GetVolumeInformationW() returns failure for "\\.\NUL". This will
+ * GetFullPathName() turns special devices like "NUL" into "\\.\NUL",
+ * but GetVolumeInformation() returns failure for "\\.\NUL". This will
* cause "NUL" to get a drive number of -1, which makes about as much
* sense as anything since the special devices don't live on any
* drive.
@@ -2288,7 +2265,7 @@ NativeStatMode(
*
* ToCTime --
*
- * Converts a Windows FILETIME to a __time64_t in UTC.
+ * Converts a Windows FILETIME to a time_t in UTC.
*
* Results:
* Returns the count of seconds from the Posix epoch.
@@ -2296,7 +2273,7 @@ NativeStatMode(
*------------------------------------------------------------------------
*/
-static __time64_t
+static time_t
ToCTime(
FILETIME fileTime) /* UTC time */
{
@@ -2305,8 +2282,8 @@ ToCTime(
convertedTime.LowPart = fileTime.dwLowDateTime;
convertedTime.HighPart = (LONG) fileTime.dwHighDateTime;
- return (__time64_t) ((convertedTime.QuadPart -
- (long long) POSIX_EPOCH_AS_FILETIME) / (long long) 10000000);
+ return (time_t) ((convertedTime.QuadPart -
+ (Tcl_WideInt) POSIX_EPOCH_AS_FILETIME) / (Tcl_WideInt) 10000000);
}
/*
@@ -2314,7 +2291,7 @@ ToCTime(
*
* FromCTime --
*
- * Converts a __time64_t to a Windows FILETIME
+ * Converts a time_t to a Windows FILETIME
*
* Results:
* Returns the count of 100-ns ticks seconds from the Windows epoch.
@@ -2324,13 +2301,12 @@ ToCTime(
static void
FromCTime(
- __time64_t posixTime,
+ time_t posixTime,
FILETIME *fileTime) /* UTC Time */
{
LARGE_INTEGER convertedTime;
-
convertedTime.QuadPart = ((LONGLONG) posixTime) * 10000000
- + POSIX_EPOCH_AS_FILETIME;
+ + POSIX_EPOCH_AS_FILETIME;
fileTime->dwLowDateTime = convertedTime.LowPart;
fileTime->dwHighDateTime = convertedTime.HighPart;
}
@@ -2347,7 +2323,7 @@ FromCTime(
* is either the given clientData, if the working directory hasn't
* changed, or a new clientData (owned by our caller), giving the new
* native path, or NULL if the current directory could not be determined.
- * If NULL is returned, the caller can examine the standard Posix error
+ * If NULL is returned, the caller can examine the standard posix error
* codes to determine the cause of the problem.
*
* Side effects:
@@ -2356,24 +2332,38 @@ FromCTime(
*----------------------------------------------------------------------
*/
-void *
+ClientData
TclpGetNativeCwd(
- void *clientData)
+ ClientData clientData)
{
WCHAR buffer[MAX_PATH];
- if (GetCurrentDirectoryW(MAX_PATH, buffer) == 0) {
- Tcl_WinConvertError(GetLastError());
+ if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) {
+ TclWinConvertError(GetLastError());
return NULL;
}
if (clientData != NULL) {
- if (wcscmp((const WCHAR *) clientData, buffer) == 0) {
- return clientData;
+ if (tclWinProcs->useWide) {
+ /*
+ * Unicode representation when running on NT/2K/XP.
+ */
+
+ if (wcscmp((const WCHAR*)clientData, (const WCHAR*)buffer) == 0) {
+ return clientData;
+ }
+ } else {
+ /*
+ * ANSI representation when running on 95/98/ME.
+ */
+
+ if (strcmp((const char*) clientData, (const char*) buffer) == 0) {
+ return clientData;
+ }
}
}
- return TclNativeDupInternalRep(buffer);
+ return TclNativeDupInternalRep((ClientData) buffer);
}
int
@@ -2381,7 +2371,7 @@ TclpObjAccess(
Tcl_Obj *pathPtr,
int mode)
{
- return NativeAccess((const WCHAR *)Tcl_FSGetNativePath(pathPtr), mode);
+ return NativeAccess((const TCHAR *) Tcl_FSGetNativePath(pathPtr), mode);
}
int
@@ -2397,7 +2387,8 @@ TclpObjLstat(
TclWinFlushDirtyChannels();
- return NativeStat((const WCHAR *)Tcl_FSGetNativePath(pathPtr), statPtr, 1);
+ return NativeStat((const TCHAR *) Tcl_FSGetNativePath(pathPtr),
+ statPtr, 1);
}
#ifdef S_IFLNK
@@ -2409,15 +2400,15 @@ TclpObjLink(
{
if (toPtr != NULL) {
int res;
- const WCHAR *LinkTarget;
- const WCHAR *LinkSource = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ TCHAR *LinkTarget;
+ TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr);
Tcl_Obj *normalizedToPtr = Tcl_FSGetNormalizedPath(NULL, toPtr);
if (normalizedToPtr == NULL) {
return NULL;
}
- LinkTarget = (const WCHAR *)Tcl_FSGetNativePath(normalizedToPtr);
+ LinkTarget = (TCHAR *) Tcl_FSGetNativePath(normalizedToPtr);
if (LinkSource == NULL || LinkTarget == NULL) {
return NULL;
@@ -2429,7 +2420,7 @@ TclpObjLink(
return NULL;
}
} else {
- const WCHAR *LinkSource = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr);
if (LinkSource == NULL) {
return NULL;
@@ -2437,7 +2428,7 @@ TclpObjLink(
return WinReadLink(LinkSource);
}
}
-#endif /* S_IFLNK */
+#endif
/*
*---------------------------------------------------------------------------
@@ -2471,21 +2462,23 @@ TclpFilesystemPathType(
if (normPath == NULL) {
return NULL;
}
- path = TclGetString(normPath);
+ path = Tcl_GetString(normPath);
if (path == NULL) {
return NULL;
}
- firstSeparator = strchr((char *)path, '/');
+ firstSeparator = strchr(path, '/');
if (firstSeparator == NULL) {
- found = GetVolumeInformationW((const WCHAR *)Tcl_FSGetNativePath(pathPtr),
- NULL, 0, NULL, NULL, NULL, volType, VOL_BUF_SIZE);
+ found = tclWinProcs->getVolumeInformationProc(
+ Tcl_FSGetNativePath(pathPtr), NULL, 0, NULL, NULL, NULL,
+ (WCHAR *) volType, VOL_BUF_SIZE);
} else {
Tcl_Obj *driveName = Tcl_NewStringObj(path, firstSeparator - path+1);
Tcl_IncrRefCount(driveName);
- found = GetVolumeInformationW((const WCHAR *)Tcl_FSGetNativePath(driveName),
- NULL, 0, NULL, NULL, NULL, volType, VOL_BUF_SIZE);
+ found = tclWinProcs->getVolumeInformationProc(
+ Tcl_FSGetNativePath(driveName), NULL, 0, NULL, NULL, NULL,
+ (WCHAR *) volType, VOL_BUF_SIZE);
Tcl_DecrRefCount(driveName);
}
@@ -2493,10 +2486,13 @@ TclpFilesystemPathType(
return NULL;
} else {
Tcl_DString ds;
+ Tcl_Obj *objPtr;
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString(volType, TCL_INDEX_NONE, &ds);
- return Tcl_DStringToObj(&ds);
+ Tcl_WinTCharToUtf((const char *) volType, -1, &ds);
+ objPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),
+ Tcl_DStringLength(&ds));
+ Tcl_DStringFree(&ds);
+ return objPtr;
}
#undef VOL_BUF_SIZE
}
@@ -2538,257 +2534,409 @@ TclpFilesystemPathType(
int
TclpObjNormalizePath(
- TCL_UNUSED(Tcl_Interp *),
- Tcl_Obj *pathPtr, /* An unshared object containing the path to
- * normalize */
- int nextCheckpoint) /* offset to start at in pathPtr */
+ Tcl_Interp *interp,
+ Tcl_Obj *pathPtr,
+ int nextCheckpoint)
{
char *lastValidPathEnd = NULL;
Tcl_DString dsNorm; /* This will hold the normalized string. */
char *path, *currentPathEndPosition;
Tcl_Obj *temp = NULL;
- int isDrive = 1;
- Tcl_DString ds; /* Some workspace. */
Tcl_DStringInit(&dsNorm);
- path = TclGetString(pathPtr);
+ path = Tcl_GetString(pathPtr);
- currentPathEndPosition = path + nextCheckpoint;
- if (*currentPathEndPosition == '/') {
- currentPathEndPosition++;
- }
- while (1) {
- char cur = *currentPathEndPosition;
+ if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) {
+ /*
+ * We're on Win95, 98 or ME. There are two assumptions in this block
+ * of code. First that the native (NULL) encoding is basically ascii,
+ * and second that symbolic links are not possible. Both of these
+ * assumptions appear to be true of these operating systems.
+ */
- if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) {
- /*
- * Reached directory separator, or end of string.
- */
+ int isDrive = 1;
+ Tcl_DString ds;
- WIN32_FILE_ATTRIBUTE_DATA data;
- const WCHAR *nativePath;
+ currentPathEndPosition = path + nextCheckpoint;
+ if (*currentPathEndPosition == '/') {
+ currentPathEndPosition++;
+ }
- Tcl_DStringInit(&ds);
- nativePath = Tcl_UtfToWCharDString(path,
- currentPathEndPosition - path, &ds);
+ while (1) {
+ char cur = *currentPathEndPosition;
- if (GetFileAttributesExW(nativePath,
- GetFileExInfoStandard, &data) != TRUE) {
+ if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) {
/*
- * File doesn't exist.
+ * Reached directory separator, or end of string.
*/
- if (isDrive) {
- size_t len = WinIsReserved(path);
+ const char *nativePath = Tcl_UtfToExternalDString(NULL, path,
+ currentPathEndPosition - path, &ds);
- if (len > 0) {
+ /*
+ * Now we convert the tail of the current path to its 'long
+ * form', and append it to 'dsNorm' which holds the current
+ * normalized path, if the file exists.
+ */
+
+ if (isDrive) {
+ if (GetFileAttributesA(nativePath)
+ == INVALID_FILE_ATTRIBUTES) {
/*
- * Actually it does exist - COM1, etc.
+ * File doesn't exist.
*/
- size_t i;
-
- for (i=0 ; i<len ; i++) {
- WCHAR wc = ((WCHAR *)nativePath)[i];
-
- if (wc >= 'a') {
- wc -= ('a' - 'A');
- ((WCHAR *) nativePath)[i] = wc;
+ if (isDrive) {
+ int len = WinIsReserved(path);
+
+ if (len > 0) {
+ /*
+ * Actually it does exist - COM1, etc.
+ */
+
+ int i;
+
+ for (i=0 ; i<len ; i++) {
+ if (nativePath[i] >= 'a') {
+ ((char *) nativePath)[i] -= ('a'-'A');
+ }
+ }
+ Tcl_DStringAppend(&dsNorm, nativePath, len);
+ lastValidPathEnd = currentPathEndPosition;
+ } else if (nextCheckpoint == 0) {
+ /* Path starts with a drive designation
+ * that's not actually on the system.
+ * We still must normalize up past the
+ * first separator. [Bug 3603434] */
+ currentPathEndPosition++;
+ }
+ }
+ Tcl_DStringFree(&ds);
+ break;
+ }
+ if (nativePath[0] >= 'a') {
+ ((char *) nativePath)[0] -= ('a' - 'A');
+ }
+ Tcl_DStringAppend(&dsNorm, nativePath,
+ Tcl_DStringLength(&ds));
+ } else {
+ char *checkDots = NULL;
+
+ if (lastValidPathEnd[1] == '.') {
+ checkDots = lastValidPathEnd + 1;
+ while (checkDots < currentPathEndPosition) {
+ if (*checkDots != '.') {
+ checkDots = NULL;
+ break;
}
+ checkDots++;
}
- Tcl_DStringAppend(&dsNorm,
- (const char *)nativePath,
- sizeof(WCHAR) * len);
- lastValidPathEnd = currentPathEndPosition;
- } else if (nextCheckpoint == 0) {
+ }
+ if (checkDots != NULL) {
+ int dotLen = currentPathEndPosition-lastValidPathEnd;
+
+ /*
+ * Path is just dots. We shouldn't really ever see a
+ * path like that. However, to be nice we at least
+ * don't mangle the path - we just add the dots as a
+ * path segment and continue
+ */
+
+ Tcl_DStringAppend(&dsNorm, (TCHAR *)
+ (nativePath + Tcl_DStringLength(&ds)-dotLen),
+ dotLen);
+ } else {
/*
- * Path starts with a drive designation that's not
- * actually on the system. We still must normalize up
- * past the first separator. [Bug 3603434]
+ * Normal path.
*/
- currentPathEndPosition++;
+ WIN32_FIND_DATA fData;
+ HANDLE handle;
+
+ handle = FindFirstFileA(nativePath, &fData);
+ if (handle == INVALID_HANDLE_VALUE) {
+ if (GetFileAttributesA(nativePath)
+ == INVALID_FILE_ATTRIBUTES) {
+ /*
+ * File doesn't exist.
+ */
+
+ Tcl_DStringFree(&ds);
+ break;
+ }
+
+ /*
+ * This is usually the '/' in 'c:/' at end of
+ * string.
+ */
+
+ Tcl_DStringAppend(&dsNorm,"/", 1);
+ } else {
+ char *nativeName;
+
+ if (fData.cFileName[0] != '\0') {
+ nativeName = fData.cFileName;
+ } else {
+ nativeName = fData.cAlternateFileName;
+ }
+ FindClose(handle);
+ Tcl_DStringAppend(&dsNorm,"/", 1);
+ Tcl_DStringAppend(&dsNorm,nativeName,-1);
+ }
}
}
Tcl_DStringFree(&ds);
- break;
+ lastValidPathEnd = currentPathEndPosition;
+ if (cur == 0) {
+ break;
+ }
+
+ /*
+ * If we get here, we've got past one directory delimiter, so
+ * we know it is no longer a drive.
+ */
+
+ isDrive = 0;
}
+ currentPathEndPosition++;
+ }
+ } else {
+ /*
+ * We're on WinNT (or 2000 or XP; something with an NT core).
+ */
- /*
- * File 'nativePath' does exist if we get here. We now want to
- * check if it is a symlink and otherwise continue with the
- * rest of the path.
- */
+ int isDrive = 1;
+ Tcl_DString ds;
- /*
- * Check for symlinks, except at last component of path (we don't
- * follow final symlinks). Also a drive (C:/) for example, may
- * sometimes have the reparse flag set for some reason I don't
- * understand. We therefore don't perform this check for drives.
- */
+ currentPathEndPosition = path + nextCheckpoint;
+ if (*currentPathEndPosition == '/') {
+ currentPathEndPosition++;
+ }
+ while (1) {
+ char cur = *currentPathEndPosition;
- if (cur != 0 && !isDrive &&
- data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT){
- Tcl_Obj *to = WinReadLinkDirectory(nativePath);
+ if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) {
+ /*
+ * Reached directory separator, or end of string.
+ */
- if (to != NULL) {
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ const char *nativePath = Tcl_WinUtfToTChar(path,
+ currentPathEndPosition - path, &ds);
+
+ if ((*tclWinProcs->getFileAttributesExProc)(nativePath,
+ GetFileExInfoStandard, &data) != TRUE) {
/*
- * Read the reparse point ok. Now, reparse points need not
- * be normalized, otherwise we could use:
- *
- * Tcl_GetStringFromObj(to, &pathLen);
- * nextCheckpoint = pathLen;
- *
- * So, instead we have to start from the beginning.
+ * File doesn't exist.
*/
- nextCheckpoint = 0;
- Tcl_AppendToObj(to, currentPathEndPosition, TCL_INDEX_NONE);
+ if (isDrive) {
+ int len = WinIsReserved(path);
- /*
- * Convert link to forward slashes.
- */
+ if (len > 0) {
+ /*
+ * Actually it does exist - COM1, etc.
+ */
- for (path = TclGetString(to); *path != 0; path++) {
- if (*path == '\\') {
- *path = '/';
- }
- }
- path = TclGetString(to);
- currentPathEndPosition = path + nextCheckpoint;
- if (temp != NULL) {
- Tcl_DecrRefCount(temp);
- }
- temp = to;
+ int i;
- /*
- * Reset variables so we can restart normalization.
- */
+ for (i=0 ; i<len ; i++) {
+ WCHAR wc = ((WCHAR *) nativePath)[i];
- isDrive = 1;
- Tcl_DStringFree(&dsNorm);
+ if (wc >= L'a') {
+ wc -= (L'a' - L'A');
+ ((WCHAR *) nativePath)[i] = wc;
+ }
+ }
+ Tcl_DStringAppend(&dsNorm, nativePath,
+ (int)(sizeof(WCHAR) * len));
+ lastValidPathEnd = currentPathEndPosition;
+ } else if (nextCheckpoint == 0) {
+ /* Path starts with a drive designation
+ * that's not actually on the system.
+ * We still must normalize up past the
+ * first separator. [Bug 3603434] */
+ currentPathEndPosition++;
+ }
+ }
Tcl_DStringFree(&ds);
- continue;
+ break;
}
- }
-#ifndef TclNORM_LONG_PATH
- /*
- * Now we convert the tail of the current path to its 'long form',
- * and append it to 'dsNorm' which holds the current normalized
- * path
- */
+ /*
+ * File 'nativePath' does exist if we get here. We now want to
+ * check if it is a symlink and otherwise continue with the
+ * rest of the path.
+ */
- if (isDrive) {
- WCHAR drive = ((WCHAR *) nativePath)[0];
+ /*
+ * Check for symlinks, except at last component of path (we
+ * don't follow final symlinks). Also a drive (C:/) for
+ * example, may sometimes have the reparse flag set for some
+ * reason I don't understand. We therefore don't perform this
+ * check for drives.
+ */
- if (drive >= 'a') {
- drive -= ('a' - 'A');
- ((WCHAR *) nativePath)[0] = drive;
- }
- Tcl_DStringAppend(&dsNorm, (const char *)nativePath,
- Tcl_DStringLength(&ds));
- } else {
- char *checkDots = NULL;
-
- if (lastValidPathEnd[1] == '.') {
- checkDots = lastValidPathEnd + 1;
- while (checkDots < currentPathEndPosition) {
- if (*checkDots != '.') {
- checkDots = NULL;
- break;
+ if (cur != 0 && !isDrive &&
+ data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT){
+ Tcl_Obj *to = WinReadLinkDirectory(nativePath);
+
+ if (to != NULL) {
+ /*
+ * Read the reparse point ok. Now, reparse points need
+ * not be normalized, otherwise we could use:
+ *
+ * Tcl_GetStringFromObj(to, &pathLen);
+ * nextCheckpoint = pathLen
+ *
+ * So, instead we have to start from the beginning.
+ */
+
+ nextCheckpoint = 0;
+ Tcl_AppendToObj(to, currentPathEndPosition, -1);
+
+ /*
+ * Convert link to forward slashes.
+ */
+
+ for (path = Tcl_GetString(to); *path != 0; path++) {
+ if (*path == '\\') {
+ *path = '/';
+ }
}
- checkDots++;
+ path = Tcl_GetString(to);
+ currentPathEndPosition = path + nextCheckpoint;
+ if (temp != NULL) {
+ Tcl_DecrRefCount(temp);
+ }
+ temp = to;
+
+ /*
+ * Reset variables so we can restart normalization.
+ */
+
+ isDrive = 1;
+ Tcl_DStringFree(&dsNorm);
+ Tcl_DStringInit(&dsNorm);
+ Tcl_DStringFree(&ds);
+ continue;
}
}
- if (checkDots != NULL) {
- int dotLen = currentPathEndPosition-lastValidPathEnd;
- /*
- * Path is just dots. We shouldn't really ever see a path
- * like that. However, to be nice we at least don't mangle
- * the path - we just add the dots as a path segment and
- * continue.
- */
+#ifndef TclNORM_LONG_PATH
+ /*
+ * Now we convert the tail of the current path to its 'long
+ * form', and append it to 'dsNorm' which holds the current
+ * normalized path
+ */
- Tcl_DStringAppend(&dsNorm, ((const char *)nativePath)
- + Tcl_DStringLength(&ds)
- - (dotLen * sizeof(WCHAR)),
- dotLen * sizeof(WCHAR));
+ if (isDrive) {
+ WCHAR drive = ((WCHAR *) nativePath)[0];
+ if (drive >= L'a') {
+ drive -= (L'a' - L'A');
+ ((WCHAR *) nativePath)[0] = drive;
+ }
+ Tcl_DStringAppend(&dsNorm, nativePath,
+ Tcl_DStringLength(&ds));
} else {
- /*
- * Normal path.
- */
-
- WIN32_FIND_DATAW fData;
- HANDLE handle;
+ char *checkDots = NULL;
+
+ if (lastValidPathEnd[1] == '.') {
+ checkDots = lastValidPathEnd + 1;
+ while (checkDots < currentPathEndPosition) {
+ if (*checkDots != '.') {
+ checkDots = NULL;
+ break;
+ }
+ checkDots++;
+ }
+ }
+ if (checkDots != NULL) {
+ int dotLen = currentPathEndPosition-lastValidPathEnd;
- handle = FindFirstFileW((WCHAR *) nativePath, &fData);
- if (handle == INVALID_HANDLE_VALUE) {
/*
- * This is usually the '/' in 'c:/' at end of string.
+ * Path is just dots. We shouldn't really ever see a
+ * path like that. However, to be nice we at least
+ * don't mangle the path - we just add the dots as a
+ * path segment and continue.
*/
- Tcl_DStringAppend(&dsNorm, (const char *) L"/",
- sizeof(WCHAR));
+ Tcl_DStringAppend(&dsNorm, (TCHAR *)
+ ((WCHAR*)(nativePath + Tcl_DStringLength(&ds))
+ - dotLen), (int)(dotLen * sizeof(WCHAR)));
} else {
- WCHAR *nativeName;
+ /*
+ * Normal path.
+ */
- if (fData.cFileName[0] != '\0') {
- nativeName = fData.cFileName;
+ WIN32_FIND_DATAW fData;
+ HANDLE handle;
+
+ handle = FindFirstFileW((WCHAR *) nativePath, &fData);
+ if (handle == INVALID_HANDLE_VALUE) {
+ /*
+ * This is usually the '/' in 'c:/' at end of
+ * string.
+ */
+
+ Tcl_DStringAppend(&dsNorm, (const char *) L"/",
+ sizeof(WCHAR));
} else {
- nativeName = fData.cAlternateFileName;
+ WCHAR *nativeName;
+
+ if (fData.cFileName[0] != '\0') {
+ nativeName = fData.cFileName;
+ } else {
+ nativeName = fData.cAlternateFileName;
+ }
+ FindClose(handle);
+ Tcl_DStringAppend(&dsNorm, (const char *) L"/",
+ sizeof(WCHAR));
+ Tcl_DStringAppend(&dsNorm, (TCHAR *) nativeName,
+ (int) (wcslen(nativeName)*sizeof(WCHAR)));
}
- FindClose(handle);
- Tcl_DStringAppend(&dsNorm, (const char *) L"/",
- sizeof(WCHAR));
- Tcl_DStringAppend(&dsNorm,
- (const char *) nativeName,
- wcslen(nativeName)*sizeof(WCHAR));
}
}
- }
-#endif /* !TclNORM_LONG_PATH */
- Tcl_DStringFree(&ds);
- lastValidPathEnd = currentPathEndPosition;
- if (cur == 0) {
- break;
- }
+#endif
+ Tcl_DStringFree(&ds);
+ lastValidPathEnd = currentPathEndPosition;
+ if (cur == 0) {
+ break;
+ }
- /*
- * If we get here, we've got past one directory delimiter, so we
- * know it is no longer a drive.
- */
+ /*
+ * If we get here, we've got past one directory delimiter, so
+ * we know it is no longer a drive.
+ */
- isDrive = 0;
+ isDrive = 0;
+ }
+ currentPathEndPosition++;
}
- currentPathEndPosition++;
#ifdef TclNORM_LONG_PATH
/*
* Convert the entire known path to long form.
*/
- WCHAR wpath[MAX_PATH];
- const WCHAR *nativePath;
- DWORD wpathlen;
+ if (1) {
+ WCHAR wpath[MAX_PATH];
+ const char *nativePath =
+ Tcl_WinUtfToTChar(path, lastValidPathEnd - path, &ds);
+ DWORD wpathlen = (*tclWinProcs->getLongPathNameProc)(
+ nativePath, (TCHAR *) wpath, MAX_PATH);
- Tcl_DStringInit(&ds);
- nativePath =
- Tcl_UtfToWCharDString(path, lastValidPathEnd - path, &ds);
- wpathlen = GetLongPathNameProc(nativePath,
- (WCHAR *) wpath, MAX_PATH);
- /*
- * We have to make the drive letter uppercase.
- */
+ /*
+ * We have to make the drive letter uppercase.
+ */
- if (wpath[0] >= 'a') {
- wpath[0] -= ('a' - 'A');
+ if (wpath[0] >= L'a') {
+ wpath[0] -= (L'a' - L'A');
+ }
+ Tcl_DStringAppend(&dsNorm, (TCHAR*)wpath, wpathlen*sizeof(WCHAR));
+ Tcl_DStringFree(&ds);
}
- Tcl_DStringAppend(&dsNorm, (const char *) wpath,
- wpathlen * sizeof(WCHAR));
- Tcl_DStringFree(&ds);
-#endif /* TclNORM_LONG_PATH */
+#endif
}
/*
@@ -2803,22 +2951,24 @@ TclpObjNormalizePath(
* native encoding, so we have to convert it to Utf.
*/
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString((const WCHAR *) Tcl_DStringValue(&dsNorm),
- Tcl_DStringLength(&dsNorm)>>1, &ds);
- nextCheckpoint = Tcl_DStringLength(&ds);
+ Tcl_DString dsTemp;
+
+ Tcl_WinTCharToUtf(Tcl_DStringValue(&dsNorm),
+ Tcl_DStringLength(&dsNorm), &dsTemp);
+ nextCheckpoint = Tcl_DStringLength(&dsTemp);
if (*lastValidPathEnd != 0) {
/*
* Not the end of the string.
*/
+ int len;
+ char *path;
Tcl_Obj *tmpPathPtr;
- Tcl_Size len;
- tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),
+ tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp),
nextCheckpoint);
- Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, TCL_INDEX_NONE);
- path = TclGetStringFromObj(tmpPathPtr, &len);
+ Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, -1);
+ path = Tcl_GetStringFromObj(tmpPathPtr, &len);
Tcl_SetStringObj(pathPtr, path, len);
Tcl_DecrRefCount(tmpPathPtr);
} else {
@@ -2826,9 +2976,10 @@ TclpObjNormalizePath(
* End of string was reached above.
*/
- Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&ds), nextCheckpoint);
+ Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&dsTemp),
+ nextCheckpoint);
}
- Tcl_DStringFree(&ds);
+ Tcl_DStringFree(&dsTemp);
}
Tcl_DStringFree(&dsNorm);
@@ -2840,7 +2991,6 @@ TclpObjNormalizePath(
if (temp != NULL) {
Tcl_DecrRefCount(temp);
}
-
return nextCheckpoint;
}
@@ -2887,10 +3037,10 @@ TclWinVolumeRelativeNormalize(
* current volume.
*/
- const char *drive = TclGetString(useThisCwd);
+ const char *drive = Tcl_GetString(useThisCwd);
absolutePath = Tcl_NewStringObj(drive,2);
- Tcl_AppendToObj(absolutePath, path, TCL_INDEX_NONE);
+ Tcl_AppendToObj(absolutePath, path, -1);
Tcl_IncrRefCount(absolutePath);
/*
@@ -2902,8 +3052,9 @@ TclWinVolumeRelativeNormalize(
* also on drive C.
*/
- Tcl_Size cwdLen;
- const char *drive = TclGetStringFromObj(useThisCwd, &cwdLen);
+ int cwdLen;
+ const char *drive =
+ Tcl_GetStringFromObj(useThisCwd, &cwdLen);
char drive_cur = path[0];
if (drive_cur >= 'a') {
@@ -2943,7 +3094,7 @@ TclWinVolumeRelativeNormalize(
Tcl_AppendToObj(absolutePath, "/", 1);
}
Tcl_IncrRefCount(absolutePath);
- Tcl_AppendToObj(absolutePath, path+2, TCL_INDEX_NONE);
+ Tcl_AppendToObj(absolutePath, path+2, -1);
}
*useThisCwdPtr = useThisCwd;
return absolutePath;
@@ -2972,15 +3123,14 @@ TclWinVolumeRelativeNormalize(
Tcl_Obj *
TclpNativeToNormalized(
- void *clientData)
+ ClientData clientData)
{
Tcl_DString ds;
Tcl_Obj *objPtr;
- Tcl_Size len;
+ int len;
char *copy, *p;
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString((const WCHAR *) clientData, TCL_INDEX_NONE, &ds);
+ Tcl_WinTCharToUtf((const char *) clientData, -1, &ds);
copy = Tcl_DStringValue(&ds);
len = Tcl_DStringLength(&ds);
@@ -3027,20 +3177,19 @@ TclpNativeToNormalized(
* The nativePath representation.
*
* Side effects:
- * Memory will be allocated. The path might be normalized.
+ * Memory will be allocated. The path may need to be normalized.
*
*---------------------------------------------------------------------------
*/
-void *
+ClientData
TclNativeCreateNativeRep(
Tcl_Obj *pathPtr)
{
- WCHAR *nativePathPtr = NULL;
- const char *str;
+ char *nativePathPtr, *str;
+ Tcl_DString ds;
Tcl_Obj *validPathPtr;
- Tcl_Size len;
- WCHAR *wp;
+ int len;
if (TclFSCwdIsNative()) {
/*
@@ -3053,11 +3202,6 @@ TclNativeCreateNativeRep(
if (validPathPtr == NULL) {
return NULL;
}
-
- /*
- * refCount of validPathPtr was already incremented in
- * Tcl_FSGetTranslatedPath
- */
} else {
/*
* Make sure the normalized path is set.
@@ -3067,113 +3211,87 @@ TclNativeCreateNativeRep(
if (validPathPtr == NULL) {
return NULL;
}
-
- /*
- * validPathPtr returned from Tcl_FSGetNormalizedPath is owned by Tcl,
- * so incr refCount here
- */
-
Tcl_IncrRefCount(validPathPtr);
}
- str = TclGetStringFromObj(validPathPtr, &len);
-
- if (strlen(str) != (size_t)len) {
+ str = Tcl_GetStringFromObj(validPathPtr, &len);
+ Tcl_WinUtfToTChar(str, len, &ds);
+ if (tclWinProcs->useWide) {
+ WCHAR *wp = (WCHAR *) Tcl_DStringValue(&ds);
+ /* For a reserved device, strip a possible postfix ':' */
+ len = WinIsReserved(str);
+ /* For normal devices */
+ if (len == 0) len = Tcl_DStringLength(&ds)>>1;
/*
- * String contains NUL-bytes. This is invalid.
- */
-
- goto done;
- }
-
- /*
- * For a reserved device, strip a possible postfix ':'
- */
-
- len = WinIsReserved(str);
- if (len == 0) {
+ ** If path starts with "//?/" or "\\?\" (extended path), translate
+ ** any slashes to backslashes but accept the '?' as being valid.
+ */
+ if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/')
+ && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) {
+ wp[0] = wp[1] = wp[3] = '\\';
+ str += 4;
+ wp += 4;
+ len -= 4;
+ }
/*
- * Let MultiByteToWideChar check for other invalid sequences, like
- * 0xC0 0x80 (== overlong NUL). See bug [3118489]: NUL in filenames
- */
-
- len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, 0, 0);
- if (len==0) {
- goto done;
+ ** If there is a drive prefix, the ':' must be considered valid.
+ **/
+ if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z'))
+ && str[1]==':') {
+ wp += 2;
+ len -= 2;
}
- }
-
- /*
- * Overallocate 6 chars, making some room for extended paths
- */
-
- wp = nativePathPtr = (WCHAR *)ckalloc((len + 6) * sizeof(WCHAR));
- if (nativePathPtr==0) {
- goto done;
- }
- MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, nativePathPtr,
- len + 2);
- nativePathPtr[len] = 0;
-
- /*
- * If path starts with "//?/" or "\\?\" (extended path), translate any
- * slashes to backslashes but leave the '?' intact
- */
-
- if ((str[0] == '\\' || str[0] == '/') && (str[1] == '\\' || str[1] == '/')
- && str[2] == '?' && (str[3] == '\\' || str[3] == '/')) {
- wp[0] = wp[1] = wp[3] = '\\';
- str += 4;
- wp += 4;
- }
-
- /*
- * If there is no "\\?\" prefix but there is a drive or UNC path prefix
- * and the path is larger than MAX_PATH chars, no Win32 API function can
- * handle that unless it is prefixed with the extended path prefix. See:
- * <https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maxpath>
- */
-
- if (((str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= 'a' && str[0] <= 'z'))
- && str[1] == ':') {
- if (wp == nativePathPtr && len > MAX_PATH
- && (str[2] == '\\' || str[2] == '/')) {
- memmove(wp + 4, wp, len * sizeof(WCHAR));
- memcpy(wp, L"\\\\?\\", 4 * sizeof(WCHAR));
- wp += 4;
+ while (len-->0) {
+ if ((*wp < ' ') || wcschr(L"\"*:<>?|", *wp)) {
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ } else if (*wp=='/') {
+ *wp = '\\';
+ }
+ ++wp;
}
-
+ len = Tcl_DStringLength(&ds) + sizeof(WCHAR);
+ } else {
+ char *p = Tcl_DStringValue(&ds);
+ len = Tcl_DStringLength(&ds);
/*
- * If (remainder of) path starts with "<drive>:", leave the ':'
- * intact.
- */
-
- wp += 2;
- } else if (wp == nativePathPtr && len > MAX_PATH
- && (str[0] == '\\' || str[0] == '/')
- && (str[1] == '\\' || str[1] == '/') && str[2] != '?') {
- memmove(wp + 6, wp, len * sizeof(WCHAR));
- memcpy(wp, L"\\\\?\\UNC", 7 * sizeof(WCHAR));
- wp += 7;
- }
-
- /*
- * In the remainder of the path, translate invalid characters to
- * characters in the Unicode private use area.
- */
-
- while (*wp != '\0') {
- if ((*wp < ' ') || wcschr(L"\"*:<>?|", *wp)) {
- *wp |= 0xF000;
- } else if (*wp == '/') {
- *wp = '\\';
+ ** If path starts with "//?/" or "\\?\" (extended path), translate
+ ** any slashes to backslashes but accept the '?' as being valid.
+ */
+ if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/')
+ && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) {
+ p[0] = p[1] = p[3] = '\\';
+ str += 4;
+ p += 4;
+ len -= 4;
+ }
+ /*
+ ** If there is a drive prefix, the ':' must be considered valid.
+ **/
+ if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z'))
+ && str[1]==':') {
+ p += 2;
+ len -= 2;
+ }
+ while (len-->0) {
+ if ((*p < ' ') || strchr("\"*:<>?|", *p)) {
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ } else if (*p=='/') {
+ *p = '\\';
+ }
+ ++p;
}
- ++wp;
+ len = Tcl_DStringLength(&ds) + sizeof(char);
}
+ Tcl_DecrRefCount(validPathPtr);
+ nativePathPtr = ckalloc((unsigned) len);
+ memcpy(nativePathPtr, Tcl_DStringValue(&ds), (size_t) len);
- done:
- TclDecrRefCount(validPathPtr);
- return nativePathPtr;
+ Tcl_DStringFree(&ds);
+ return (ClientData) nativePathPtr;
}
/*
@@ -3193,9 +3311,9 @@ TclNativeCreateNativeRep(
*---------------------------------------------------------------------------
*/
-void *
+ClientData
TclNativeDupInternalRep(
- void *clientData)
+ ClientData clientData)
{
char *copy;
size_t len;
@@ -3204,11 +3322,23 @@ TclNativeDupInternalRep(
return NULL;
}
- len = sizeof(WCHAR) * (wcslen((const WCHAR *) clientData) + 1);
+ if (tclWinProcs->useWide) {
+ /*
+ * Unicode representation when running on NT/2K/XP.
+ */
+
+ len = sizeof(WCHAR) * (wcslen((const WCHAR *) clientData) + 1);
+ } else {
+ /*
+ * ANSI representation when running on 95/98/ME.
+ */
- copy = (char *)ckalloc(len);
+ len = sizeof(char) * (strlen((const char *) clientData) + 1);
+ }
+
+ copy = (char *) ckalloc(len);
memcpy(copy, clientData, len);
- return copy;
+ return (ClientData) copy;
}
/*
@@ -3235,7 +3365,7 @@ TclpUtime(
{
int res = 0;
HANDLE fileHandle;
- const WCHAR *native;
+ const TCHAR *native;
DWORD attr = 0;
DWORD flags = FILE_ATTRIBUTE_NORMAL;
FILETIME lastAccessTime, lastModTime;
@@ -3243,9 +3373,9 @@ TclpUtime(
FromCTime(tval->actime, &lastAccessTime);
FromCTime(tval->modtime, &lastModTime);
- native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ native = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
- attr = GetFileAttributesW(native);
+ attr = (*tclWinProcs->getFileAttributesProc)(native);
if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY) {
flags = FILE_FLAG_BACKUP_SEMANTICS;
@@ -3256,12 +3386,12 @@ TclpUtime(
* savings complications that utime gets wrong.
*/
- fileHandle = CreateFileW(native, FILE_WRITE_ATTRIBUTES, 0, NULL,
- OPEN_EXISTING, flags, NULL);
+ fileHandle = (tclWinProcs->createFileProc)(native, FILE_WRITE_ATTRIBUTES,
+ 0, NULL, OPEN_EXISTING, flags, NULL);
if (fileHandle == INVALID_HANDLE_VALUE ||
!SetFileTime(fileHandle, NULL, &lastAccessTime, &lastModTime)) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
res = -1;
}
if (fileHandle != INVALID_HANDLE_VALUE) {
@@ -3271,80 +3401,6 @@ TclpUtime(
}
/*
- *---------------------------------------------------------------------------
- *
- * TclWinFileOwned --
- *
- * Returns 1 if the specified file exists and is owned by the current
- * user and 0 otherwise. Like the Unix case, the check is made using
- * the real process SID, not the effective (impersonation) one.
- *
- *---------------------------------------------------------------------------
- */
-
-int
-TclWinFileOwned(
- Tcl_Obj *pathPtr) /* File whose ownership is to be checked */
-{
- const WCHAR *native;
- PSID ownerSid = NULL;
- PSECURITY_DESCRIPTOR secd = NULL;
- HANDLE token;
- LPBYTE buf = NULL;
- DWORD bufsz;
- int owned = 0;
-
- native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
-
- if (GetNamedSecurityInfoW((LPWSTR) native, SE_FILE_OBJECT,
- OWNER_SECURITY_INFORMATION, &ownerSid, NULL, NULL, NULL,
- &secd) != ERROR_SUCCESS) {
- /*
- * Either not a file, or we do not have access to it in which case we
- * are in all likelihood not the owner.
- */
-
- return 0;
- }
-
- /*
- * Getting the current process SID is a multi-step process. We make the
- * assumption that if a call fails, this process is so underprivileged it
- * could not possibly own anything. Normally a process can *always* look
- * up its own token.
- */
-
- if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
- /*
- * Find out how big the buffer needs to be.
- */
-
- bufsz = 0;
- GetTokenInformation(token, TokenUser, NULL, 0, &bufsz);
- if (bufsz) {
- buf = (LPBYTE)ckalloc(bufsz);
- if (GetTokenInformation(token, TokenUser, buf, bufsz, &bufsz)) {
- owned = EqualSid(ownerSid, ((PTOKEN_USER) buf)->User.Sid);
- }
- }
- CloseHandle(token);
- }
-
- /*
- * Free allocations and be done.
- */
-
- if (secd) {
- LocalFree(secd); /* Also frees ownerSid */
- }
- if (buf) {
- ckfree(buf);
- }
-
- return (owned != 0); /* Convert non-0 to 1 */
-}
-
-/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff --git a/win/tclWinInit.c b/win/tclWinInit.c
index 3764a79..4e860b2 100644
--- a/win/tclWinInit.c
+++ b/win/tclWinInit.c
@@ -3,8 +3,8 @@
*
* Contains the Windows-specific interpreter initialization functions.
*
- * Copyright © 1994-1997 Sun Microsystems, Inc.
- * Copyright © 1998-1999 Scriptics Corporation.
+ * Copyright (c) 1994-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1998-1999 by Scriptics Corporation.
* All rights reserved.
*
* See the file "license.terms" for information on usage and redistribution of
@@ -17,7 +17,7 @@
#include <lmcons.h>
/*
- * GetUserNameW() is found in advapi32.dll
+ * GetUserName() is found in advapi32.dll
*/
#ifdef _MSC_VER
# pragma comment(lib, "advapi32.lib")
@@ -36,14 +36,61 @@ typedef struct {
} OemId;
/*
- * The following arrays contain the human readable strings for the
- * processor values.
+ * The following macros are missing from some versions of winnt.h.
*/
-#define NUMPROCESSORS 15
-static const char *const processors[NUMPROCESSORS] = {
+#ifndef PROCESSOR_ARCHITECTURE_INTEL
+#define PROCESSOR_ARCHITECTURE_INTEL 0
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_MIPS
+#define PROCESSOR_ARCHITECTURE_MIPS 1
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_ALPHA
+#define PROCESSOR_ARCHITECTURE_ALPHA 2
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_PPC
+#define PROCESSOR_ARCHITECTURE_PPC 3
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_SHX
+#define PROCESSOR_ARCHITECTURE_SHX 4
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_ARM
+#define PROCESSOR_ARCHITECTURE_ARM 5
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_IA64
+#define PROCESSOR_ARCHITECTURE_IA64 6
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_ALPHA64
+#define PROCESSOR_ARCHITECTURE_ALPHA64 7
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_MSIL
+#define PROCESSOR_ARCHITECTURE_MSIL 8
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_AMD64
+#define PROCESSOR_ARCHITECTURE_AMD64 9
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
+#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10
+#endif
+#ifndef PROCESSOR_ARCHITECTURE_UNKNOWN
+#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF
+#endif
+
+/*
+ * The following arrays contain the human readable strings for the Windows
+ * platform and processor values.
+ */
+
+
+#define NUMPLATFORMS 4
+static char* platforms[NUMPLATFORMS] = {
+ "Win32s", "Windows 95", "Windows NT", "Windows CE"
+};
+
+#define NUMPROCESSORS 11
+static char* processors[NUMPROCESSORS] = {
"intel", "mips", "alpha", "ppc", "shx", "arm", "ia64", "alpha64", "msil",
- "amd64", "ia32_on_win64", "neutral", "arm64", "arm32_on_win64", "ia32_on_arm64"
+ "amd64", "ia32_on_win64"
};
/*
@@ -58,14 +105,15 @@ static TclInitProcessGlobalValueProc InitializeSourceLibraryDir;
static ProcessGlobalValue sourceLibraryDir =
{0, 0, NULL, NULL, InitializeSourceLibraryDir, NULL, NULL};
-static void AppendEnvironment(Tcl_Obj *listPtr, const char *lib);
+static void AppendEnvironment(Tcl_Obj *listPtr, CONST char *lib);
+static int ToUtf(CONST WCHAR *wSrc, char *dst);
/*
*---------------------------------------------------------------------------
*
* TclpInitPlatform --
*
- * Initialize all the platform-dependent things like signals,
+ * Initialize all the platform-dependant things like signals,
* floating-point error handling and sockets.
*
* Called at process initialization time.
@@ -87,11 +135,11 @@ TclpInitPlatform(void)
tclPlatform = TCL_PLATFORM_WINDOWS;
- /*
- * Initialize the winsock library. On Windows XP and higher this
- * can never fail.
- */
- WSAStartup(wVersionRequested, &wsaData);
+ /*
+ * Initialize the winsock library. On Windows XP and higher this
+ * can never fail.
+ */
+ WSAStartup(wVersionRequested, &wsaData);
#ifdef STATIC_BUILD
/*
@@ -100,7 +148,7 @@ TclpInitPlatform(void)
* invoked.
*/
- TclWinInit(GetModuleHandleW(NULL));
+ TclWinInit(GetModuleHandle(NULL));
#endif
}
@@ -124,16 +172,15 @@ TclpInitPlatform(void)
void
TclpInitLibraryPath(
char **valuePtr,
- TCL_HASH_TYPE *lengthPtr,
+ int *lengthPtr,
Tcl_Encoding *encodingPtr)
{
#define LIBRARY_SIZE 64
Tcl_Obj *pathPtr;
char installLib[LIBRARY_SIZE];
- const char *bytes;
- Tcl_Size length;
+ char *bytes;
- TclNewObj(pathPtr);
+ pathPtr = Tcl_NewObj();
/*
* Initialize the substring used when locating the script library. The
@@ -141,13 +188,13 @@ TclpInitLibraryPath(
* installed DLL.
*/
- snprintf(installLib, sizeof(installLib), "lib/tcl%s", TCL_VERSION);
+ sprintf(installLib, "lib/tcl%s", TCL_VERSION);
/*
* Look for the library relative to the TCL_LIBRARY env variable. If the
* last dirname in the TCL_LIBRARY path does not match the last dirname in
* the installLib variable, use the last dir name of installLib in
- * addition to the original TCL_LIBRARY path.
+ * addition to the orginal TCL_LIBRARY path.
*/
AppendEnvironment(pathPtr, installLib);
@@ -167,10 +214,9 @@ TclpInitLibraryPath(
TclGetProcessGlobalValue(&sourceLibraryDir));
*encodingPtr = NULL;
- bytes = TclGetStringFromObj(pathPtr, &length);
- *lengthPtr = length++;
- *valuePtr = (char *)ckalloc(length);
- memcpy(*valuePtr, bytes, length);
+ bytes = Tcl_GetStringFromObj(pathPtr, lengthPtr);
+ *valuePtr = ckalloc((unsigned int)(*lengthPtr)+1);
+ memcpy(*valuePtr, bytes, (size_t)(*lengthPtr)+1);
Tcl_DecrRefCount(pathPtr);
}
@@ -196,14 +242,14 @@ TclpInitLibraryPath(
static void
AppendEnvironment(
Tcl_Obj *pathPtr,
- const char *lib)
+ CONST char *lib)
{
- Tcl_Size pathc;
+ int pathc;
WCHAR wBuf[MAX_PATH];
- char buf[MAX_PATH * 3];
+ char buf[MAX_PATH * TCL_UTF_MAX];
Tcl_Obj *objPtr;
Tcl_DString ds;
- const char **pathv;
+ CONST char **pathv;
char *shortlib;
/*
@@ -213,7 +259,7 @@ AppendEnvironment(
for (shortlib = (char *) &lib[strlen(lib)-1]; shortlib>lib ; shortlib--) {
if (*shortlib == '/') {
- if ((size_t)(shortlib - lib) == strlen(lib) - 1) {
+ if ((unsigned)(shortlib - lib) == strlen(lib) - 1) {
Tcl_Panic("last character in lib cannot be '/'");
}
shortlib++;
@@ -225,26 +271,32 @@ AppendEnvironment(
}
/*
- * The "L" preceding the TCL_LIBRARY string is used to tell VC++ that
- * this is a Unicode string.
+ * The "L" preceeding the TCL_LIBRARY string is used to tell VC++ that
+ * this is a unicode string.
*/
- GetEnvironmentVariableW(L"TCL_LIBRARY", wBuf, MAX_PATH);
- WideCharToMultiByte(CP_UTF8, 0, wBuf, -1, buf, MAX_PATH * 3, NULL, NULL);
+ if (GetEnvironmentVariableW(L"TCL_LIBRARY", wBuf, MAX_PATH) == 0) {
+ buf[0] = '\0';
+ GetEnvironmentVariableA("TCL_LIBRARY", buf, MAX_PATH);
+ } else {
+ ToUtf(wBuf, buf);
+ }
if (buf[0] != '\0') {
- objPtr = Tcl_NewStringObj(buf, TCL_INDEX_NONE);
+ objPtr = Tcl_NewStringObj(buf, -1);
Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
TclWinNoBackslash(buf);
Tcl_SplitPath(buf, &pathc, &pathv);
/*
- * The lstrcmpiA() will work even if pathv[pathc-1] is random UTF-8
+ * The lstrcmpi() will work even if pathv[pathc-1] is random UTF-8
* chars because I know shortlib is ascii.
*/
if ((pathc > 0) && (lstrcmpiA(shortlib, pathv[pathc - 1]) != 0)) {
+ CONST char *str;
+
/*
* TCL_LIBRARY is set but refers to a different tcl installation
* than the current version. Try fiddling with the specified
@@ -254,13 +306,14 @@ AppendEnvironment(
pathv[pathc - 1] = shortlib;
Tcl_DStringInit(&ds);
- (void) Tcl_JoinPath(pathc, pathv, &ds);
- objPtr = Tcl_DStringToObj(&ds);
+ str = Tcl_JoinPath(pathc, pathv, &ds);
+ objPtr = Tcl_NewStringObj(str, Tcl_DStringLength(&ds));
+ Tcl_DStringFree(&ds);
} else {
- objPtr = Tcl_NewStringObj(buf, TCL_INDEX_NONE);
+ objPtr = Tcl_NewStringObj(buf, -1);
}
Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
- ckfree(pathv);
+ ckfree((char *) pathv);
}
}
@@ -284,16 +337,19 @@ AppendEnvironment(
static void
InitializeDefaultLibraryDir(
char **valuePtr,
- TCL_HASH_TYPE *lengthPtr,
+ int *lengthPtr,
Tcl_Encoding *encodingPtr)
{
- HMODULE hModule = (HMODULE)TclWinGetTclInstance();
+ HMODULE hModule = TclWinGetTclInstance();
WCHAR wName[MAX_PATH + LIBRARY_SIZE];
- char name[(MAX_PATH + LIBRARY_SIZE) * 3];
+ char name[(MAX_PATH + LIBRARY_SIZE) * TCL_UTF_MAX];
char *end, *p;
- GetModuleFileNameW(hModule, wName, sizeof(wName)/sizeof(WCHAR));
- WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL, NULL);
+ if (GetModuleFileNameW(hModule, wName, MAX_PATH) == 0) {
+ GetModuleFileNameA(hModule, name, MAX_PATH);
+ } else {
+ ToUtf(wName, name);
+ }
end = strrchr(name, '\\');
*end = '\0';
@@ -304,11 +360,11 @@ InitializeDefaultLibraryDir(
*end = '\\';
TclWinNoBackslash(name);
- snprintf(end + 1, LIBRARY_SIZE, "lib/tcl%s", TCL_VERSION);
+ sprintf(end + 1, "lib/tcl%s", TCL_VERSION);
*lengthPtr = strlen(name);
- *valuePtr = (char *)ckalloc(*lengthPtr + 1);
+ *valuePtr = ckalloc(*lengthPtr + 1);
*encodingPtr = NULL;
- memcpy(*valuePtr, name, *lengthPtr + 1);
+ memcpy(*valuePtr, name, (size_t) *lengthPtr + 1);
}
/*
@@ -332,16 +388,19 @@ InitializeDefaultLibraryDir(
static void
InitializeSourceLibraryDir(
char **valuePtr,
- TCL_HASH_TYPE *lengthPtr,
+ int *lengthPtr,
Tcl_Encoding *encodingPtr)
{
- HMODULE hModule = (HMODULE)TclWinGetTclInstance();
+ HMODULE hModule = TclWinGetTclInstance();
WCHAR wName[MAX_PATH + LIBRARY_SIZE];
- char name[(MAX_PATH + LIBRARY_SIZE) * 3];
+ char name[(MAX_PATH + LIBRARY_SIZE) * TCL_UTF_MAX];
char *end, *p;
- GetModuleFileNameW(hModule, wName, sizeof(wName)/sizeof(WCHAR));
- WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL, NULL);
+ if (GetModuleFileNameW(hModule, wName, MAX_PATH) == 0) {
+ GetModuleFileNameA(hModule, name, MAX_PATH);
+ } else {
+ ToUtf(wName, name);
+ }
end = strrchr(name, '\\');
*end = '\0';
@@ -352,11 +411,68 @@ InitializeSourceLibraryDir(
*end = '\\';
TclWinNoBackslash(name);
- snprintf(end + 1, LIBRARY_SIZE, "../library");
+ sprintf(end + 1, "../library");
*lengthPtr = strlen(name);
- *valuePtr = (char *)ckalloc(*lengthPtr + 1);
+ *valuePtr = ckalloc((unsigned int) *lengthPtr + 1);
*encodingPtr = NULL;
- memcpy(*valuePtr, name, *lengthPtr + 1);
+ memcpy(*valuePtr, name, (size_t) *lengthPtr + 1);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * ToUtf --
+ *
+ * Convert a char string to a UTF string.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static int
+ToUtf(
+ CONST WCHAR *wSrc,
+ char *dst)
+{
+ char *start;
+
+ start = dst;
+ while (*wSrc != '\0') {
+ dst += Tcl_UniCharToUtf(*wSrc, dst);
+ wSrc++;
+ }
+ *dst = '\0';
+ return (int) (dst - start);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TclWinEncodingsCleanup --
+ *
+ * Reset information to its original state in finalization to allow for
+ * reinitialization to be possible. This must not be called until after
+ * the filesystem has been finalised, or exit crashes may occur when
+ * using virtual filesystems.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Static information reset to startup state.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+TclWinEncodingsCleanup(void)
+{
+ TclWinResetInterfaceEncodings();
}
/*
@@ -388,49 +504,34 @@ TclpSetInitialEncodings(void)
{
Tcl_DString encodingName;
+ TclpSetInterfaces();
Tcl_SetSystemEncoding(NULL,
Tcl_GetEncodingNameFromEnvironment(&encodingName));
Tcl_DStringFree(&encodingName);
}
-const char *
+void
+TclpSetInterfaces(void)
+{
+ int platformId, useWide;
+
+ platformId = TclWinGetPlatformId();
+ useWide = ((platformId == VER_PLATFORM_WIN32_NT)
+ || (platformId == VER_PLATFORM_WIN32_CE));
+ TclWinSetInterfaces(useWide);
+}
+
+CONST char *
Tcl_GetEncodingNameFromEnvironment(
Tcl_DString *bufPtr)
{
- UINT acp = GetACP();
-
Tcl_DStringInit(bufPtr);
- if (acp == CP_UTF8) {
- Tcl_DStringAppend(bufPtr, "utf-8", 5);
- } else {
- Tcl_DStringSetLength(bufPtr, 2+TCL_INTEGER_SPACE);
- snprintf(Tcl_DStringValue(bufPtr), 2+TCL_INTEGER_SPACE, "cp%d", GetACP());
- Tcl_DStringSetLength(bufPtr, strlen(Tcl_DStringValue(bufPtr)));
- }
+ Tcl_DStringSetLength(bufPtr, 2+TCL_INTEGER_SPACE);
+ wsprintfA(Tcl_DStringValue(bufPtr), "cp%d", GetACP());
+ Tcl_DStringSetLength(bufPtr, strlen(Tcl_DStringValue(bufPtr)));
return Tcl_DStringValue(bufPtr);
}
-const char *
-TclpGetUserName(
- Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
- * the name of user. */
-{
- Tcl_DStringInit(bufferPtr);
-
- if (TclGetEnv("USERNAME", bufferPtr) == NULL) {
- WCHAR szUserName[UNLEN+1];
- DWORD cchUserNameLen = UNLEN;
-
- if (!GetUserNameW(szUserName, &cchUserNameLen)) {
- return NULL;
- }
- cchUserNameLen--;
- Tcl_DStringInit(bufferPtr);
- Tcl_WCharToUtfDString(szUserName, cchUserNameLen, bufferPtr);
- }
- return Tcl_DStringValue(bufferPtr);
-}
-
/*
*---------------------------------------------------------------------------
*
@@ -452,7 +553,7 @@ void
TclpSetVariables(
Tcl_Interp *interp) /* Interp to initialize. */
{
- const char *ptr;
+ CONST char *ptr;
char buffer[TCL_INTEGER_SPACE * 2];
union {
SYSTEM_INFO info;
@@ -461,18 +562,23 @@ TclpSetVariables(
static OSVERSIONINFOW osInfo;
static int osInfoInitialized = 0;
Tcl_DString ds;
+ WCHAR szUserName[UNLEN+1];
+ DWORD cchUserNameLen = UNLEN;
Tcl_SetVar2Ex(interp, "tclDefaultLibrary", NULL,
TclGetProcessGlobalValue(&defaultLibraryDir), TCL_GLOBAL_ONLY);
if (!osInfoInitialized) {
- HMODULE handle = GetModuleHandleW(L"NTDLL");
+ HANDLE handle = LoadLibraryW(L"NTDLL");
int(__stdcall *getversion)(void *) =
- (int(__stdcall *)(void *))(void *)GetProcAddress(handle, "RtlGetVersion");
+ (int(__stdcall *)(void *)) GetProcAddress(handle, "RtlGetVersion");
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
if (!getversion || getversion(&osInfo)) {
GetVersionExW(&osInfo);
}
+ if (handle) {
+ FreeLibrary(handle);
+ }
osInfoInitialized = 1;
}
GetSystemInfo(&sys.info);
@@ -483,12 +589,11 @@ TclpSetVariables(
Tcl_SetVar2(interp, "tcl_platform", "platform", "windows",
TCL_GLOBAL_ONLY);
- Tcl_SetVar2(interp, "tcl_platform", "os",
- "Windows NT", TCL_GLOBAL_ONLY);
- if (osInfo.dwMajorVersion == 10 && osInfo.dwBuildNumber >= 22000) {
- osInfo.dwMajorVersion = 11;
+ if (osInfo.dwPlatformId < NUMPLATFORMS) {
+ Tcl_SetVar2(interp, "tcl_platform", "os",
+ platforms[osInfo.dwPlatformId], TCL_GLOBAL_ONLY);
}
- snprintf(buffer, sizeof(buffer), "%ld.%ld", osInfo.dwMajorVersion, osInfo.dwMinorVersion);
+ wsprintfA(buffer, "%d.%d", osInfo.dwMajorVersion, osInfo.dwMinorVersion);
Tcl_SetVar2(interp, "tcl_platform", "osVersion", buffer, TCL_GLOBAL_ONLY);
if (sys.oemId.wProcessorArchitecture < NUMPROCESSORS) {
Tcl_SetVar2(interp, "tcl_platform", "machine",
@@ -496,8 +601,7 @@ TclpSetVariables(
TCL_GLOBAL_ONLY);
}
-#if !defined(NDEBUG) && !defined(TCL_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9
-
+#ifndef NDEBUG
/*
* The existence of the "debug" element of the tcl_platform array
* indicates that this particular Tcl shell has been compiled with debug
@@ -520,24 +624,17 @@ TclpSetVariables(
if (ptr == NULL) {
ptr = Tcl_GetVar2(interp, "env", "HOMEDRIVE", TCL_GLOBAL_ONLY);
if (ptr != NULL) {
- Tcl_DStringAppend(&ds, ptr, TCL_INDEX_NONE);
+ Tcl_DStringAppend(&ds, ptr, -1);
}
ptr = Tcl_GetVar2(interp, "env", "HOMEPATH", TCL_GLOBAL_ONLY);
if (ptr != NULL) {
- Tcl_DStringAppend(&ds, ptr, TCL_INDEX_NONE);
+ Tcl_DStringAppend(&ds, ptr, -1);
}
if (Tcl_DStringLength(&ds) > 0) {
Tcl_SetVar2(interp, "env", "HOME", Tcl_DStringValue(&ds),
TCL_GLOBAL_ONLY);
} else {
- /* None of HOME, HOMEDRIVE, HOMEPATH exists. Try USERPROFILE */
- ptr = Tcl_GetVar2(interp, "env", "USERPROFILE", TCL_GLOBAL_ONLY);
- if (ptr != NULL && ptr[0]) {
- Tcl_SetVar2(interp, "env", "HOME", ptr, TCL_GLOBAL_ONLY);
- } else {
- /* Last resort */
- Tcl_SetVar2(interp, "env", "HOME", "c:\\", TCL_GLOBAL_ONLY);
- }
+ Tcl_SetVar2(interp, "env", "HOME", "c:\\", TCL_GLOBAL_ONLY);
}
}
@@ -547,16 +644,17 @@ TclpSetVariables(
* Note: cchUserNameLen is number of characters including nul terminator.
*/
- ptr = TclpGetUserName(&ds);
- Tcl_SetVar2(interp, "tcl_platform", "user", ptr ? ptr : "",
+ Tcl_DStringInit(&ds);
+ if (TclGetEnv("USERNAME", &ds) == NULL) {
+ if (tclWinProcs->getUserName((LPTSTR)szUserName, &cchUserNameLen) != 0) {
+ int cbUserNameLen = cchUserNameLen - 1;
+ if (tclWinProcs->useWide) cbUserNameLen *= sizeof(WCHAR);
+ Tcl_WinTCharToUtf((LPTSTR)szUserName, cbUserNameLen, &ds);
+ }
+ }
+ Tcl_SetVar2(interp, "tcl_platform", "user", Tcl_DStringValue(&ds),
TCL_GLOBAL_ONLY);
Tcl_DStringFree(&ds);
-
- /*
- * Define what the platform PATH separator is. [TIP #315]
- */
-
- Tcl_SetVar2(interp, "tcl_platform","pathSeparator", ";", TCL_GLOBAL_ONLY);
}
/*
@@ -565,7 +663,7 @@ TclpSetVariables(
* TclpFindVariable --
*
* Locate the entry in environ for a given name. On Unix this routine is
- * case sensitive, on Windows this matches mixed case.
+ * case sensitive, on Windows this matches mioxed case.
*
* Results:
* The return value is the index in environ of an entry with the name
@@ -579,18 +677,17 @@ TclpSetVariables(
*----------------------------------------------------------------------
*/
-Tcl_Size
+int
TclpFindVariable(
- const char *name, /* Name of desired environment variable
+ CONST char *name, /* Name of desired environment variable
* (UTF-8). */
- Tcl_Size *lengthPtr) /* Used to return length of name (for
+ int *lengthPtr) /* Used to return length of name (for
* successful searches) or number of non-NULL
* entries in environ (for unsuccessful
* searches). */
{
- Tcl_Size i, length, result = TCL_INDEX_NONE;
- const WCHAR *env;
- const char *p1, *p2;
+ int i, length, result = -1;
+ register CONST char *env, *p1, *p2;
char *envUpper, *nameUpper;
Tcl_DString envString;
@@ -599,25 +696,24 @@ TclpFindVariable(
*/
length = strlen(name);
- nameUpper = (char *)ckalloc(length + 1);
- memcpy(nameUpper, name, length+1);
+ nameUpper = (char *) ckalloc((unsigned) length+1);
+ memcpy(nameUpper, name, (size_t) length+1);
Tcl_UtfToUpper(nameUpper);
Tcl_DStringInit(&envString);
- for (i = 0, env = _wenviron[i]; env != NULL; i++, env = _wenviron[i]) {
+ for (i = 0, env = environ[i]; env != NULL; i++, env = environ[i]) {
/*
* Chop the env string off after the equal sign, then Convert the name
* to all upper case, so we do not have to convert all the characters
* after the equal sign.
*/
- Tcl_DStringInit(&envString);
- envUpper = Tcl_WCharToUtfDString(env, TCL_INDEX_NONE, &envString);
+ envUpper = Tcl_ExternalToUtfDString(NULL, env, -1, &envString);
p1 = strchr(envUpper, '=');
if (p1 == NULL) {
continue;
}
- length = p1 - envUpper;
+ length = (int) (p1 - envUpper);
Tcl_DStringSetLength(&envString, length+1);
Tcl_UtfToUpper(envUpper);
diff --git a/win/tclWinInt.h b/win/tclWinInt.h
index dfe4d10..ccf48bb 100644
--- a/win/tclWinInt.h
+++ b/win/tclWinInt.h
@@ -32,99 +32,178 @@ typedef struct TCLEXCEPTION_REGISTRATION {
#endif
/*
+ * The following specifies how much stack space TclpCheckStackSpace()
+ * ensures is available. TclpCheckStackSpace() is called by Tcl_EvalObj()
+ * to help avoid overflowing the stack in the case of infinite recursion.
+ */
+
+#define TCL_WIN_STACK_THRESHOLD 0x8000
+
+/*
+ * Some versions of Borland C have a define for the OSVERSIONINFO for
+ * Win32s and for NT, but not for Windows 95.
+ * Define VER_PLATFORM_WIN32_CE for those without newer headers.
+ */
+
+#ifndef VER_PLATFORM_WIN32_WINDOWS
+#define VER_PLATFORM_WIN32_WINDOWS 1
+#endif
+#ifndef VER_PLATFORM_WIN32_CE
+#define VER_PLATFORM_WIN32_CE 3
+#endif
+
+#ifdef _WIN64
+# define TCL_I_MODIFIER "I"
+#else
+# define TCL_I_MODIFIER ""
+#endif
+
+/*
+ * The following structure keeps track of whether we are using the
+ * multi-byte or the wide-character interfaces to the operating system.
+ * System calls should be made through the following function table.
+ */
+
+typedef union {
+ WIN32_FIND_DATAA a;
+ WIN32_FIND_DATAW w;
+} WIN32_FIND_DATAT;
+
+typedef struct TclWinProcs {
+ int useWide;
+
+ BOOL (WINAPI *buildCommDCBProc)(CONST TCHAR *, LPDCB);
+ TCHAR *(WINAPI *charLowerProc)(TCHAR *);
+ BOOL (WINAPI *copyFileProc)(CONST TCHAR *, CONST TCHAR *, BOOL);
+ BOOL (WINAPI *createDirectoryProc)(CONST TCHAR *, LPSECURITY_ATTRIBUTES);
+ HANDLE (WINAPI *createFileProc)(CONST TCHAR *, DWORD, DWORD,
+ LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
+ BOOL (WINAPI *createProcessProc)(CONST TCHAR *, TCHAR *,
+ LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD,
+ LPVOID, CONST TCHAR *, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
+ BOOL (WINAPI *deleteFileProc)(CONST TCHAR *);
+ HANDLE (WINAPI *findFirstFileProc)(CONST TCHAR *, WIN32_FIND_DATAT *);
+ BOOL (WINAPI *findNextFileProc)(HANDLE, WIN32_FIND_DATAT *);
+ BOOL (WINAPI *getComputerNameProc)(WCHAR *, LPDWORD);
+ DWORD (WINAPI *getCurrentDirectoryProc)(DWORD, WCHAR *);
+ DWORD (WINAPI *getFileAttributesProc)(CONST TCHAR *);
+ DWORD (WINAPI *getFullPathNameProc)(CONST TCHAR *, DWORD nBufferLength,
+ WCHAR *, TCHAR **);
+ DWORD (WINAPI *getModuleFileNameProc)(HMODULE, WCHAR *, int);
+ DWORD (WINAPI *getShortPathNameProc)(CONST TCHAR *, WCHAR *, DWORD);
+ UINT (WINAPI *getTempFileNameProc)(CONST TCHAR *, CONST TCHAR *, UINT,
+ WCHAR *);
+ DWORD (WINAPI *getTempPathProc)(DWORD, WCHAR *);
+ BOOL (WINAPI *getVolumeInformationProc)(CONST TCHAR *, WCHAR *, DWORD,
+ LPDWORD, LPDWORD, LPDWORD, WCHAR *, DWORD);
+ HINSTANCE (WINAPI *loadLibraryExProc)(CONST TCHAR *, HANDLE, DWORD);
+ TCHAR (WINAPI *lstrcpyProc)(WCHAR *, CONST TCHAR *);
+ BOOL (WINAPI *moveFileProc)(CONST TCHAR *, CONST TCHAR *);
+ BOOL (WINAPI *removeDirectoryProc)(CONST TCHAR *);
+ DWORD (WINAPI *searchPathProc)(CONST TCHAR *, CONST TCHAR *,
+ CONST TCHAR *, DWORD, WCHAR *, TCHAR **);
+ BOOL (WINAPI *setCurrentDirectoryProc)(CONST TCHAR *);
+ BOOL (WINAPI *setFileAttributesProc)(CONST TCHAR *, DWORD);
+ /*
+ * These two function pointers will only be set when
+ * Tcl_FindExecutable is called. If you don't ever call that
+ * function, the application will crash whenever WinTcl tries to call
+ * functions through these null pointers. That is not a bug in Tcl
+ * -- Tcl_FindExecutable is obligatory in recent Tcl releases.
+ */
+ BOOL (WINAPI *getFileAttributesExProc)(CONST TCHAR *,
+ GET_FILEEX_INFO_LEVELS, LPVOID);
+ BOOL (WINAPI *createHardLinkProc)(CONST TCHAR*, CONST TCHAR*,
+ LPSECURITY_ATTRIBUTES);
+
+ /* deleted INT (__cdecl *utimeProc)(CONST TCHAR*, struct _utimbuf *); */
+ /* These two are also NULL at start; see comment above */
+ HANDLE (WINAPI *findFirstFileExProc)(CONST TCHAR*, UINT,
+ LPVOID, UINT,
+ LPVOID, DWORD);
+ BOOL (WINAPI *getVolumeNameForVMPProc)(CONST TCHAR*, TCHAR*, DWORD);
+ DWORD (WINAPI *getLongPathNameProc)(CONST TCHAR*, TCHAR*, DWORD);
+ /*
+ * These six are for the security sdk to get correct file
+ * permissions on NT, 2000, XP, etc. On 95,98,ME they are
+ * always null.
+ */
+ BOOL (WINAPI *getFileSecurityProc)(LPCTSTR lpFileName,
+ SECURITY_INFORMATION RequestedInformation,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ DWORD nLength,
+ LPDWORD lpnLengthNeeded);
+ BOOL (WINAPI *impersonateSelfProc) (SECURITY_IMPERSONATION_LEVEL
+ ImpersonationLevel);
+ BOOL (WINAPI *openThreadTokenProc) (HANDLE ThreadHandle,
+ DWORD DesiredAccess, BOOL OpenAsSelf,
+ PHANDLE TokenHandle);
+ BOOL (WINAPI *revertToSelfProc) (void);
+ VOID (WINAPI *mapGenericMaskProc) (PDWORD AccessMask,
+ PGENERIC_MAPPING GenericMapping);
+ BOOL (WINAPI *accessCheckProc)(PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ HANDLE ClientToken, DWORD DesiredAccess,
+ PGENERIC_MAPPING GenericMapping,
+ PPRIVILEGE_SET PrivilegeSet,
+ LPDWORD PrivilegeSetLength,
+ LPDWORD GrantedAccess,
+ LPBOOL AccessStatus);
+ /*
+ * Unicode console support. WriteConsole and ReadConsole
+ */
+ BOOL (WINAPI *readConsoleProc)(
+ HANDLE hConsoleInput,
+ LPVOID lpBuffer,
+ DWORD nNumberOfCharsToRead,
+ LPDWORD lpNumberOfCharsRead,
+ LPVOID lpReserved
+ );
+ BOOL (WINAPI *writeConsoleProc)(
+ HANDLE hConsoleOutput,
+ const VOID* lpBuffer,
+ DWORD nNumberOfCharsToWrite,
+ LPDWORD lpNumberOfCharsWritten,
+ LPVOID lpReserved
+ );
+ BOOL (WINAPI *getUserName)(LPTSTR lpBuffer, LPDWORD lpnSize);
+} TclWinProcs;
+
+MODULE_SCOPE TclWinProcs *tclWinProcs;
+
+/*
* Declarations of functions that are not accessible by way of the
* stubs table.
*/
MODULE_SCOPE char TclWinDriveLetterForVolMountPoint(
- const WCHAR *mountPoint);
-MODULE_SCOPE void TclWinEncodingsCleanup(void);
+ CONST WCHAR *mountPoint);
+MODULE_SCOPE void TclWinEncodingsCleanup();
MODULE_SCOPE void TclWinInit(HINSTANCE hInst);
MODULE_SCOPE TclFile TclWinMakeFile(HANDLE handle);
MODULE_SCOPE Tcl_Channel TclWinOpenConsoleChannel(HANDLE handle,
char *channelName, int permissions);
+MODULE_SCOPE Tcl_Channel TclWinOpenFileChannel(HANDLE handle, char *channelName,
+ int permissions, int appendMode);
MODULE_SCOPE Tcl_Channel TclWinOpenSerialChannel(HANDLE handle,
char *channelName, int permissions);
-MODULE_SCOPE HANDLE TclWinSerialOpen(HANDLE handle, const WCHAR *name,
+MODULE_SCOPE void TclWinResetInterfaceEncodings();
+MODULE_SCOPE HANDLE TclWinSerialOpen(HANDLE handle, CONST TCHAR *name,
DWORD access);
-MODULE_SCOPE int TclWinSymLinkCopyDirectory(const WCHAR *LinkOriginal,
- const WCHAR *LinkCopy);
-MODULE_SCOPE int TclWinSymLinkDelete(const WCHAR *LinkOriginal,
+MODULE_SCOPE int TclWinSymLinkCopyDirectory(CONST TCHAR* LinkOriginal,
+ CONST TCHAR* LinkCopy);
+MODULE_SCOPE int TclWinSymLinkDelete(CONST TCHAR* LinkOriginal,
int linkOnly);
-MODULE_SCOPE int TclWinFileOwned(Tcl_Obj *);
-MODULE_SCOPE void TclWinGenerateChannelName(char channelName[],
- const char *channelTypeName, void *channelImpl);
-MODULE_SCOPE const char*TclpGetUserName(Tcl_DString *bufferPtr);
+#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
+MODULE_SCOPE void TclWinFreeAllocCache(void);
+MODULE_SCOPE void TclFreeAllocCache(void *);
+MODULE_SCOPE Tcl_Mutex *TclpNewAllocMutex(void);
+MODULE_SCOPE void * TclpGetAllocCache(void);
+MODULE_SCOPE void TclpSetAllocCache(void *);
+#endif /* TCL_THREADS */
/* Needed by tclWinFile.c and tclWinFCmd.c */
#ifndef FILE_ATTRIBUTE_REPARSE_POINT
#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
#endif
-/*
- *----------------------------------------------------------------------
- * Declarations of helper-workers threaded facilities for a pipe based channel.
- *
- * Corresponding functionality provided in "tclWinPipe.c".
- *----------------------------------------------------------------------
- */
-
-typedef struct TclPipeThreadInfo {
- HANDLE evControl; /* Auto-reset event used by the main thread to
- * signal when the pipe thread should attempt
- * to do read/write operation. Additionally
- * used as signal to stop (state set to -1) */
- volatile LONG state; /* Indicates current state of the thread */
- void *clientData; /* Referenced data of the main thread */
- HANDLE evWakeUp; /* Optional wake-up event worker set by shutdown */
-} TclPipeThreadInfo;
-
-
-/* If pipe-workers will use some tcl subsystem, we can use ckalloc without
- * more overhead for finalize thread (should be executed anyway)
- *
- * #define _PTI_USE_CKALLOC 1
- */
-
-/*
- * State of the pipe-worker.
- *
- * State PTI_STATE_STOP possible from idle state only, worker owns TI structure.
- * Otherwise PTI_STATE_END used (main thread hold ownership of the TI).
- */
-
-#define PTI_STATE_IDLE 0 /* idle or not yet initialzed */
-#define PTI_STATE_WORK 1 /* in work */
-#define PTI_STATE_STOP 2 /* thread should stop work (owns TI structure) */
-#define PTI_STATE_END 4 /* thread should stop work (worker is busy) */
-#define PTI_STATE_DOWN 8 /* worker is down */
-
-
-MODULE_SCOPE
-TclPipeThreadInfo * TclPipeThreadCreateTI(TclPipeThreadInfo **pipeTIPtr,
- void *clientData, HANDLE wakeEvent);
-MODULE_SCOPE int TclPipeThreadWaitForSignal(TclPipeThreadInfo **pipeTIPtr);
-
-static inline void
-TclPipeThreadSignal(
- TclPipeThreadInfo **pipeTIPtr)
-{
- TclPipeThreadInfo *pipeTI = *pipeTIPtr;
- if (pipeTI) {
- SetEvent(pipeTI->evControl);
- }
-};
-
-static inline int
-TclPipeThreadIsAlive(
- TclPipeThreadInfo **pipeTIPtr)
-{
- TclPipeThreadInfo *pipeTI = *pipeTIPtr;
- return (pipeTI && pipeTI->state != PTI_STATE_DOWN);
-};
-
-MODULE_SCOPE int TclPipeThreadStopSignal(TclPipeThreadInfo **pipeTIPtr, HANDLE wakeEvent);
-MODULE_SCOPE void TclPipeThreadStop(TclPipeThreadInfo **pipeTIPtr, HANDLE hThread);
-MODULE_SCOPE void TclPipeThreadExit(TclPipeThreadInfo **pipeTIPtr);
-
#endif /* _TCLWININT */
diff --git a/win/tclWinLoad.c b/win/tclWinLoad.c
index a03132f..c4d08e8 100644
--- a/win/tclWinLoad.c
+++ b/win/tclWinLoad.c
@@ -5,7 +5,7 @@
* the Windows "LoadLibrary" and "GetProcAddress" API for dynamic
* loading.
*
- * Copyright © 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -13,25 +13,6 @@
#include "tclWinInt.h"
-/*
- * Native name of the directory in the native filesystem where DLLs used in
- * this process are copied prior to loading, and mutex used to protect its
- * allocation.
- */
-
-static WCHAR *dllDirectoryName = NULL;
-#if TCL_THREADS
-static Tcl_Mutex dllDirectoryNameMutex;
-#endif
-
-/*
- * Static functions defined within this file.
- */
-
-static void * FindSymbol(Tcl_Interp *interp,
- Tcl_LoadHandle loadHandle, const char *symbol);
-static int InitDLLDirectoryName(void);
-static void UnloadFile(Tcl_LoadHandle loadHandle);
/*
*----------------------------------------------------------------------
@@ -59,16 +40,13 @@ TclpDlopen(
Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded
* file which will be passed back to
* (*unloadProcPtr)() to unload the file. */
- Tcl_FSUnloadFileProc **unloadProcPtr,
+ Tcl_FSUnloadFileProc **unloadProcPtr)
/* Filled with address of Tcl_FSUnloadFileProc
* function which should be used for this
* file. */
- TCL_UNUSED(int) /*flags*/)
{
- HINSTANCE hInstance = NULL;
- const WCHAR *nativeName;
- Tcl_LoadHandle handlePtr;
- DWORD firstError;
+ HINSTANCE handle;
+ CONST TCHAR *nativeName;
/*
* First try the full path the user gave us. This is particularly
@@ -76,12 +54,10 @@ TclpDlopen(
* relative path.
*/
- nativeName = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
- if (nativeName != NULL) {
- hInstance = LoadLibraryExW(nativeName, NULL,
- LOAD_WITH_ALTERED_SEARCH_PATH);
- }
- if (hInstance == NULL) {
+ nativeName = Tcl_FSGetNativePath(pathPtr);
+ handle = (*tclWinProcs->loadLibraryExProc)(nativeName, NULL,
+ LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (handle == NULL) {
/*
* Let the OS loader examine the binary search path for whatever
* string the user gave us which hopefully refers to a file on the
@@ -89,39 +65,38 @@ TclpDlopen(
*/
Tcl_DString ds;
+ char *fileName = Tcl_GetString(pathPtr);
- /*
- * Remember the first error on load attempt to be used if the
- * second load attempt below also fails.
- */
- firstError = (nativeName == NULL) ?
- ERROR_MOD_NOT_FOUND : GetLastError();
-
- Tcl_DStringInit(&ds);
- nativeName = Tcl_UtfToWCharDString(TclGetString(pathPtr), TCL_INDEX_NONE, &ds);
- hInstance = LoadLibraryExW(nativeName, NULL,
+ nativeName = Tcl_WinUtfToTChar(fileName, -1, &ds);
+ handle = (*tclWinProcs->loadLibraryExProc)(nativeName, NULL,
LOAD_WITH_ALTERED_SEARCH_PATH);
Tcl_DStringFree(&ds);
}
- if (hInstance == NULL) {
- DWORD lastError;
- Tcl_Obj *errMsg;
+ *loadHandle = (Tcl_LoadHandle) handle;
- /*
- * We choose to only use the error from the second call if the first
- * call failed due to the file not being found. Else stick to the
- * first error for reporting purposes.
- */
- if (firstError == ERROR_MOD_NOT_FOUND ||
- firstError == ERROR_DLL_NOT_FOUND) {
- lastError = GetLastError();
- } else {
- lastError = firstError;
- }
+ if (handle == NULL) {
+ DWORD lastError = GetLastError();
+
+#if 0
+ /*
+ * It would be ideal if the FormatMessage stuff worked better, but
+ * unfortunately it doesn't seem to want to...
+ */
+
+ LPTSTR lpMsgBuf;
+ char *buf;
+ int size;
+
+ size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, lastError, 0,
+ (LPTSTR) &lpMsgBuf, 0, NULL);
+ buf = (char *) ckalloc((unsigned) TCL_INTEGER_SPACE + size + 1);
+ sprintf(buf, "%d %s", lastError, (char *)lpMsgBuf);
+#endif
- errMsg = Tcl_ObjPrintf("couldn't load library \"%s\": ",
- TclGetString(pathPtr));
+ Tcl_AppendResult(interp, "couldn't load library \"",
+ Tcl_GetString(pathPtr), "\": ", NULL);
/*
* Check for possible DLL errors. This doesn't work quite right,
@@ -130,63 +105,40 @@ TclpDlopen(
* better if there was a way to get what DLLs
*/
- if (interp) {
- switch (lastError) {
- case ERROR_MOD_NOT_FOUND:
- Tcl_SetErrorCode(interp, "WIN_LOAD", "MOD_NOT_FOUND", (void *)NULL);
- goto notFoundMsg;
- case ERROR_DLL_NOT_FOUND:
- Tcl_SetErrorCode(interp, "WIN_LOAD", "DLL_NOT_FOUND", (void *)NULL);
- notFoundMsg:
- Tcl_AppendToObj(errMsg, "this library or a dependent library"
- " could not be found in library path", TCL_INDEX_NONE);
- break;
- case ERROR_PROC_NOT_FOUND:
- Tcl_SetErrorCode(interp, "WIN_LOAD", "PROC_NOT_FOUND", (void *)NULL);
- Tcl_AppendToObj(errMsg, "A function specified in the import"
- " table could not be resolved by the system. Windows"
- " is not telling which one, I'm sorry.", TCL_INDEX_NONE);
- break;
- case ERROR_INVALID_DLL:
- Tcl_SetErrorCode(interp, "WIN_LOAD", "INVALID_DLL", (void *)NULL);
- Tcl_AppendToObj(errMsg, "this library or a dependent library"
- " is damaged", TCL_INDEX_NONE);
- break;
- case ERROR_DLL_INIT_FAILED:
- Tcl_SetErrorCode(interp, "WIN_LOAD", "DLL_INIT_FAILED", (void *)NULL);
- Tcl_AppendToObj(errMsg, "the library initialization"
- " routine failed", TCL_INDEX_NONE);
- break;
- case ERROR_BAD_EXE_FORMAT:
- Tcl_SetErrorCode(interp, "WIN_LOAD", "BAD_EXE_FORMAT", (void *)NULL);
- Tcl_AppendToObj(errMsg, "Bad exe format. Possibly a 32/64-bit mismatch.", TCL_INDEX_NONE);
- break;
- default:
- Tcl_WinConvertError(lastError);
- Tcl_AppendToObj(errMsg, Tcl_PosixError(interp), TCL_INDEX_NONE);
- }
- Tcl_SetObjResult(interp, errMsg);
+ switch (lastError) {
+ case ERROR_MOD_NOT_FOUND:
+ case ERROR_DLL_NOT_FOUND:
+ Tcl_AppendResult(interp, "this library or a dependent library"
+ " could not be found in library path", NULL);
+ break;
+ case ERROR_PROC_NOT_FOUND:
+ Tcl_AppendResult(interp, "A function specified in the import"
+ " table could not be resolved by the system. Windows"
+ " is not telling which one, I'm sorry.", NULL);
+ break;
+ case ERROR_INVALID_DLL:
+ Tcl_AppendResult(interp, "this library or a dependent library"
+ " is damaged", NULL);
+ break;
+ case ERROR_DLL_INIT_FAILED:
+ Tcl_AppendResult(interp, "the library initialization"
+ " routine failed", NULL);
+ break;
+ default:
+ TclWinConvertError(lastError);
+ Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL);
}
return TCL_ERROR;
+ } else {
+ *unloadProcPtr = &TclpUnloadFile;
}
-
- /*
- * Succeded; package everything up for Tcl.
- */
-
- handlePtr = (Tcl_LoadHandle)ckalloc(sizeof(struct Tcl_LoadHandle_));
- handlePtr->clientData = (void *) hInstance;
- handlePtr->findSymbolProcPtr = &FindSymbol;
- handlePtr->unloadFileProcPtr = &UnloadFile;
- *loadHandle = handlePtr;
- *unloadProcPtr = &UnloadFile;
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
- * FindSymbol --
+ * TclpFindSymbol --
*
* Looks up a symbol, by name, through a handle associated with a
* previously loaded piece of code (shared library).
@@ -199,43 +151,37 @@ TclpDlopen(
*----------------------------------------------------------------------
*/
-static void *
-FindSymbol(
+Tcl_PackageInitProc *
+TclpFindSymbol(
Tcl_Interp *interp,
Tcl_LoadHandle loadHandle,
- const char *symbol)
+ CONST char *symbol)
{
- HINSTANCE hInstance = (HINSTANCE) loadHandle->clientData;
- void *proc = NULL;
+ Tcl_PackageInitProc *proc = NULL;
+ HINSTANCE handle = (HINSTANCE)loadHandle;
/*
* For each symbol, check for both Symbol and _Symbol, since Borland
* generates C symbols with a leading '_' by default.
*/
- proc = (void *)GetProcAddress(hInstance, symbol);
+ proc = (Tcl_PackageInitProc *) GetProcAddress(handle, symbol);
if (proc == NULL) {
Tcl_DString ds;
- const char *sym2;
Tcl_DStringInit(&ds);
- TclDStringAppendLiteral(&ds, "_");
- sym2 = Tcl_DStringAppend(&ds, symbol, TCL_INDEX_NONE);
- proc = (void *)GetProcAddress(hInstance, sym2);
+ Tcl_DStringAppend(&ds, "_", 1);
+ symbol = Tcl_DStringAppend(&ds, symbol, -1);
+ proc = (Tcl_PackageInitProc *) GetProcAddress(handle, symbol);
Tcl_DStringFree(&ds);
}
- if (proc == NULL && interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "cannot find symbol \"%s\"", symbol));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "LOAD_SYMBOL", symbol, (void *)NULL);
- }
return proc;
}
/*
*----------------------------------------------------------------------
*
- * UnloadFile --
+ * TclpUnloadFile --
*
* Unloads a dynamically loaded binary code file from memory. Code
* pointers in the formerly loaded file are no longer valid after calling
@@ -250,149 +196,46 @@ FindSymbol(
*----------------------------------------------------------------------
*/
-static void
-UnloadFile(
+void
+TclpUnloadFile(
Tcl_LoadHandle loadHandle) /* loadHandle returned by a previous call to
* TclpDlopen(). The loadHandle is a token
* that represents the loaded file. */
{
- HINSTANCE hInstance = (HINSTANCE) loadHandle->clientData;
-
- FreeLibrary(hInstance);
- ckfree(loadHandle);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpTempFileNameForLibrary --
- *
- * Constructs a temporary file name for loading a shared object (DLL).
- *
- * Results:
- * Returns the constructed file name.
- *
- * On Windows, a DLL is identified by the final component of its path name.
- * Cross linking among DLL's (and hence, preloading) will not work unless this
- * name is preserved when copying a DLL from a VFS to a temp file for
- * preloading. For this reason, all DLLs in a given process are copied to a
- * temp directory, and their names are preserved.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Obj *
-TclpTempFileNameForLibrary(
- Tcl_Interp *interp, /* Tcl interpreter. */
- Tcl_Obj *path) /* Path name of the DLL in the VFS. */
-{
- Tcl_Obj *fileName; /* Name of the temp file. */
- Tcl_Obj *tail; /* Tail of the source path. */
-
- Tcl_MutexLock(&dllDirectoryNameMutex);
- if (dllDirectoryName == NULL) {
- if (InitDLLDirectoryName() == TCL_ERROR) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't create temporary directory: %s",
- Tcl_PosixError(interp)));
- Tcl_MutexUnlock(&dllDirectoryNameMutex);
- return NULL;
- }
- }
- Tcl_MutexUnlock(&dllDirectoryNameMutex);
+ HINSTANCE handle;
- /*
- * Now we know where to put temporary DLLs, construct the name.
- */
-
- fileName = TclpNativeToNormalized(dllDirectoryName);
- tail = TclPathPart(interp, path, TCL_PATH_TAIL);
- if (tail == NULL) {
- Tcl_DecrRefCount(fileName);
- return NULL;
- }
- Tcl_AppendToObj(fileName, "/", 1);
- Tcl_AppendObjToObj(fileName, tail);
- return fileName;
+ handle = (HINSTANCE) loadHandle;
+ FreeLibrary(handle);
}
/*
*----------------------------------------------------------------------
*
- * InitDLLDirectoryName --
+ * TclGuessPackageName --
*
- * Helper for TclpTempFileNameForLibrary; builds a temporary directory
- * that is specific to the current process. Should only be called once
- * per process start. Caller must hold dllDirectoryNameMutex.
+ * If the "load" command is invoked without providing a package name,
+ * this function is invoked to try to figure it out.
*
* Results:
- * Tcl result code.
+ * Always returns 0 to indicate that we couldn't figure out a package
+ * name; generic code will then try to guess the package from the file
+ * name. A return value of 1 would have meant that we figured out the
+ * package name and put it in bufPtr.
*
- * Side-effects:
- * Creates temp directory.
- * Allocates memory pointed to by dllDirectoryName.
+ * Side effects:
+ * None.
*
*----------------------------------------------------------------------
- * [Candidate for process global?]
*/
-static int
-InitDLLDirectoryName(void)
+int
+TclGuessPackageName(
+ CONST char *fileName, /* Name of file containing package (already
+ * translated to local form if needed). */
+ Tcl_DString *bufPtr) /* Initialized empty dstring. Append package
+ * name to this if possible. */
{
- size_t nameLen; /* Length of the temp folder name. */
- WCHAR name[MAX_PATH]; /* Path name of the temp folder. */
- DWORD id; /* The process id. */
- DWORD lastError; /* Last error to happen in Win API. */
- int i;
-
- /*
- * Determine the name of the directory to use, and create it. (Keep
- * trying with new names until an attempt to create the directory
- * succeeds)
- */
-
- nameLen = GetTempPathW(MAX_PATH, name);
- if (nameLen >= MAX_PATH-12) {
- Tcl_SetErrno(ENAMETOOLONG);
- return TCL_ERROR;
- }
-
- wcscpy(name+nameLen, L"TCLXXXXXXXX");
- nameLen += 11;
-
- id = GetCurrentProcessId();
- lastError = ERROR_ALREADY_EXISTS;
-
- for (i=0 ; i<256 ; i++) {
- wsprintfW(name+nameLen-8, L"%08x", id);
- if (CreateDirectoryW(name, NULL)) {
- /*
- * Issue: we don't schedule this directory for deletion by anyone.
- * Can we ask the OS to do this for us? There appears to be
- * potential for using CreateFile (with the flag
- * FILE_FLAG_BACKUP_SEMANTICS) and RemoveDirectory to do this...
- */
-
- goto copyToGlobalBuffer;
- }
- lastError = GetLastError();
- if (lastError != ERROR_ALREADY_EXISTS) {
- break;
- }
- id *= 16777619;
- }
-
- Tcl_WinConvertError(lastError);
- return TCL_ERROR;
-
- /*
- * Store our computed value in the global.
- */
-
- copyToGlobalBuffer:
- dllDirectoryName = (WCHAR *)ckalloc((nameLen+1) * sizeof(WCHAR));
- wcscpy(dllDirectoryName, name);
- return TCL_OK;
+ return 0;
}
/*
diff --git a/win/tclWinNotify.c b/win/tclWinNotify.c
index 795db74..1cd5823 100644
--- a/win/tclWinNotify.c
+++ b/win/tclWinNotify.c
@@ -5,7 +5,7 @@
* is the lowest-level part of the Tcl event loop. This file works
* together with ../generic/tclNotify.c.
*
- * Copyright © 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -14,7 +14,7 @@
#include "tclInt.h"
/*
- * The following static indicates whether this module has been initialized.
+ * The follwing static indicates whether this module has been initialized.
*/
#define INTERVAL_TIMER 1 /* Handle of interval timer. */
@@ -27,7 +27,7 @@
* created for each thread that is using the notifier.
*/
-typedef struct {
+typedef struct ThreadSpecificData {
CRITICAL_SECTION crit; /* Monitor for this notifier. */
DWORD thread; /* Identifier for thread associated with this
* notifier. */
@@ -36,11 +36,15 @@ typedef struct {
int pending; /* Alert message pending, this field is locked
* by the notifierMutex. */
HWND hwnd; /* Messaging window. */
+ int timeout; /* Current timeout value. */
int timerActive; /* 1 if interval timer is running. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
+extern TclStubs tclStubs;
+extern Tcl_NotifierProcs tclOriginalNotifier;
+
/*
* The following static indicates the number of threads that have initialized
* notifiers. It controls the lifetime of the TclNotifier window class.
@@ -49,16 +53,14 @@ static Tcl_ThreadDataKey dataKey;
*/
static int notifierCount = 0;
-static const WCHAR className[] = L"TclNotifier";
-static int initialized = 0;
-static CRITICAL_SECTION notifierMutex;
+TCL_DECLARE_MUTEX(notifierMutex)
/*
* Static routines defined in this file.
*/
-static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message,
- WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam);
/*
*----------------------------------------------------------------------
@@ -76,45 +78,36 @@ static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message,
*----------------------------------------------------------------------
*/
-void *
-TclpInitNotifier(void)
+ClientData
+Tcl_InitNotifier(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
- TclpGlobalLock();
- if (!initialized) {
- initialized = 1;
- InitializeCriticalSection(&notifierMutex);
- }
- TclpGlobalUnlock();
+ WNDCLASS class;
/*
* Register Notifier window class if this is the first thread to use this
* module.
*/
- EnterCriticalSection(&notifierMutex);
+ Tcl_MutexLock(&notifierMutex);
if (notifierCount == 0) {
- WNDCLASSW clazz;
-
- clazz.style = 0;
- clazz.cbClsExtra = 0;
- clazz.cbWndExtra = 0;
- clazz.hInstance = TclWinGetTclInstance();
- clazz.hbrBackground = NULL;
- clazz.lpszMenuName = NULL;
- clazz.lpszClassName = className;
- clazz.lpfnWndProc = NotifierProc;
- clazz.hIcon = NULL;
- clazz.hCursor = NULL;
-
- if (!RegisterClassW(&clazz)) {
- Tcl_Panic("Tcl_InitNotifier: %s",
- "unable to register TclNotifier window class");
+ class.style = 0;
+ class.cbClsExtra = 0;
+ class.cbWndExtra = 0;
+ class.hInstance = TclWinGetTclInstance();
+ class.hbrBackground = NULL;
+ class.lpszMenuName = NULL;
+ class.lpszClassName = "TclNotifier";
+ class.lpfnWndProc = NotifierProc;
+ class.hIcon = NULL;
+ class.hCursor = NULL;
+
+ if (!RegisterClassA(&class)) {
+ Tcl_Panic("Unable to register TclNotifier window class");
}
}
notifierCount++;
- LeaveCriticalSection(&notifierMutex);
+ Tcl_MutexUnlock(&notifierMutex);
tsdPtr->pending = 0;
tsdPtr->timerActive = 0;
@@ -123,16 +116,16 @@ TclpInitNotifier(void)
tsdPtr->hwnd = NULL;
tsdPtr->thread = GetCurrentThreadId();
- tsdPtr->event = CreateEventW(NULL, TRUE /* manual */,
+ tsdPtr->event = CreateEvent(NULL, TRUE /* manual */,
FALSE /* !signaled */, NULL);
- return tsdPtr;
+ return (ClientData) tsdPtr;
}
/*
*----------------------------------------------------------------------
*
- * TclpFinalizeNotifier --
+ * Tcl_FinalizeNotifier --
*
* This function is called to cleanup the notifier state before a thread
* is terminated.
@@ -147,8 +140,8 @@ TclpInitNotifier(void)
*/
void
-TclpFinalizeNotifier(
- void *clientData) /* Pointer to notifier data. */
+Tcl_FinalizeNotifier(
+ ClientData clientData) /* Pointer to notifier data. */
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
@@ -184,20 +177,18 @@ TclpFinalizeNotifier(
* window class.
*/
- EnterCriticalSection(&notifierMutex);
- if (notifierCount) {
- notifierCount--;
- if (notifierCount == 0) {
- UnregisterClassW(className, TclWinGetTclInstance());
- }
+ Tcl_MutexLock(&notifierMutex);
+ notifierCount--;
+ if (notifierCount == 0) {
+ UnregisterClassA("TclNotifier", TclWinGetTclInstance());
}
- LeaveCriticalSection(&notifierMutex);
+ Tcl_MutexUnlock(&notifierMutex);
}
/*
*----------------------------------------------------------------------
*
- * TclpAlertNotifier --
+ * Tcl_AlertNotifier --
*
* Wake up the specified notifier from any thread. This routine is called
* by the platform independent notifier code whenever the Tcl_ThreadAlert
@@ -217,8 +208,8 @@ TclpFinalizeNotifier(
*/
void
-TclpAlertNotifier(
- void *clientData) /* Pointer to thread data. */
+Tcl_AlertNotifier(
+ ClientData clientData) /* Pointer to thread data. */
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
@@ -235,7 +226,7 @@ TclpAlertNotifier(
EnterCriticalSection(&tsdPtr->crit);
if (!tsdPtr->pending) {
- PostMessageW(tsdPtr->hwnd, WM_WAKEUP, 0, 0);
+ PostMessage(tsdPtr->hwnd, WM_WAKEUP, 0, 0);
}
tsdPtr->pending = 1;
LeaveCriticalSection(&tsdPtr->crit);
@@ -247,7 +238,7 @@ TclpAlertNotifier(
/*
*----------------------------------------------------------------------
*
- * TclpSetTimer --
+ * Tcl_SetTimer --
*
* This procedure sets the current notifier timer value. The notifier
* will ensure that Tcl_ServiceAll() is called after the specified
@@ -263,13 +254,23 @@ TclpAlertNotifier(
*/
void
-TclpSetTimer(
- const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
+Tcl_SetTimer(
+ Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
UINT timeout;
/*
+ * Allow the notifier to be hooked. This may not make sense on Windows,
+ * but mirrors the UNIX hook.
+ */
+
+ if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) {
+ tclStubs.tcl_SetTimer(timePtr);
+ return;
+ }
+
+ /*
* We only need to set up an interval timer if we're being called from an
* external event loop. If we don't have a window handle then we just
* return immediately and let Tcl_WaitForEvent handle timeouts.
@@ -292,10 +293,11 @@ TclpSetTimer(
timeout = 1;
}
}
-
+ tsdPtr->timeout = timeout;
if (timeout != 0) {
tsdPtr->timerActive = 1;
- SetTimer(tsdPtr->hwnd, INTERVAL_TIMER, timeout, NULL);
+ SetTimer(tsdPtr->hwnd, INTERVAL_TIMER, (unsigned long) tsdPtr->timeout,
+ NULL);
} else {
tsdPtr->timerActive = 0;
KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
@@ -305,7 +307,7 @@ TclpSetTimer(
/*
*----------------------------------------------------------------------
*
- * TclpServiceModeHook --
+ * Tcl_ServiceModeHook --
*
* This function is invoked whenever the service mode changes.
*
@@ -320,7 +322,7 @@ TclpSetTimer(
*/
void
-TclpServiceModeHook(
+Tcl_ServiceModeHook(
int mode) /* Either TCL_SERVICE_ALL, or
* TCL_SERVICE_NONE. */
{
@@ -336,7 +338,7 @@ TclpServiceModeHook(
*/
if (mode == TCL_SERVICE_ALL && !tsdPtr->hwnd) {
- tsdPtr->hwnd = CreateWindowW(className, className, WS_TILED,
+ tsdPtr->hwnd = CreateWindowA("TclNotifier", "TclNotifier", WS_TILED,
0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL);
/*
@@ -346,39 +348,13 @@ TclpServiceModeHook(
* is needed.
*/
- Tcl_AlertNotifier(tsdPtr);
+ Tcl_AlertNotifier((ClientData)tsdPtr);
}
}
/*
*----------------------------------------------------------------------
*
- * TclAsyncNotifier --
- *
- * This procedure is a no-op on Windows.
- *
- * Result:
- * Always true.
- *
- * Side effetcs:
- * None.
- *----------------------------------------------------------------------
- */
-
-int
-TclAsyncNotifier(
- TCL_UNUSED(int), /* Signal number. */
- TCL_UNUSED(Tcl_ThreadId), /* Target thread. */
- TCL_UNUSED(void *), /* Notifier data. */
- TCL_UNUSED(int *), /* Flag to mark. */
- TCL_UNUSED(int)) /* Value of mark. */
-{
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
* NotifierProc --
*
* This procedure is invoked by Windows to process events on the notifier
@@ -408,7 +384,7 @@ NotifierProc(
tsdPtr->pending = 0;
LeaveCriticalSection(&tsdPtr->crit);
} else if (message != WM_TIMER) {
- return DefWindowProcW(hwnd, message, wParam, lParam);
+ return DefWindowProc(hwnd, message, wParam, lParam);
}
/*
@@ -422,30 +398,7 @@ NotifierProc(
/*
*----------------------------------------------------------------------
*
- * TclpNotifierData --
- *
- * This function returns a void pointer to be associated
- * with a Tcl_AsyncHandler.
- *
- * Results:
- * On Windows, returns always NULL.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void *
-TclpNotifierData(void)
-{
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpWaitForEvent --
+ * Tcl_WaitForEvent --
*
* This function is called by Tcl_DoOneEvent to wait for new events on
* the message queue. If the block time is 0, then Tcl_WaitForEvent just
@@ -462,8 +415,8 @@ TclpNotifierData(void)
*/
int
-TclpWaitForEvent(
- const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
+Tcl_WaitForEvent(
+ Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
MSG msg;
@@ -471,6 +424,15 @@ TclpWaitForEvent(
int status;
/*
+ * Allow the notifier to be hooked. This may not make sense on windows,
+ * but mirrors the UNIX hook.
+ */
+
+ if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) {
+ return tclStubs.tcl_WaitForEvent(timePtr);
+ }
+
+ /*
* Compute the timeout in milliseconds.
*/
@@ -486,7 +448,7 @@ TclpWaitForEvent(
myTime.usec = timePtr->usec;
if (myTime.sec != 0 || myTime.usec != 0) {
- TclScaleTime(&myTime);
+ (*tclScaleTimeProcPtr) (&myTime, tclTimeClientData);
}
timeout = myTime.sec * 1000 + myTime.usec / 1000;
@@ -500,19 +462,19 @@ TclpWaitForEvent(
* currently sitting in the queue.
*/
- if (!PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE)) {
+ if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
/*
* Wait for something to happen (a signal from another thread, a
* message, or timeout) or loop servicing asynchronous procedure calls
* queued to this thread.
*/
- do {
- result = MsgWaitForMultipleObjectsEx(1, &tsdPtr->event, timeout,
- QS_ALLINPUT, MWMO_ALERTABLE);
- } while (result == WAIT_IO_COMPLETION);
-
- if (result == WAIT_FAILED) {
+ again:
+ result = MsgWaitForMultipleObjectsEx(1, &tsdPtr->event, timeout,
+ QS_ALLINPUT, MWMO_ALERTABLE);
+ if (result == WAIT_IO_COMPLETION) {
+ goto again;
+ } else if (result == WAIT_FAILED) {
status = -1;
goto end;
}
@@ -522,12 +484,12 @@ TclpWaitForEvent(
* Check to see if there are any messages to process.
*/
- if (PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE)) {
+ if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
/*
* Retrieve and dispatch the first message.
*/
- result = GetMessageW(&msg, NULL, 0, 0);
+ result = GetMessage(&msg, NULL, 0, 0);
if (result == 0) {
/*
* We received a request to exit this thread (WM_QUIT), so
@@ -536,7 +498,7 @@ TclpWaitForEvent(
PostQuitMessage((int) msg.wParam);
status = -1;
- } else if (result == (DWORD) -1) {
+ } else if (result == (DWORD)-1) {
/*
* We got an error from the system. I have no idea why this would
* happen, so we'll just unwind.
@@ -545,7 +507,7 @@ TclpWaitForEvent(
status = -1;
} else {
TranslateMessage(&msg);
- DispatchMessageW(&msg);
+ DispatchMessage(&msg);
status = 1;
}
} else {
@@ -608,11 +570,11 @@ Tcl_Sleep(
* TIP #233: Scale delay from virtual to real-time.
*/
- TclScaleTime(&vdelay);
+ (*tclScaleTimeProcPtr) (&vdelay, tclTimeClientData);
sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
for (;;) {
- SleepEx(sleepTime, TRUE);
+ Sleep(sleepTime);
Tcl_GetTime(&now);
if (now.sec > desired.sec) {
break;
@@ -623,7 +585,7 @@ Tcl_Sleep(
vdelay.sec = desired.sec - now.sec;
vdelay.usec = desired.usec - now.usec;
- TclScaleTime(&vdelay);
+ (*tclScaleTimeProcPtr) (&vdelay, tclTimeClientData);
sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
}
}
diff --git a/win/tclWinPanic.c b/win/tclWinPanic.c
deleted file mode 100644
index 3131286..0000000
--- a/win/tclWinPanic.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * tclWinPanic.c --
- *
- * Contains the Windows-specific command-line panic proc.
- *
- * Copyright © 2013 Jan Nijtmans.
- * All rights reserved.
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-#include "tclInt.h"
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_ConsolePanic --
- *
- * Display a message. If a debugger is present, present it directly to
- * the debugger, otherwise send it to stderr.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_ConsolePanic(
- const char *format, ...)
-{
-#define TCL_MAX_WARN_LEN 26000
- va_list argList;
- WCHAR msgString[TCL_MAX_WARN_LEN];
- char buf[TCL_MAX_WARN_LEN * 3];
- HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);
- DWORD dummy;
-
- va_start(argList, format);
- vsnprintf(buf+3, sizeof(buf)-3, format, argList);
- buf[sizeof(buf)-1] = 0;
- msgString[TCL_MAX_WARN_LEN-1] = '\0';
- MultiByteToWideChar(CP_UTF8, 0, buf+3, -1, msgString, TCL_MAX_WARN_LEN);
-
- /*
- * Truncate MessageBox string if it is too long to not overflow the buffer.
- */
-
- if (msgString[TCL_MAX_WARN_LEN-1] != '\0') {
- memcpy(msgString + (TCL_MAX_WARN_LEN - 5), L" ...", 5 * sizeof(WCHAR));
- }
-
- if (IsDebuggerPresent()) {
- OutputDebugStringW(msgString);
- } else if (_isatty(2)) {
- WriteConsoleW(handle, msgString, (DWORD)wcslen(msgString), &dummy, 0);
- } else {
- buf[0] = '\xEF'; buf[1] = '\xBB'; buf[2] = '\xBF'; /* UTF-8 bom */
- WriteFile(handle, buf, (DWORD)strlen(buf), &dummy, 0);
- WriteFile(handle, "\n", 1, &dummy, 0);
- FlushFileBuffers(handle);
- }
-# if defined(__GNUC__)
- __builtin_trap();
-# elif defined(_WIN64)
- __debugbreak();
-# elif defined(_MSC_VER)
- _asm {int 3}
-# else
- DebugBreak();
-# endif
-#if defined(_WIN32)
- ExitProcess(1);
-#else
- abort();
-#endif
-}
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * tab-width: 8
- * End:
- */
diff --git a/win/tclWinPipe.c b/win/tclWinPipe.c
index bb4983e..ee088a5 100644
--- a/win/tclWinPipe.c
+++ b/win/tclWinPipe.c
@@ -4,7 +4,7 @@
* This file implements the Windows-specific exec pipeline functions, the
* "pipe" channel driver, and the "pid" Tcl command.
*
- * Copyright © 1996-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -50,7 +50,7 @@ TCL_DECLARE_MUTEX(pipeMutex)
* used in a pipeline.
*/
-typedef struct {
+typedef struct WinFile {
int type; /* One of the file types defined above. */
HANDLE handle; /* Open file handle. */
} WinFile;
@@ -61,7 +61,7 @@ typedef struct {
typedef struct ProcInfo {
HANDLE hProcess;
- TCL_HASH_TYPE dwProcessId;
+ DWORD dwProcessId;
struct ProcInfo *nextPtr;
} ProcInfo;
@@ -82,12 +82,6 @@ static ProcInfo *procList;
#define PIPE_EXTRABYTE (1<<3) /* The reader thread has consumed one byte. */
/*
- * TODO: It appears the whole EXTRABYTE machinery is in place to support
- * outdated Win 95 systems. If this can be confirmed, much code can be
- * deleted.
- */
-
-/*
* This structure describes per-instance data for a pipe based channel.
*/
@@ -104,27 +98,35 @@ typedef struct PipeInfo {
TclFile readFile; /* Output from pipe. */
TclFile writeFile; /* Input from pipe. */
TclFile errorFile; /* Error output from pipe. */
- TCL_HASH_TYPE numPids; /* Number of processes attached to pipe. */
+ int numPids; /* Number of processes attached to pipe. */
Tcl_Pid *pidPtr; /* Pids of attached processes. */
Tcl_ThreadId threadId; /* Thread to which events should be reported.
* This value is used by the reader/writer
* threads. */
- TclPipeThreadInfo *writeTI; /* Thread info of writer and reader, this */
- TclPipeThreadInfo *readTI; /* structure owned by corresponding thread. */
HANDLE writeThread; /* Handle to writer thread. */
HANDLE readThread; /* Handle to reader thread. */
-
HANDLE writable; /* Manual-reset event to signal when the
* writer thread has finished waiting for the
* current buffer to be written. */
HANDLE readable; /* Manual-reset event to signal when the
* reader thread has finished waiting for
* input. */
+ HANDLE startWriter; /* Auto-reset event used by the main thread to
+ * signal when the writer thread should
+ * attempt to write to the pipe. */
+ HANDLE stopWriter; /* Manual-reset event used to alert the reader
+ * thread to fall-out and exit */
+ HANDLE startReader; /* Auto-reset event used by the main thread to
+ * signal when the reader thread should
+ * attempt to read from the pipe. */
+ HANDLE stopReader; /* Manual-reset event used to alert the reader
+ * thread to fall-out and exit */
DWORD writeError; /* An error caused by the last background
* write. Set to 0 if no error has been
* detected. This word is shared with the
* writer thread so access must be
- * synchronized with the writable object. */
+ * synchronized with the writable object.
+ */
char *writeBuf; /* Current background output buffer. Access is
* synchronized with the writable object. */
int writeBufLen; /* Size of write buffer. Access is
@@ -140,7 +142,7 @@ typedef struct PipeInfo {
* synchronized with the readable object. */
} PipeInfo;
-typedef struct {
+typedef struct ThreadSpecificData {
/*
* The following pointer refers to the head of the list of pipes that are
* being watched for file events.
@@ -156,7 +158,7 @@ static Tcl_ThreadDataKey dataKey;
* events are generated.
*/
-typedef struct {
+typedef struct PipeEvent {
Tcl_Event header; /* Information that is standard for all
* events. */
PipeInfo *infoPtr; /* Pointer to pipe info structure. Note that
@@ -171,28 +173,28 @@ typedef struct {
static int ApplicationType(Tcl_Interp *interp,
const char *fileName, char *fullName);
-static void BuildCommandLine(const char *executable, Tcl_Size argc,
+static void BuildCommandLine(const char *executable, int argc,
const char **argv, Tcl_DString *linePtr);
static BOOL HasConsole(void);
-static int PipeBlockModeProc(void *instanceData, int mode);
-static void PipeCheckProc(void *clientData, int flags);
-static int PipeClose2Proc(void *instanceData,
+static int PipeBlockModeProc(ClientData instanceData, int mode);
+static void PipeCheckProc(ClientData clientData, int flags);
+static int PipeClose2Proc(ClientData instanceData,
Tcl_Interp *interp, int flags);
static int PipeEventProc(Tcl_Event *evPtr, int flags);
-static int PipeGetHandleProc(void *instanceData,
- int direction, void **handlePtr);
+static int PipeGetHandleProc(ClientData instanceData,
+ int direction, ClientData *handlePtr);
static void PipeInit(void);
-static int PipeInputProc(void *instanceData, char *buf,
+static int PipeInputProc(ClientData instanceData, char *buf,
int toRead, int *errorCode);
-static int PipeOutputProc(void *instanceData,
+static int PipeOutputProc(ClientData instanceData,
const char *buf, int toWrite, int *errorCode);
static DWORD WINAPI PipeReaderThread(LPVOID arg);
-static void PipeSetupProc(void *clientData, int flags);
-static void PipeWatchProc(void *instanceData, int mask);
+static void PipeSetupProc(ClientData clientData, int flags);
+static void PipeWatchProc(ClientData instanceData, int mask);
static DWORD WINAPI PipeWriterThread(LPVOID arg);
static int TempFileName(WCHAR name[MAX_PATH]);
static int WaitForRead(PipeInfo *infoPtr, int blocking);
-static void PipeThreadActionProc(void *instanceData,
+static void PipeThreadActionProc(ClientData instanceData,
int action);
/*
@@ -200,7 +202,7 @@ static void PipeThreadActionProc(void *instanceData,
* I/O.
*/
-static const Tcl_ChannelType pipeChannelType = {
+static Tcl_ChannelType pipeChannelType = {
"pipe", /* Type name. */
TCL_CHANNEL_VERSION_5, /* v5 channel */
TCL_CLOSE2PROC, /* Close proc. */
@@ -217,7 +219,7 @@ static const Tcl_ChannelType pipeChannelType = {
NULL, /* handler proc. */
NULL, /* wide seek proc */
PipeThreadActionProc, /* thread action proc */
- NULL /* truncate */
+ NULL, /* truncate */
};
/*
@@ -310,7 +312,7 @@ TclpFinalizePipes(void)
void
PipeSetupProc(
- TCL_UNUSED(void *),
+ ClientData data, /* Not used. */
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
PipeInfo *infoPtr;
@@ -363,7 +365,7 @@ PipeSetupProc(
static void
PipeCheckProc(
- TCL_UNUSED(void *),
+ ClientData data, /* Not used. */
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
PipeInfo *infoPtr;
@@ -402,7 +404,7 @@ PipeCheckProc(
if (needEvent) {
infoPtr->flags |= PIPE_PENDING;
- evPtr = (PipeEvent *)ckalloc(sizeof(PipeEvent));
+ evPtr = (PipeEvent *) ckalloc(sizeof(PipeEvent));
evPtr->header.proc = PipeEventProc;
evPtr->infoPtr = infoPtr;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
@@ -433,7 +435,7 @@ TclWinMakeFile(
{
WinFile *filePtr;
- filePtr = (WinFile *)ckalloc(sizeof(WinFile));
+ filePtr = (WinFile *) ckalloc(sizeof(WinFile));
filePtr->type = WIN_FILE;
filePtr->handle = handle;
@@ -465,15 +467,24 @@ TempFileName(
WCHAR name[MAX_PATH]) /* Buffer in which name for temporary file
* gets stored. */
{
- const WCHAR *prefix = L"TCL";
- if (GetTempPathW(MAX_PATH, name) != 0) {
- if (GetTempFileNameW(name, prefix, 0, name) != 0) {
+ TCHAR *prefix;
+
+ prefix = (tclWinProcs->useWide) ? (TCHAR *) L"TCL" : (TCHAR *) "TCL";
+ if ((*tclWinProcs->getTempPathProc)(MAX_PATH, name) != 0) {
+ if ((*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0,
+ name) != 0) {
return 1;
}
}
- name[0] = '.';
- name[1] = '\0';
- return GetTempFileNameW(name, prefix, 0, name);
+ if (tclWinProcs->useWide) {
+ ((WCHAR *) name)[0] = '.';
+ ((WCHAR *) name)[1] = '\0';
+ } else {
+ ((char *) name)[0] = '.';
+ ((char *) name)[1] = '\0';
+ }
+ return (*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0,
+ name);
}
/*
@@ -500,7 +511,7 @@ TclpMakeFile(
HANDLE handle;
if (Tcl_GetChannelHandle(channel, direction,
- (void **) &handle) == TCL_OK) {
+ (ClientData *) &handle) == TCL_OK) {
return TclWinMakeFile(handle);
} else {
return (TclFile) NULL;
@@ -532,7 +543,7 @@ TclpOpenFile(
HANDLE handle;
DWORD accessMode, createMode, shareMode, flags;
Tcl_DString ds;
- const WCHAR *nativePath;
+ const TCHAR *nativePath;
/*
* Map the access bits to the NT access mode.
@@ -549,7 +560,7 @@ TclpOpenFile(
accessMode = (GENERIC_READ | GENERIC_WRITE);
break;
default:
- Tcl_WinConvertError(ERROR_INVALID_FUNCTION);
+ TclWinConvertError(ERROR_INVALID_FUNCTION);
return NULL;
}
@@ -577,8 +588,7 @@ TclpOpenFile(
break;
}
- Tcl_DStringInit(&ds);
- nativePath = Tcl_UtfToWCharDString(path, TCL_INDEX_NONE, &ds);
+ nativePath = Tcl_WinUtfToTChar(path, -1, &ds);
/*
* If the file is not being created, use the existing file attributes.
@@ -586,7 +596,7 @@ TclpOpenFile(
flags = 0;
if (!(mode & O_CREAT)) {
- flags = GetFileAttributesW(nativePath);
+ flags = (*tclWinProcs->getFileAttributesProc)(nativePath);
if (flags == 0xFFFFFFFF) {
flags = 0;
}
@@ -602,18 +612,18 @@ TclpOpenFile(
* Now we get to create the file.
*/
- handle = CreateFileW(nativePath, accessMode, shareMode,
- NULL, createMode, flags, NULL);
+ handle = (*tclWinProcs->createFileProc)(nativePath, accessMode,
+ shareMode, NULL, createMode, flags, NULL);
Tcl_DStringFree(&ds);
if (handle == INVALID_HANDLE_VALUE) {
DWORD err;
err = GetLastError();
- if ((err & 0xFFFFL) == ERROR_OPEN_FAILED) {
+ if ((err & 0xffffL) == ERROR_OPEN_FAILED) {
err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND;
}
- Tcl_WinConvertError(err);
+ TclWinConvertError(err);
return NULL;
}
@@ -659,7 +669,7 @@ TclpCreateTempFile(
return NULL;
}
- handle = CreateFileW(name,
+ handle = (*tclWinProcs->createFileProc)((TCHAR *) name,
GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL);
if (handle == INVALID_HANDLE_VALUE) {
@@ -679,7 +689,7 @@ TclpCreateTempFile(
* Convert the contents from UTF to native encoding
*/
- native = Tcl_UtfToExternalDString(NULL, contents, TCL_INDEX_NONE, &dstring);
+ native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring);
toCopy = Tcl_DStringLength(&dstring);
for (p = native; toCopy > 0; p++, toCopy--) {
@@ -719,9 +729,9 @@ TclpCreateTempFile(
Tcl_DStringFree(&dstring);
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
CloseHandle(handle);
- DeleteFileW(name);
+ (*tclWinProcs->deleteFileProc)((TCHAR *) name);
return NULL;
}
@@ -750,7 +760,7 @@ TclpTempFileName(void)
return NULL;
}
- return TclpNativeToNormalized(fileName);
+ return TclpNativeToNormalized((ClientData) fileName);
}
/*
@@ -784,7 +794,7 @@ TclpCreatePipe(
return 1;
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return 0;
}
@@ -825,8 +835,8 @@ TclpCloseFile(
&& (GetStdHandle(STD_ERROR_HANDLE) != filePtr->handle))) {
if (filePtr->handle != NULL &&
CloseHandle(filePtr->handle) == FALSE) {
- Tcl_WinConvertError(GetLastError());
- ckfree(filePtr);
+ TclWinConvertError(GetLastError());
+ ckfree((char *) filePtr);
return -1;
}
}
@@ -836,7 +846,7 @@ TclpCloseFile(
Tcl_Panic("TclpCloseFile: unexpected file type");
}
- ckfree(filePtr);
+ ckfree((char *) filePtr);
return 0;
}
@@ -851,7 +861,7 @@ TclpCloseFile(
* Results:
* Returns the process id for the child process. If the pid was not known
* by Tcl, either because the pid was not created by Tcl or the child
- * process has already been reaped, TCL_INDEX_NONE is returned.
+ * process has already been reaped, -1 is returned.
*
* Side effects:
* None.
@@ -859,7 +869,7 @@ TclpCloseFile(
*--------------------------------------------------------------------------
*/
-Tcl_Size
+int
TclpGetPid(
Tcl_Pid pid) /* The HANDLE of the child process. */
{
@@ -869,13 +879,13 @@ TclpGetPid(
Tcl_MutexLock(&pipeMutex);
for (infoPtr = procList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
- if (infoPtr->dwProcessId == PTR2UINT(pid)) {
+ if (infoPtr->hProcess == (HANDLE) pid) {
Tcl_MutexUnlock(&pipeMutex);
return infoPtr->dwProcessId;
}
}
Tcl_MutexUnlock(&pipeMutex);
- return TCL_INDEX_NONE;
+ return (unsigned long) -1;
}
/*
@@ -890,7 +900,7 @@ TclpGetPid(
*
* The complete Windows search path is searched to find the specified
* executable. If an executable by the given name is not found,
- * automatically tries appending standard extensions to the
+ * automatically tries appending ".com", ".exe", and ".bat" to the
* executable name.
*
* Results:
@@ -911,7 +921,7 @@ TclpCreateProcess(
* occurred when creating the child process.
* Error messages from the child process
* itself are sent to errorFile. */
- Tcl_Size argc, /* Number of arguments in following array. */
+ int argc, /* Number of arguments in following array. */
const char **argv, /* Array of argument strings. argv[0] contains
* the name of the executable converted to
* native format (using the
@@ -923,12 +933,12 @@ TclpCreateProcess(
* receive no standard input. */
TclFile outputFile, /* If non-NULL, gives the file that receives
* output from the child process. If
- * outputFile file is not writable or is
+ * outputFile file is not writeable or is
* NULL, output from the child will be
* discarded. */
TclFile errorFile, /* If non-NULL, gives the file that receives
* errors from the child process. If errorFile
- * file is not writable or is NULL, errors
+ * file is not writeable or is NULL, errors
* from the child will be discarded. errorFile
* may be the same as outputFile. */
Tcl_Pid *pidPtr) /* If this function is successful, pidPtr is
@@ -936,12 +946,12 @@ TclpCreateProcess(
* process. */
{
int result, applType, createFlags;
- Tcl_DString cmdLine; /* Complete command line (WCHAR). */
- STARTUPINFOW startInfo;
+ Tcl_DString cmdLine; /* Complete command line (TCHAR). */
+ STARTUPINFOA startInfo;
PROCESS_INFORMATION procInfo;
SECURITY_ATTRIBUTES secAtts;
HANDLE hProcess, h, inputHandle, outputHandle, errorHandle;
- char execPath[MAX_PATH * 3];
+ char execPath[MAX_PATH * TCL_UTF_MAX];
WinFile *filePtr;
PipeInit();
@@ -1026,10 +1036,9 @@ TclpCreateProcess(
0, TRUE, DUPLICATE_SAME_ACCESS);
}
if (startInfo.hStdInput == INVALID_HANDLE_VALUE) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't duplicate input handle: %s",
- Tcl_PosixError(interp)));
+ TclWinConvertError(GetLastError());
+ Tcl_AppendResult(interp, "couldn't duplicate input handle: ",
+ Tcl_PosixError(interp), (char *) NULL);
goto end;
}
@@ -1048,17 +1057,23 @@ TclpCreateProcess(
* sink.
*/
- startInfo.hStdOutput = CreateFileW(L"NUL:", GENERIC_WRITE, 0,
- &secAtts, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if ((TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS)
+ && (applType == APPL_DOS)) {
+ if (CreatePipe(&h, &startInfo.hStdOutput, &secAtts, 0) != FALSE) {
+ CloseHandle(h);
+ }
+ } else {
+ startInfo.hStdOutput = CreateFileA("NUL:", GENERIC_WRITE, 0,
+ &secAtts, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ }
} else {
DuplicateHandle(hProcess, outputHandle, hProcess,
&startInfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
}
if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't duplicate output handle: %s",
- Tcl_PosixError(interp)));
+ TclWinConvertError(GetLastError());
+ Tcl_AppendResult(interp, "couldn't duplicate output handle: ",
+ Tcl_PosixError(interp), (char *) NULL);
goto end;
}
@@ -1068,17 +1083,16 @@ TclpCreateProcess(
* sink.
*/
- startInfo.hStdError = CreateFileW(L"NUL:", GENERIC_WRITE, 0,
+ startInfo.hStdError = CreateFileA("NUL:", GENERIC_WRITE, 0,
&secAtts, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
} else {
DuplicateHandle(hProcess, errorHandle, hProcess, &startInfo.hStdError,
0, TRUE, DUPLICATE_SAME_ACCESS);
}
if (startInfo.hStdError == INVALID_HANDLE_VALUE) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't duplicate error handle: %s",
- Tcl_PosixError(interp)));
+ TclWinConvertError(GetLastError());
+ Tcl_AppendResult(interp, "couldn't duplicate error handle: ",
+ Tcl_PosixError(interp), (char *) NULL);
goto end;
}
@@ -1095,23 +1109,110 @@ TclpCreateProcess(
* detached processes. The GUI window will still pop up to the foreground.
*/
- if (HasConsole()) {
- createFlags = 0;
- } else if (applType == APPL_DOS) {
- /*
- * Under NT, 16-bit DOS applications will not run unless they can
- * be attached to a console. If we are running without a console,
- * run the 16-bit program as an normal process inside of a hidden
- * console application, and then run that hidden console as a
- * detached process.
- */
+ if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
+ if (HasConsole()) {
+ createFlags = 0;
+ } else if (applType == APPL_DOS) {
+ /*
+ * Under NT, 16-bit DOS applications will not run unless they can
+ * be attached to a console. If we are running without a console,
+ * run the 16-bit program as an normal process inside of a hidden
+ * console application, and then run that hidden console as a
+ * detached process.
+ */
- startInfo.wShowWindow = SW_HIDE;
- startInfo.dwFlags |= STARTF_USESHOWWINDOW;
- createFlags = CREATE_NEW_CONSOLE;
- TclDStringAppendLiteral(&cmdLine, "cmd.exe /c");
+ startInfo.wShowWindow = SW_HIDE;
+ startInfo.dwFlags |= STARTF_USESHOWWINDOW;
+ createFlags = CREATE_NEW_CONSOLE;
+ Tcl_DStringAppend(&cmdLine, "cmd.exe /c", -1);
+ } else {
+ createFlags = DETACHED_PROCESS;
+ }
} else {
- createFlags = DETACHED_PROCESS;
+ if (HasConsole()) {
+ createFlags = 0;
+ } else {
+ createFlags = DETACHED_PROCESS;
+ }
+
+ if (applType == APPL_DOS) {
+ /*
+ * Under Windows 95, 16-bit DOS applications do not work well with
+ * pipes:
+ *
+ * 1. EOF on a pipe between a detached 16-bit DOS application and
+ * another application is not seen at the other end of the pipe,
+ * so the listening process blocks forever on reads. This inablity
+ * to detect EOF happens when either a 16-bit app or the 32-bit
+ * app is the listener.
+ *
+ * 2. If a 16-bit DOS application (detached or not) blocks when
+ * writing to a pipe, it will never wake up again, and it
+ * eventually brings the whole system down around it.
+ *
+ * The 16-bit application is run as a normal process inside of a
+ * hidden helper console app, and this helper may be run as a
+ * detached process. If any of the stdio handles is a pipe, the
+ * helper application accumulates information into temp files and
+ * forwards it to or from the DOS application as appropriate.
+ * This means that DOS apps must receive EOF from a stdin pipe
+ * before they will actually begin, and must finish generating
+ * stdout or stderr before the data will be sent to the next stage
+ * of the pipe.
+ *
+ * The helper app should be located in the same directory as the
+ * tcl dll.
+ */
+ Tcl_Obj *tclExePtr, *pipeDllPtr;
+ char *start, *end;
+ int i, fileExists;
+ Tcl_DString pipeDll;
+
+ if (createFlags != 0) {
+ startInfo.wShowWindow = SW_HIDE;
+ startInfo.dwFlags |= STARTF_USESHOWWINDOW;
+ createFlags = CREATE_NEW_CONSOLE;
+ }
+
+ Tcl_DStringInit(&pipeDll);
+ Tcl_DStringAppend(&pipeDll, TCL_PIPE_DLL, -1);
+ tclExePtr = TclGetObjNameOfExecutable();
+ Tcl_IncrRefCount(tclExePtr);
+ start = Tcl_GetStringFromObj(tclExePtr, &i);
+ for (end = start + (i-1); end > start; end--) {
+ if (*end == '/') {
+ break;
+ }
+ }
+ if (*end != '/') {
+ Tcl_AppendResult(interp, "no / in executable path name \"",
+ start, "\"", (char *) NULL);
+ Tcl_DecrRefCount(tclExePtr);
+ Tcl_DStringFree(&pipeDll);
+ goto end;
+ }
+ i = (end - start) + 1;
+ pipeDllPtr = Tcl_NewStringObj(start, i);
+ Tcl_AppendToObj(pipeDllPtr, Tcl_DStringValue(&pipeDll), -1);
+ Tcl_IncrRefCount(pipeDllPtr);
+ if (Tcl_FSConvertToPathType(interp, pipeDllPtr) != TCL_OK) {
+ Tcl_Panic("Tcl_FSConvertToPathType failed");
+ }
+ fileExists = (Tcl_FSAccess(pipeDllPtr, F_OK) == 0);
+ if (!fileExists) {
+ Tcl_AppendResult(interp, "Tcl pipe dll \"",
+ Tcl_DStringValue(&pipeDll), "\" not found",
+ (char *) NULL);
+ Tcl_DecrRefCount(tclExePtr);
+ Tcl_DecrRefCount(pipeDllPtr);
+ Tcl_DStringFree(&pipeDll);
+ goto end;
+ }
+ Tcl_DStringAppend(&cmdLine, Tcl_DStringValue(&pipeDll), -1);
+ Tcl_DecrRefCount(tclExePtr);
+ Tcl_DecrRefCount(pipeDllPtr);
+ Tcl_DStringFree(&pipeDll);
+ }
}
/*
@@ -1134,12 +1235,12 @@ TclpCreateProcess(
BuildCommandLine(execPath, argc, argv, &cmdLine);
- if (CreateProcessW(NULL, (WCHAR *) Tcl_DStringValue(&cmdLine),
- NULL, NULL, TRUE, (DWORD) createFlags, NULL, NULL, &startInfo,
- &procInfo) == 0) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf("couldn't execute \"%s\": %s",
- argv[0], Tcl_PosixError(interp)));
+ if ((*tclWinProcs->createProcessProc)(NULL,
+ (TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE,
+ (DWORD) createFlags, NULL, NULL, &startInfo, &procInfo) == 0) {
+ TclWinConvertError(GetLastError());
+ Tcl_AppendResult(interp, "couldn't execute \"", argv[0],
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
goto end;
}
@@ -1156,14 +1257,14 @@ TclpCreateProcess(
* will be created for each process but the previous instances may not be
* cleaned up. This results in a significant virtual memory loss each time
* the process is spawned. If there is a WaitForInputIdle() call between
- * CreateProcessW() and CloseHandle(), the problem does not occur." PSS ID
+ * CreateProcess() and CloseHandle(), the problem does not occur." PSS ID
* Number: Q124121
*/
WaitForInputIdle(procInfo.hProcess, 5000);
CloseHandle(procInfo.hThread);
- *pidPtr = (Tcl_Pid)INT2PTR(procInfo.dwProcessId);
+ *pidPtr = (Tcl_Pid) procInfo.hProcess;
if (*pidPtr != 0) {
TclWinAddProcess(procInfo.hProcess, procInfo.dwProcessId);
}
@@ -1205,7 +1306,7 @@ HasConsole(void)
{
HANDLE handle;
- handle = CreateFileW(L"CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
+ handle = CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle != INVALID_HANDLE_VALUE) {
@@ -1260,22 +1361,22 @@ ApplicationType(
{
int applType, i, nameLen, found;
HANDLE hFile;
- WCHAR *rest;
+ TCHAR *rest;
char *ext;
char buf[2];
DWORD attr, read;
IMAGE_DOS_HEADER header;
Tcl_DString nameBuf, ds;
- const WCHAR *nativeName;
+ const TCHAR *nativeName;
WCHAR nativeFullPath[MAX_PATH];
- static const char extensions[][5] = {"", ".com", ".exe", ".bat", ".cmd"};
+ static const char extensions[][5] = {"", ".com", ".exe", ".bat"};
/*
* Look for the program as an external program. First try the name as it
- * is, then try adding .com, .exe, .bat and .cmd, in that order, to the name,
+ * is, then try adding .com, .exe, and .bat, in that order, to the name,
* looking for an executable.
*
- * Using the raw SearchPathW() function doesn't do quite what is necessary.
+ * Using the raw SearchPath() function doesn't do quite what is necessary.
* If the name of the executable already contains a '.' character, it will
* not try appending the specified extension when searching (in other
* words, SearchPath will not find the program "a.b.exe" if the arguments
@@ -1285,17 +1386,16 @@ ApplicationType(
applType = APPL_NONE;
Tcl_DStringInit(&nameBuf);
- Tcl_DStringAppend(&nameBuf, originalName, TCL_INDEX_NONE);
+ Tcl_DStringAppend(&nameBuf, originalName, -1);
nameLen = Tcl_DStringLength(&nameBuf);
for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
Tcl_DStringSetLength(&nameBuf, nameLen);
- Tcl_DStringAppend(&nameBuf, extensions[i], TCL_INDEX_NONE);
- Tcl_DStringInit(&ds);
- nativeName = Tcl_UtfToWCharDString(Tcl_DStringValue(&nameBuf),
+ Tcl_DStringAppend(&nameBuf, extensions[i], -1);
+ nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&nameBuf),
Tcl_DStringLength(&nameBuf), &ds);
- found = SearchPathW(NULL, nativeName, NULL, MAX_PATH,
- nativeFullPath, &rest);
+ found = (*tclWinProcs->searchPathProc)(NULL, nativeName, NULL,
+ MAX_PATH, nativeFullPath, &rest);
Tcl_DStringFree(&ds);
if (found == 0) {
continue;
@@ -1306,22 +1406,20 @@ ApplicationType(
* known type.
*/
- attr = GetFileAttributesW(nativeFullPath);
- if ((attr == 0xFFFFFFFF) || (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ attr = (*tclWinProcs->getFileAttributesProc)((TCHAR *) nativeFullPath);
+ if ((attr == 0xffffffff) || (attr & FILE_ATTRIBUTE_DIRECTORY)) {
continue;
}
- Tcl_DStringInit(&ds);
- strcpy(fullName, Tcl_WCharToUtfDString(nativeFullPath, TCL_INDEX_NONE, &ds));
+ strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
Tcl_DStringFree(&ds);
ext = strrchr(fullName, '.');
- if ((ext != NULL) &&
- (strcasecmp(ext, ".cmd") == 0 || strcasecmp(ext, ".bat") == 0)) {
+ if ((ext != NULL) && (strcasecmp(ext, ".bat") == 0)) {
applType = APPL_DOS;
break;
}
- hFile = CreateFileW(nativeFullPath,
+ hFile = (*tclWinProcs->createFileProc)((TCHAR *) nativeFullPath,
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
@@ -1387,13 +1485,13 @@ ApplicationType(
Tcl_DStringFree(&nameBuf);
if (applType == APPL_NONE) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf("couldn't execute \"%s\": %s",
- originalName, Tcl_PosixError(interp)));
+ TclWinConvertError(GetLastError());
+ Tcl_AppendResult(interp, "couldn't execute \"", originalName,
+ "\": ", Tcl_PosixError(interp), (char *) NULL);
return APPL_NONE;
}
- if (applType == APPL_WIN3X) {
+ if ((applType == APPL_DOS) || (applType == APPL_WIN3X)) {
/*
* Replace long path name of executable with short path name for
* 16-bit applications. Otherwise the application may not be able to
@@ -1401,9 +1499,9 @@ ApplicationType(
* application name from the arguments.
*/
- GetShortPathNameW(nativeFullPath, nativeFullPath, MAX_PATH);
- Tcl_DStringInit(&ds);
- strcpy(fullName, Tcl_WCharToUtfDString(nativeFullPath, TCL_INDEX_NONE, &ds));
+ (*tclWinProcs->getShortPathNameProc)((TCHAR *) nativeFullPath,
+ nativeFullPath, MAX_PATH);
+ strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds));
Tcl_DStringFree(&ds);
}
return applType;
@@ -1415,7 +1513,7 @@ ApplicationType(
* BuildCommandLine --
*
* The command line arguments are stored in linePtr separated by spaces,
- * in a form that CreateProcessW() understands. Special characters in
+ * in a form that CreateProcess() understands. Special characters in
* individual arguments from argv[] must be quoted when being stored in
* cmdLine.
*
@@ -1428,144 +1526,18 @@ ApplicationType(
*----------------------------------------------------------------------
*/
-static const char *
-BuildCmdLineBypassBS(
- const char *current,
- const char **bspos)
-{
- /*
- * Mark first backslash position.
- */
-
- if (!*bspos) {
- *bspos = current;
- }
- do {
- current++;
- } while (*current == '\\');
- return current;
-}
-
-static void
-QuoteCmdLineBackslash(
- Tcl_DString *dsPtr,
- const char *start,
- const char *current,
- const char *bspos)
-{
- if (!bspos) {
- if (current > start) { /* part before current (special) */
- Tcl_DStringAppend(dsPtr, start, (int) (current - start));
- }
- } else {
- if (bspos > start) { /* part before first backslash */
- Tcl_DStringAppend(dsPtr, start, (int) (bspos - start));
- }
- while (bspos++ < current) { /* each backslash twice */
- TclDStringAppendLiteral(dsPtr, "\\\\");
- }
- }
-}
-
-static const char *
-QuoteCmdLinePart(
- Tcl_DString *dsPtr,
- const char *start,
- const char *special,
- const char *specMetaChars,
- const char **bspos)
-{
- if (!*bspos) {
- /*
- * Rest before special (before quote).
- */
-
- QuoteCmdLineBackslash(dsPtr, start, special, NULL);
- start = special;
- } else {
- /*
- * Rest before first backslash and backslashes into new quoted block.
- */
-
- QuoteCmdLineBackslash(dsPtr, start, *bspos, NULL);
- start = *bspos;
- }
-
- /*
- * escape all special chars enclosed in quotes like `"..."`, note that
- * here we don't must escape `\` (with `\`), because it's outside of the
- * main quotes, so `\` remains `\`, but important - not at end of part,
- * because results as before the quote, so `%\%\` should be escaped as
- * `"%\%"\\`).
- */
-
- TclDStringAppendLiteral(dsPtr, "\""); /* opening escape quote-char */
- do {
- *bspos = NULL;
- special++;
- if (*special == '\\') {
- /*
- * Bypass backslashes (and mark first backslash position).
- */
-
- special = BuildCmdLineBypassBS(special, bspos);
- if (*special == '\0') {
- break;
- }
- }
- } while (*special && strchr(specMetaChars, *special));
- if (!*bspos) {
- /*
- * Unescaped rest before quote.
- */
-
- QuoteCmdLineBackslash(dsPtr, start, special, NULL);
- } else {
- /*
- * Unescaped rest before first backslash (rather belongs to the main
- * block).
- */
-
- QuoteCmdLineBackslash(dsPtr, start, *bspos, NULL);
- }
- TclDStringAppendLiteral(dsPtr, "\""); /* closing escape quote-char */
- return special;
-}
-
static void
BuildCommandLine(
const char *executable, /* Full path of executable (including
* extension). Replacement for argv[0]. */
- Tcl_Size argc, /* Number of arguments. */
+ int argc, /* Number of arguments. */
const char **argv, /* Argument strings in UTF. */
Tcl_DString *linePtr) /* Initialized Tcl_DString that receives the
- * command line (WCHAR). */
+ * command line (TCHAR). */
{
- const char *arg, *start, *special, *bspos;
- int quote = 0;
- Tcl_Size i;
+ const char *arg, *start, *special;
+ int quote, i;
Tcl_DString ds;
-#ifdef TCL_WIN_PIPE_FULLESC
- /* full escape inclusive %-subst avoidance */
- static const char specMetaChars[] = "&|^<>!()%";
- /* Characters to enclose in quotes if unpaired
- * quote flag set. */
- static const char specMetaChars2[] = "%";
- /* Character to enclose in quotes in any case
- * (regardless of unpaired-flag). */
-#else
- /* escape considering quotation only (no %-subst avoidance) */
- static const char specMetaChars[] = "&|^<>!()";
- /* Characters to enclose in quotes if unpaired
- * quote flag set. */
-#endif
- /*
- * Quote flags:
- * CL_ESCAPE - escape argument;
- * CL_QUOTE - enclose in quotes;
- * CL_UNPAIRED - previous arguments chain contains unpaired quote-char;
- */
- enum {CL_ESCAPE = 1, CL_QUOTE = 2, CL_UNPAIRED = 4};
Tcl_DStringInit(&ds);
@@ -1573,9 +1545,9 @@ BuildCommandLine(
* Prime the path. Add a space separator if we were primed with something.
*/
- TclDStringAppendDString(&ds, linePtr);
+ Tcl_DStringAppend(&ds, Tcl_DStringValue(linePtr), -1);
if (Tcl_DStringLength(linePtr) > 0) {
- TclDStringAppendLiteral(&ds, " ");
+ Tcl_DStringAppend(&ds, " ", 1);
}
for (i = 0; i < argc; i++) {
@@ -1583,166 +1555,68 @@ BuildCommandLine(
arg = executable;
} else {
arg = argv[i];
- TclDStringAppendLiteral(&ds, " ");
+ Tcl_DStringAppend(&ds, " ", 1);
}
- quote &= ~(CL_ESCAPE|CL_QUOTE); /* reset escape flags */
- bspos = NULL;
+ quote = 0;
if (arg[0] == '\0') {
- quote = CL_QUOTE;
+ quote = 1;
} else {
- for (start = arg;
- *start != '\0' &&
- (quote & (CL_ESCAPE|CL_QUOTE)) != (CL_ESCAPE|CL_QUOTE);
- start++) {
- if (*start & 0x80) {
- continue;
- }
- if (TclIsSpaceProc(*start)) {
- quote |= CL_QUOTE; /* quote only */
- if (bspos) { /* if backslash found, escape & quote */
- quote |= CL_ESCAPE;
- break;
- }
- continue;
- }
- if (strchr(specMetaChars, *start)) {
- quote |= (CL_ESCAPE|CL_QUOTE); /* escape & quote */
+ int count;
+ Tcl_UniChar ch;
+ for (start = arg; *start != '\0'; start += count) {
+ count = Tcl_UtfToUniChar(start, &ch);
+ if (Tcl_UniCharIsSpace(ch)) { /* INTL: ISO space. */
+ quote = 1;
break;
}
- if (*start == '"') {
- quote |= CL_ESCAPE; /* escape only */
- continue;
- }
- if (*start == '\\') {
- bspos = start;
- if (quote & CL_QUOTE) { /* if quote, escape & quote */
- quote |= CL_ESCAPE;
- break;
- }
- continue;
- }
}
- bspos = NULL;
- }
- if (quote & CL_QUOTE) {
- /*
- * Start of argument (main opening quote-char).
- */
-
- TclDStringAppendLiteral(&ds, "\"");
}
- if (!(quote & CL_ESCAPE)) {
- /*
- * Nothing to escape.
- */
-
- Tcl_DStringAppend(&ds, arg, TCL_INDEX_NONE);
- } else {
- start = arg;
- for (special = arg; *special != '\0'; ) {
- /*
- * Position of `\` is important before quote or at end (equal
- * `\"` because quoted).
- */
-
- if (*special == '\\') {
- /*
- * Bypass backslashes (and mark first backslash position)
- */
+ if (quote) {
+ Tcl_DStringAppend(&ds, "\"", 1);
+ }
+ start = arg;
+ for (special = arg; ; ) {
+ if ((*special == '\\') && (special[1] == '\\' ||
+ special[1] == '"' || (quote && special[1] == '\0'))) {
+ Tcl_DStringAppend(&ds, start, (int) (special - start));
+ start = special;
+ while (1) {
+ special++;
+ if (*special == '"' || (quote && *special == '\0')) {
+ /*
+ * N backslashes followed a quote -> insert N * 2 + 1
+ * backslashes then a quote.
+ */
- special = BuildCmdLineBypassBS(special, &bspos);
- if (*special == '\0') {
+ Tcl_DStringAppend(&ds, start,
+ (int) (special - start));
+ break;
+ }
+ if (*special != '\\') {
break;
}
}
- /* ["] */
- if (*special == '"') {
- /*
- * Invert the unpaired flag - observe unpaired quotes
- */
-
- quote ^= CL_UNPAIRED;
-
- /*
- * Add part before (and escape backslashes before quote).
- */
-
- QuoteCmdLineBackslash(&ds, start, special, bspos);
- bspos = NULL;
-
- /*
- * Escape using backslash
- */
-
- TclDStringAppendLiteral(&ds, "\\\"");
- start = ++special;
- continue;
- }
-
- /*
- * Unpaired (escaped) quote causes special handling on
- * meta-chars
- */
-
- if ((quote & CL_UNPAIRED) && strchr(specMetaChars, *special)) {
- special = QuoteCmdLinePart(&ds, start, special,
- specMetaChars, &bspos);
-
- /*
- * Start to current or first backslash
- */
-
- start = !bspos ? special : bspos;
- continue;
- }
-#ifdef TCL_WIN_PIPE_FULLESC
- /*
- * Special case for % - should be enclosed always (paired
- * also)
- */
-
- if (strchr(specMetaChars2, *special)) {
- special = QuoteCmdLinePart(&ds, start, special,
- specMetaChars2, &bspos);
-
- /*
- * Start to current or first backslash.
- */
-
- start = !bspos ? special : bspos;
- continue;
- }
-#endif
-
- /*
- * Other not special (and not meta) character
- */
-
- bspos = NULL; /* reset last backslash position (not
- * interesting) */
- special++;
+ Tcl_DStringAppend(&ds, start, (int) (special - start));
+ start = special;
}
-
- /*
- * Rest of argument (and escape backslashes before closing main
- * quote)
- */
-
- QuoteCmdLineBackslash(&ds, start, special,
- (quote & CL_QUOTE) ? bspos : NULL);
+ if (*special == '"') {
+ Tcl_DStringAppend(&ds, start, (int) (special - start));
+ Tcl_DStringAppend(&ds, "\\\"", 2);
+ start = special + 1;
+ }
+ if (*special == '\0') {
+ break;
+ }
+ special++;
}
- if (quote & CL_QUOTE) {
- /*
- * End of argument (main closing quote-char)
- */
-
- TclDStringAppendLiteral(&ds, "\"");
+ Tcl_DStringAppend(&ds, start, (int) (special - start));
+ if (quote) {
+ Tcl_DStringAppend(&ds, "\"", 1);
}
}
Tcl_DStringFree(linePtr);
- Tcl_DStringInit(linePtr);
- Tcl_UtfToWCharDString(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
+ Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
Tcl_DStringFree(&ds);
}
@@ -1769,11 +1643,12 @@ TclpCreateCommandChannel(
TclFile writeFile, /* If non-null, gives the file for writing. */
TclFile errorFile, /* If non-null, gives the file where errors
* can be read. */
- Tcl_Size numPids, /* The number of pids in the pid array. */
+ int numPids, /* The number of pids in the pid array. */
Tcl_Pid *pidPtr) /* An array of process identifiers. */
{
char channelName[16 + TCL_INTEGER_SPACE];
- PipeInfo *infoPtr = (PipeInfo *)ckalloc(sizeof(PipeInfo));
+ DWORD id;
+ PipeInfo *infoPtr = (PipeInfo *) ckalloc((unsigned) sizeof(PipeInfo));
PipeInit();
@@ -1788,7 +1663,7 @@ TclpCreateCommandChannel(
infoPtr->writeBuf = 0;
infoPtr->writeBufLen = 0;
infoPtr->writeError = 0;
- infoPtr->channel = NULL;
+ infoPtr->channel = (Tcl_Channel) NULL;
infoPtr->validMask = 0;
@@ -1799,14 +1674,14 @@ TclpCreateCommandChannel(
* Start the background reader thread.
*/
- infoPtr->readable = CreateEventW(NULL, TRUE, TRUE, NULL);
+ infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
+ infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL);
+ infoPtr->stopReader = CreateEvent(NULL, TRUE, FALSE, NULL);
infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread,
- TclPipeThreadCreateTI(&infoPtr->readTI, infoPtr, infoPtr->readable),
- 0, NULL);
+ infoPtr, 0, &id);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_READABLE;
} else {
- infoPtr->readTI = NULL;
infoPtr->readThread = 0;
}
if (writeFile != NULL) {
@@ -1814,15 +1689,13 @@ TclpCreateCommandChannel(
* Start the background writer thread.
*/
- infoPtr->writable = CreateEventW(NULL, TRUE, TRUE, NULL);
+ infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
+ infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
+ infoPtr->stopWriter = CreateEvent(NULL, TRUE, FALSE, NULL);
infoPtr->writeThread = CreateThread(NULL, 256, PipeWriterThread,
- TclPipeThreadCreateTI(&infoPtr->writeTI, infoPtr, infoPtr->writable),
- 0, NULL);
- SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST);
+ infoPtr, 0, &id);
+ SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_WRITABLE;
- } else {
- infoPtr->writeTI = NULL;
- infoPtr->writeThread = 0;
}
/*
@@ -1832,9 +1705,9 @@ TclpCreateCommandChannel(
* unique, in case channels share handles (stdin/stdout).
*/
- TclWinGenerateChannelName(channelName, "file", infoPtr);
+ sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t)infoPtr);
infoPtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
- infoPtr, infoPtr->validMask);
+ (ClientData) infoPtr, infoPtr->validMask);
/*
* Pipes have AUTO translation mode on Windows and ^Z eof char, which
@@ -1842,58 +1715,16 @@ TclpCreateCommandChannel(
* Windows programs that expect a ^Z at EOF.
*/
- Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto");
- Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\x1A {}");
+ Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel,
+ "-translation", "auto");
+ Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel,
+ "-eofchar", "\032 {}");
return infoPtr->channel;
}
/*
*----------------------------------------------------------------------
*
- * Tcl_CreatePipe --
- *
- * System dependent interface to create a pipe for the [chan pipe]
- * command. Stolen from TclX.
- *
- * Results:
- * TCL_OK or TCL_ERROR.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_CreatePipe(
- Tcl_Interp *interp, /* Errors returned in result.*/
- Tcl_Channel *rchan, /* Where to return the read side. */
- Tcl_Channel *wchan, /* Where to return the write side. */
- TCL_UNUSED(int) /*flags*/) /* Reserved for future use. */
-{
- HANDLE readHandle, writeHandle;
- SECURITY_ATTRIBUTES sec;
-
- sec.nLength = sizeof(SECURITY_ATTRIBUTES);
- sec.lpSecurityDescriptor = NULL;
- sec.bInheritHandle = FALSE;
-
- if (!CreatePipe(&readHandle, &writeHandle, &sec, 0)) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "pipe creation failed: %s", Tcl_PosixError(interp)));
- return TCL_ERROR;
- }
-
- *rchan = Tcl_MakeFileChannel((void *) readHandle, TCL_READABLE);
- Tcl_RegisterChannel(interp, *rchan);
-
- *wchan = Tcl_MakeFileChannel((void *) writeHandle, TCL_WRITABLE);
- Tcl_RegisterChannel(interp, *wchan);
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
* TclGetAndDetachPids --
*
* Stores a list of the command PIDs for a command channel in the
@@ -1915,8 +1746,8 @@ TclGetAndDetachPids(
{
PipeInfo *pipePtr;
const Tcl_ChannelType *chanTypePtr;
- Tcl_Obj *pidsObj, *elemPtr;
- TCL_HASH_TYPE i;
+ int i;
+ char buf[TCL_INTEGER_SPACE];
/*
* Punt if the channel is not a command channel.
@@ -1927,16 +1758,14 @@ TclGetAndDetachPids(
return;
}
- pipePtr = (PipeInfo *)Tcl_GetChannelInstanceData(chan);
- TclNewObj(pidsObj);
+ pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan);
for (i = 0; i < pipePtr->numPids; i++) {
- TclNewIntObj(elemPtr, TclpGetPid(pipePtr->pidPtr[i]));
- Tcl_ListObjAppendElement(NULL, pidsObj, elemPtr);
- Tcl_DetachPids(1, &pipePtr->pidPtr[i]);
+ wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i]));
+ Tcl_AppendElement(interp, buf);
+ Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
}
- Tcl_SetObjResult(interp, pidsObj);
if (pipePtr->numPids > 0) {
- ckfree(pipePtr->pidPtr);
+ ckfree((char *) pipePtr->pidPtr);
pipePtr->numPids = 0;
}
}
@@ -1959,7 +1788,7 @@ TclGetAndDetachPids(
static int
PipeBlockModeProc(
- void *instanceData, /* Instance data for channel. */
+ ClientData instanceData, /* Instance data for channel. */
int mode) /* TCL_MODE_BLOCKING or
* TCL_MODE_NONBLOCKING. */
{
@@ -1998,7 +1827,7 @@ PipeBlockModeProc(
static int
PipeClose2Proc(
- void *instanceData, /* Pointer to PipeInfo structure. */
+ ClientData instanceData, /* Pointer to PipeInfo structure. */
Tcl_Interp *interp, /* For error reporting. */
int flags) /* Flags that indicate which side to close. */
{
@@ -2007,12 +1836,12 @@ PipeClose2Proc(
int errorCode, result;
PipeInfo *infoPtr, **nextPtrPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- int inExit = (TclInExit() || TclInThreadExit());
+ DWORD exitCode;
errorCode = 0;
result = 0;
- if ((!flags || flags & TCL_CLOSE_READ) && (pipePtr->readFile != NULL)) {
+ if ((!flags || flags == TCL_CLOSE_READ) && (pipePtr->readFile != NULL)) {
/*
* Clean up the background thread if necessary. Note that this must be
* done before we can close the file, since the thread may be blocking
@@ -2020,10 +1849,55 @@ PipeClose2Proc(
*/
if (pipePtr->readThread) {
+ /*
+ * The thread may already have closed on its own. Check its exit
+ * code.
+ */
+
+ GetExitCodeThread(pipePtr->readThread, &exitCode);
+
+ if (exitCode == STILL_ACTIVE) {
+ /*
+ * Set the stop event so that if the reader thread is blocked
+ * in PipeReaderThread on WaitForMultipleEvents, it will exit
+ * cleanly.
+ */
+
+ SetEvent(pipePtr->stopReader);
+
+ /*
+ * Wait at most 20 milliseconds for the reader thread to
+ * close.
+ */
+
+ if (WaitForSingleObject(pipePtr->readThread,
+ 20) == WAIT_TIMEOUT) {
+ /*
+ * The thread must be blocked waiting for the pipe to
+ * become readable in ReadFile(). There isn't a clean way
+ * to exit the thread from this condition. We should
+ * terminate the child process instead to get the reader
+ * thread to fall out of ReadFile with a FALSE. (below) is
+ * not the correct way to do this, but will stay here
+ * until a better solution is found.
+ *
+ * Note that we need to guard against terminating the
+ * thread while it is in the middle of Tcl_ThreadAlert
+ * because it won't be able to release the notifier lock.
+ */
+
+ Tcl_MutexLock(&pipeMutex);
+
+ /* BUG: this leaks memory */
+ TerminateThread(pipePtr->readThread, 0);
+ Tcl_MutexUnlock(&pipeMutex);
+ }
+ }
- TclPipeThreadStop(&pipePtr->readTI, pipePtr->readThread);
CloseHandle(pipePtr->readThread);
CloseHandle(pipePtr->readable);
+ CloseHandle(pipePtr->startReader);
+ CloseHandle(pipePtr->stopReader);
pipePtr->readThread = NULL;
}
if (TclpCloseFile(pipePtr->readFile) != 0) {
@@ -2032,34 +1906,66 @@ PipeClose2Proc(
pipePtr->validMask &= ~TCL_READABLE;
pipePtr->readFile = NULL;
}
- if ((!flags || flags & TCL_CLOSE_WRITE) && (pipePtr->writeFile != NULL)) {
+ if ((!flags || flags & TCL_CLOSE_WRITE)
+ && (pipePtr->writeFile != NULL)) {
if (pipePtr->writeThread) {
+ /*
+ * Wait for the writer thread to finish the current buffer, then
+ * terminate the thread and close the handles. If the channel is
+ * nonblocking, there should be no pending write operations.
+ */
+
+ WaitForSingleObject(pipePtr->writable, INFINITE);
/*
- * Wait for the writer thread to finish the current buffer, then
- * terminate the thread and close the handles. If the channel is
- * nonblocking or may block during exit, bail out since the worker
- * thread is not interruptible and we want TIP#398-fast-exit.
+ * The thread may already have closed on it's own. Check its exit
+ * code.
*/
- if ((pipePtr->flags & PIPE_ASYNC) && inExit) {
- /* give it a chance to leave honorably */
- TclPipeThreadStopSignal(&pipePtr->writeTI, pipePtr->writable);
+ GetExitCodeThread(pipePtr->writeThread, &exitCode);
- if (WaitForSingleObject(pipePtr->writable, 20) == WAIT_TIMEOUT) {
- return EWOULDBLOCK;
- }
+ if (exitCode == STILL_ACTIVE) {
+ /*
+ * Set the stop event so that if the reader thread is blocked
+ * in PipeReaderThread on WaitForMultipleEvents, it will exit
+ * cleanly.
+ */
- } else {
+ SetEvent(pipePtr->stopWriter);
- WaitForSingleObject(pipePtr->writable, inExit ? 5000 : INFINITE);
+ /*
+ * Wait at most 20 milliseconds for the reader thread to
+ * close.
+ */
- }
+ if (WaitForSingleObject(pipePtr->writeThread,
+ 20) == WAIT_TIMEOUT) {
+ /*
+ * The thread must be blocked waiting for the pipe to
+ * consume input in WriteFile(). There isn't a clean way
+ * to exit the thread from this condition. We should
+ * terminate the child process instead to get the writer
+ * thread to fall out of WriteFile with a FALSE. (below)
+ * is not the correct way to do this, but will stay here
+ * until a better solution is found.
+ *
+ * Note that we need to guard against terminating the
+ * thread while it is in the middle of Tcl_ThreadAlert
+ * because it won't be able to release the notifier lock.
+ */
- TclPipeThreadStop(&pipePtr->writeTI, pipePtr->writeThread);
+ Tcl_MutexLock(&pipeMutex);
+
+ /* BUG: this leaks memory */
+ TerminateThread(pipePtr->writeThread, 0);
+ Tcl_MutexUnlock(&pipeMutex);
+ }
+ }
- CloseHandle(pipePtr->writable);
CloseHandle(pipePtr->writeThread);
+ CloseHandle(pipePtr->writable);
+ CloseHandle(pipePtr->startWriter);
+ CloseHandle(pipePtr->stopWriter);
pipePtr->writeThread = NULL;
}
if (TclpCloseFile(pipePtr->writeFile) != 0) {
@@ -2094,7 +2000,7 @@ PipeClose2Proc(
}
}
- if ((pipePtr->flags & PIPE_ASYNC) || inExit) {
+ if ((pipePtr->flags & PIPE_ASYNC) || TclInExit()) {
/*
* If the channel is non-blocking or Tcl is being cleaned up, just
* detach the children PIDs, reap them (important if we are in a
@@ -2119,11 +2025,12 @@ PipeClose2Proc(
*/
if (pipePtr->errorFile) {
- WinFile *filePtr = (WinFile *) pipePtr->errorFile;
+ WinFile *filePtr;
- errChan = Tcl_MakeFileChannel((void *)filePtr->handle,
+ filePtr = (WinFile*)pipePtr->errorFile;
+ errChan = Tcl_MakeFileChannel((ClientData) filePtr->handle,
TCL_READABLE);
- ckfree(filePtr);
+ ckfree((char *) filePtr);
} else {
errChan = NULL;
}
@@ -2133,14 +2040,14 @@ PipeClose2Proc(
}
if (pipePtr->numPids > 0) {
- ckfree(pipePtr->pidPtr);
+ ckfree((char *) pipePtr->pidPtr);
}
if (pipePtr->writeBuf != NULL) {
ckfree(pipePtr->writeBuf);
}
- ckfree(pipePtr);
+ ckfree((char*) pipePtr);
if (errorCode == 0) {
return result;
@@ -2168,7 +2075,7 @@ PipeClose2Proc(
static int
PipeInputProc(
- void *instanceData, /* Pipe state. */
+ ClientData instanceData, /* Pipe state. */
char *buf, /* Where to store data read. */
int bufSize, /* How much space is available in the
* buffer? */
@@ -2233,7 +2140,7 @@ PipeInputProc(
return bytesRead;
}
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
if (errno == EPIPE) {
infoPtr->readFlags |= PIPE_EOF;
return 0;
@@ -2262,7 +2169,7 @@ PipeInputProc(
static int
PipeOutputProc(
- void *instanceData, /* Pipe state. */
+ ClientData instanceData, /* Pipe state. */
const char *buf, /* The data buffer. */
int toWrite, /* How many bytes to write? */
int *errorCode) /* Where to store error code. */
@@ -2272,18 +2179,14 @@ PipeOutputProc(
DWORD bytesWritten, timeout;
*errorCode = 0;
-
- /* avoid blocking if pipe-thread exited */
- timeout = ((infoPtr->flags & PIPE_ASYNC)
- || !TclPipeThreadIsAlive(&infoPtr->writeTI)
- || TclInExit() || TclInThreadExit()) ? 0 : INFINITE;
+ timeout = (infoPtr->flags & PIPE_ASYNC) ? 0 : INFINITE;
if (WaitForSingleObject(infoPtr->writable, timeout) == WAIT_TIMEOUT) {
/*
* The writer thread is blocked waiting for a write to complete and
* the channel is in non-blocking mode.
*/
- errno = EWOULDBLOCK;
+ errno = EAGAIN;
goto error;
}
@@ -2292,7 +2195,7 @@ PipeOutputProc(
*/
if (infoPtr->writeError) {
- Tcl_WinConvertError(infoPtr->writeError);
+ TclWinConvertError(infoPtr->writeError);
infoPtr->writeError = 0;
goto error;
}
@@ -2312,12 +2215,12 @@ PipeOutputProc(
ckfree(infoPtr->writeBuf);
}
infoPtr->writeBufLen = toWrite;
- infoPtr->writeBuf = (char *)ckalloc(toWrite);
+ infoPtr->writeBuf = ckalloc((unsigned int) toWrite);
}
- memcpy(infoPtr->writeBuf, buf, toWrite);
+ memcpy(infoPtr->writeBuf, buf, (size_t) toWrite);
infoPtr->toWrite = toWrite;
ResetEvent(infoPtr->writable);
- TclPipeThreadSignal(&infoPtr->writeTI);
+ SetEvent(infoPtr->startWriter);
bytesWritten = toWrite;
} else {
/*
@@ -2327,7 +2230,7 @@ PipeOutputProc(
if (WriteFile(filePtr->handle, (LPVOID) buf, (DWORD) toWrite,
&bytesWritten, (LPOVERLAPPED) NULL) == FALSE) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
goto error;
}
}
@@ -2444,7 +2347,7 @@ PipeEventProc(
static void
PipeWatchProc(
- void *instanceData, /* Pipe state. */
+ ClientData instanceData, /* Pipe state. */
int mask) /* What events to watch for, OR-ed combination
* of TCL_READABLE, TCL_WRITABLE and
* TCL_EXCEPTION. */
@@ -2462,7 +2365,6 @@ PipeWatchProc(
infoPtr->watchMask = mask & infoPtr->validMask;
if (infoPtr->watchMask) {
Tcl_Time blockTime = { 0, 0 };
-
if (!oldMask) {
infoPtr->nextPtr = tsdPtr->firstPipePtr;
tsdPtr->firstPipePtr = infoPtr;
@@ -2506,21 +2408,21 @@ PipeWatchProc(
static int
PipeGetHandleProc(
- void *instanceData, /* The pipe state. */
+ ClientData instanceData, /* The pipe state. */
int direction, /* TCL_READABLE or TCL_WRITABLE */
- void **handlePtr) /* Where to store the handle. */
+ ClientData *handlePtr) /* Where to store the handle. */
{
PipeInfo *infoPtr = (PipeInfo *) instanceData;
WinFile *filePtr;
if (direction == TCL_READABLE && infoPtr->readFile) {
filePtr = (WinFile*) infoPtr->readFile;
- *handlePtr = (void *) filePtr->handle;
+ *handlePtr = (ClientData) filePtr->handle;
return TCL_OK;
}
if (direction == TCL_WRITABLE && infoPtr->writeFile) {
filePtr = (WinFile*) infoPtr->writeFile;
- *handlePtr = (void *) filePtr->handle;
+ *handlePtr = (ClientData) filePtr->handle;
return TCL_OK;
}
return TCL_ERROR;
@@ -2574,7 +2476,7 @@ Tcl_WaitPid(
prevPtrPtr = &procList;
for (infoPtr = procList; infoPtr != NULL;
prevPtrPtr = &infoPtr->nextPtr, infoPtr = infoPtr->nextPtr) {
- if (infoPtr->dwProcessId == PTR2UINT(pid)) {
+ if (infoPtr->hProcess == (HANDLE) pid) {
*prevPtrPtr = infoPtr->nextPtr;
break;
}
@@ -2692,7 +2594,7 @@ Tcl_WaitPid(
*/
CloseHandle(infoPtr->hProcess);
- ckfree(infoPtr);
+ ckfree((char*)infoPtr);
return result;
}
@@ -2718,9 +2620,9 @@ Tcl_WaitPid(
void
TclWinAddProcess(
void *hProcess, /* Handle to process */
- Tcl_Size id) /* Global process identifier */
+ unsigned long id) /* Global process identifier */
{
- ProcInfo *procPtr = (ProcInfo *)ckalloc(sizeof(ProcInfo));
+ ProcInfo *procPtr = (ProcInfo *) ckalloc(sizeof(ProcInfo));
PipeInit();
@@ -2749,9 +2651,10 @@ TclWinAddProcess(
*----------------------------------------------------------------------
*/
+ /* ARGSUSED */
int
Tcl_PidObjCmd(
- TCL_UNUSED(void *),
+ ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
@@ -2759,18 +2662,19 @@ Tcl_PidObjCmd(
Tcl_Channel chan;
const Tcl_ChannelType *chanTypePtr;
PipeInfo *pipePtr;
- TCL_HASH_TYPE i;
- Tcl_Obj *resultPtr, *elemPtr;
+ int i;
+ Tcl_Obj *resultPtr;
+ char buf[TCL_INTEGER_SPACE];
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
return TCL_ERROR;
}
if (objc == 1) {
- TclNewIntObj(elemPtr, getpid());
- Tcl_SetObjResult(interp, elemPtr);
+ wsprintfA(buf, "%lu", (unsigned long) getpid());
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1));
} else {
- chan = Tcl_GetChannel(interp, TclGetString(objv[1]),
+ chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], NULL),
NULL);
if (chan == (Tcl_Channel) NULL) {
return TCL_ERROR;
@@ -2781,10 +2685,11 @@ Tcl_PidObjCmd(
}
pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan);
- TclNewObj(resultPtr);
+ resultPtr = Tcl_NewObj();
for (i = 0; i < pipePtr->numPids; i++) {
- TclNewIntObj(elemPtr, TclpGetPid(pipePtr->pidPtr[i]));
- Tcl_ListObjAppendElement(/*interp*/ NULL, resultPtr, elemPtr);
+ wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i]));
+ Tcl_ListObjAppendElement(/*interp*/ NULL, resultPtr,
+ Tcl_NewStringObj(buf, -1));
}
Tcl_SetObjResult(interp, resultPtr);
}
@@ -2820,23 +2725,21 @@ WaitForRead(
* or not. */
{
DWORD timeout, count;
- HANDLE handle = ((WinFile *) infoPtr->readFile)->handle;
+ HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle;
while (1) {
/*
* Synchronize with the reader thread.
*/
- /* avoid blocking if pipe-thread exited */
- timeout = (!blocking || !TclPipeThreadIsAlive(&infoPtr->readTI)
- || TclInExit() || TclInThreadExit()) ? 0 : INFINITE;
+ timeout = blocking ? INFINITE : 0;
if (WaitForSingleObject(infoPtr->readable, timeout) == WAIT_TIMEOUT) {
/*
* The reader thread is blocked waiting for data and the channel
* is in non-blocking mode.
*/
- errno = EWOULDBLOCK;
+ errno = EAGAIN;
return -1;
}
@@ -2859,7 +2762,7 @@ WaitForRead(
if (PeekNamedPipe(handle, (LPVOID) NULL, (DWORD) 0,
(LPDWORD) NULL, &count, (LPDWORD) NULL) != TRUE) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
/*
* Check to see if the peek failed because of EOF.
@@ -2903,7 +2806,7 @@ WaitForRead(
*/
ResetEvent(infoPtr->readable);
- TclPipeThreadSignal(&infoPtr->readTI);
+ SetEvent(infoPtr->startReader);
}
}
@@ -2931,11 +2834,15 @@ static DWORD WINAPI
PipeReaderThread(
LPVOID arg)
{
- TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *) arg;
- PipeInfo *infoPtr = NULL; /* access info only after success init/wait */
- HANDLE handle = NULL;
+ PipeInfo *infoPtr = (PipeInfo *)arg;
+ HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle;
DWORD count, err;
int done = 0;
+ HANDLE wEvents[2];
+ DWORD waitResult;
+
+ wEvents[0] = infoPtr->stopReader;
+ wEvents[1] = infoPtr->startReader;
while (!done) {
/*
@@ -2943,14 +2850,15 @@ PipeReaderThread(
* pipe becoming readable.
*/
- if (!TclPipeThreadWaitForSignal(&pipeTI)) {
- /* exit */
- break;
- }
+ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
+
+ if (waitResult != (WAIT_OBJECT_0 + 1)) {
+ /*
+ * The start event was not signaled. It might be the stop event or
+ * an error, so exit.
+ */
- if (!infoPtr) {
- infoPtr = (PipeInfo *) pipeTI->clientData;
- handle = ((WinFile *) infoPtr->readFile)->handle;
+ break;
}
/*
@@ -2972,7 +2880,7 @@ PipeReaderThread(
infoPtr->readFlags |= PIPE_EOF;
done = 1;
} else if (err == ERROR_INVALID_HANDLE) {
- done = 1;
+ break;
}
} else if (count == 0) {
if (ReadFile(handle, &(infoPtr->extraByte), 1, &count, NULL)
@@ -2994,11 +2902,12 @@ PipeReaderThread(
infoPtr->readFlags |= PIPE_EOF;
done = 1;
} else if (err == ERROR_INVALID_HANDLE) {
- done = 1;
+ break;
}
}
}
+
/*
* Signal the main thread by signalling the readable event and then
* waking up the notifier thread.
@@ -3024,12 +2933,6 @@ PipeReaderThread(
Tcl_MutexUnlock(&pipeMutex);
}
- /*
- * If state of thread was set to stop, we can sane free info structure,
- * otherwise it is shared with main thread, so main thread will own it
- */
- TclPipeThreadExit(&pipeTI);
-
return 0;
}
@@ -3054,25 +2957,31 @@ static DWORD WINAPI
PipeWriterThread(
LPVOID arg)
{
- TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *)arg;
- PipeInfo *infoPtr = NULL; /* access info only after success init/wait */
- HANDLE handle = NULL;
+ PipeInfo *infoPtr = (PipeInfo *)arg;
+ HANDLE *handle = ((WinFile *) infoPtr->writeFile)->handle;
DWORD count, toWrite;
char *buf;
int done = 0;
+ HANDLE wEvents[2];
+ DWORD waitResult;
+
+ wEvents[0] = infoPtr->stopWriter;
+ wEvents[1] = infoPtr->startWriter;
while (!done) {
/*
* Wait for the main thread to signal before attempting to write.
*/
- if (!TclPipeThreadWaitForSignal(&pipeTI)) {
- /* exit */
- break;
- }
- if (!infoPtr) {
- infoPtr = (PipeInfo *)pipeTI->clientData;
- handle = ((WinFile *) infoPtr->writeFile)->handle;
+ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
+
+ if (waitResult != (WAIT_OBJECT_0 + 1)) {
+ /*
+ * The start event was not signaled. It might be the stop event or
+ * an error, so exit.
+ */
+
+ break;
}
buf = infoPtr->writeBuf;
@@ -3118,12 +3027,6 @@ PipeWriterThread(
Tcl_MutexUnlock(&pipeMutex);
}
- /*
- * If state of thread was set to stop, we can sane free info structure,
- * otherwise it is shared with main thread, so main thread will own it.
- */
- TclPipeThreadExit(&pipeTI);
-
return 0;
}
@@ -3145,7 +3048,7 @@ PipeWriterThread(
static void
PipeThreadActionProc(
- void *instanceData,
+ ClientData instanceData,
int action)
{
PipeInfo *infoPtr = (PipeInfo *) instanceData;
@@ -3153,7 +3056,7 @@ PipeThreadActionProc(
/*
* We do not access firstPipePtr in the thread structures. This is not for
* all pipes managed by the thread, but only those we are watching.
- * Removal of the fileevent handlers before transfer thus takes care of
+ * Removal of the filevent handlers before transfer thus takes care of
* this structure.
*/
@@ -3178,544 +3081,6 @@ PipeThreadActionProc(
}
/*
- *----------------------------------------------------------------------
- *
- * TclpOpenTemporaryFile --
- *
- * Creates a temporary file, possibly based on the supplied bits and
- * pieces of template supplied in the first three arguments. If the
- * fourth argument is non-NULL, it contains a Tcl_Obj to store the name
- * of the temporary file in (and it is caller's responsibility to clean
- * up). If the fourth argument is NULL, try to arrange for the temporary
- * file to go away once it is no longer needed.
- *
- * Results:
- * A read-write Tcl Channel open on the file.
- *
- *----------------------------------------------------------------------
- */
-
-Tcl_Channel
-TclpOpenTemporaryFile(
- TCL_UNUSED(Tcl_Obj *) /*dirObj*/,
- Tcl_Obj *basenameObj,
- TCL_UNUSED(Tcl_Obj *) /*extensionObj*/,
- Tcl_Obj *resultingNameObj)
-{
- WCHAR name[MAX_PATH];
- char *namePtr;
- HANDLE handle;
- DWORD flags = FILE_ATTRIBUTE_TEMPORARY;
- Tcl_Size length;
- int counter, counter2;
- Tcl_DString buf;
-
- if (!resultingNameObj) {
- flags |= FILE_FLAG_DELETE_ON_CLOSE;
- }
-
- namePtr = (char *) name;
- length = GetTempPathW(MAX_PATH, name);
- if (length == 0) {
- goto gotError;
- }
- namePtr += length * sizeof(WCHAR);
- if (basenameObj) {
- const char *string = TclGetStringFromObj(basenameObj, &length);
-
- Tcl_DStringInit(&buf);
- Tcl_UtfToWCharDString(string, length, &buf);
- memcpy(namePtr, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf));
- namePtr += Tcl_DStringLength(&buf);
- Tcl_DStringFree(&buf);
- } else {
- const WCHAR *baseStr = L"TCL";
- length = 3 * sizeof(WCHAR);
-
- memcpy(namePtr, baseStr, length);
- namePtr += length;
- }
- counter = TclpGetClicks() % 65533;
- counter2 = 1024; /* Only try this many times! Prevents
- * an infinite loop. */
-
- do {
- char number[TCL_INTEGER_SPACE + 4];
-
- snprintf(number, sizeof(number), "%d.TMP", counter);
- counter = (unsigned short) (counter + 1);
- Tcl_DStringInit(&buf);
- Tcl_UtfToWCharDString(number, strlen(number), &buf);
- Tcl_DStringSetLength(&buf, Tcl_DStringLength(&buf) + 1);
- memcpy(namePtr, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf) + 1);
- Tcl_DStringFree(&buf);
-
- handle = CreateFileW(name,
- GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, flags, NULL);
- } while (handle == INVALID_HANDLE_VALUE
- && --counter2 > 0
- && GetLastError() == ERROR_FILE_EXISTS);
- if (handle == INVALID_HANDLE_VALUE) {
- goto gotError;
- }
-
- if (resultingNameObj) {
- Tcl_Obj *tmpObj = TclpNativeToNormalized(name);
-
- Tcl_AppendObjToObj(resultingNameObj, tmpObj);
- TclDecrRefCount(tmpObj);
- }
-
- return Tcl_MakeFileChannel((void *) handle,
- TCL_READABLE|TCL_WRITABLE);
-
- gotError:
- Tcl_WinConvertError(GetLastError());
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclPipeThreadCreateTI --
- *
- * Creates a thread info structure, can be owned by worker.
- *
- * Results:
- * Pointer to created TI structure.
- *
- *----------------------------------------------------------------------
- */
-
-TclPipeThreadInfo *
-TclPipeThreadCreateTI(
- TclPipeThreadInfo **pipeTIPtr,
- void *clientData,
- HANDLE wakeEvent)
-{
- TclPipeThreadInfo *pipeTI;
-#ifndef _PTI_USE_CKALLOC
- pipeTI = (TclPipeThreadInfo *)malloc(sizeof(TclPipeThreadInfo));
-#else
- pipeTI = (TclPipeThreadInfo *)ckalloc(sizeof(TclPipeThreadInfo));
-#endif /* !_PTI_USE_CKALLOC */
- pipeTI->evControl = CreateEventW(NULL, FALSE, FALSE, NULL);
- pipeTI->state = PTI_STATE_IDLE;
- pipeTI->clientData = clientData;
- pipeTI->evWakeUp = wakeEvent;
- return (*pipeTIPtr = pipeTI);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclPipeThreadWaitForSignal --
- *
- * Wait for work/stop signals inside pipe worker.
- *
- * Results:
- * 1 if signaled to work, 0 if signaled to stop.
- *
- * Side effects:
- * If this function returns 0, TI-structure pointer given via pipeTIPtr
- * may be NULL, so not accessible (can be owned by main thread).
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclPipeThreadWaitForSignal(
- TclPipeThreadInfo **pipeTIPtr)
-{
- TclPipeThreadInfo *pipeTI = *pipeTIPtr;
- LONG state;
- DWORD waitResult;
- HANDLE wakeEvent;
-
- if (!pipeTI) {
- return 0;
- }
-
- wakeEvent = pipeTI->evWakeUp;
-
- /*
- * Wait for the main thread to signal before attempting to do the work.
- */
-
- /*
- * Reset work state of thread (idle/waiting)
- */
-
- state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_IDLE,
- PTI_STATE_WORK);
- if (state & (PTI_STATE_STOP|PTI_STATE_END)) {
- /*
- * End of work, check the owner of structure.
- */
-
- goto end;
- }
-
- /*
- * Entering wait
- */
-
- waitResult = WaitForSingleObject(pipeTI->evControl, INFINITE);
- if (waitResult != WAIT_OBJECT_0) {
- /*
- * The control event was not signaled, so end of work (unexpected
- * behaviour, main thread can be dead?).
- */
-
- goto end;
- }
-
- /*
- * Try to set work state of thread
- */
-
- state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_WORK,
- PTI_STATE_IDLE);
- if (state & (PTI_STATE_STOP|PTI_STATE_END)) {
- /*
- * End of work
- */
-
- goto end;
- }
-
- /*
- * Signaled to work.
- */
-
- return 1;
-
- end:
- /*
- * End of work, check the owner of the TI structure.
- */
-
- if (state != PTI_STATE_STOP) {
- *pipeTIPtr = NULL;
- } else {
- pipeTI->evWakeUp = NULL;
- }
- if (wakeEvent) {
- SetEvent(wakeEvent);
- }
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclPipeThreadStopSignal --
- *
- * Send stop signal to the pipe worker (without waiting).
- *
- * After calling of this function, TI-structure pointer given via pipeTIPtr
- * may be NULL.
- *
- * Results:
- * 1 if signaled (or pipe-thread is down), 0 if pipe thread still working.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclPipeThreadStopSignal(
- TclPipeThreadInfo **pipeTIPtr,
- HANDLE wakeEvent)
-{
- TclPipeThreadInfo *pipeTI = *pipeTIPtr;
- HANDLE evControl;
- int state;
-
- if (!pipeTI) {
- return 1;
- }
- evControl = pipeTI->evControl;
- pipeTI->evWakeUp = wakeEvent;
- state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_STOP,
- PTI_STATE_IDLE);
- switch (state) {
- case PTI_STATE_IDLE:
- /*
- * Thread was idle/waiting, notify it goes teardown
- */
-
- SetEvent(evControl);
- *pipeTIPtr = NULL;
- /* FALLTHRU */
- case PTI_STATE_DOWN:
- return 1;
-
- default:
- /*
- * Thread works currently, we should try to end it, own the TI
- * structure (because of possible sharing the joint structures with
- * thread)
- */
-
- InterlockedExchange(&pipeTI->state, PTI_STATE_END);
- break;
- }
-
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclPipeThreadStop --
- *
- * Send stop signal to the pipe worker and wait for thread completion.
- *
- * May be combined with TclPipeThreadStopSignal.
- *
- * After calling of this function, TI-structure pointer given via pipeTIPtr
- * is not accessible (owned by pipe worker or released here).
- *
- * Results:
- * None.
- *
- * Side effects:
- * Can terminate pipe worker (and / or stop its synchronous operations).
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclPipeThreadStop(
- TclPipeThreadInfo **pipeTIPtr,
- HANDLE hThread)
-{
- TclPipeThreadInfo *pipeTI = *pipeTIPtr;
- HANDLE evControl;
- int state;
-
- if (!pipeTI) {
- return;
- }
- pipeTI = *pipeTIPtr;
- evControl = pipeTI->evControl;
- pipeTI->evWakeUp = NULL;
-
- /*
- * Try to sane stop the pipe worker, corresponding its current state
- */
-
- state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_STOP,
- PTI_STATE_IDLE);
- switch (state) {
- case PTI_STATE_IDLE:
- /*
- * Thread was idle/waiting, notify it goes teardown
- */
-
- SetEvent(evControl);
-
- /*
- * We don't need to wait for it at all, thread frees himself (owns the
- * TI structure)
- */
-
- pipeTI = NULL;
- break;
-
- case PTI_STATE_STOP:
- /*
- * Already stopped, thread frees himself (owns the TI structure)
- */
-
- pipeTI = NULL;
- break;
- case PTI_STATE_DOWN:
- /*
- * Thread already down (?), do nothing
- */
-
- /*
- * We don't need to wait for it, but we should free pipeTI
- */
- hThread = NULL;
- break;
-
- /* case PTI_STATE_WORK: */
- default:
- /*
- * Thread works currently, we should try to end it, own the TI
- * structure (because of possible sharing the joint structures with
- * thread)
- */
-
- state = InterlockedCompareExchange(&pipeTI->state, PTI_STATE_END,
- PTI_STATE_WORK);
- if (state == PTI_STATE_DOWN) {
- /*
- * We don't need to wait for it, but we should free pipeTI
- */
- hThread = NULL;
- }
- break;
- }
-
- if (pipeTI && hThread) {
- DWORD exitCode;
-
- /*
- * The thread may already have closed on its own. Check its exit
- * code.
- */
-
- GetExitCodeThread(hThread, &exitCode);
-
- if (exitCode == STILL_ACTIVE) {
- int inExit = (TclInExit() || TclInThreadExit());
-
- /*
- * Set the stop event so that if the pipe thread is blocked
- * somewhere, it may hereafter sane exit cleanly.
- */
-
- SetEvent(evControl);
-
- /*
- * Cancel all sync-IO of this thread (may be blocked there).
- */
-
- CancelSynchronousIo(hThread);
-
- /*
- * Wait at most 20 milliseconds for the reader thread to close
- * (regarding TIP#398-fast-exit).
- */
-
- /*
- * If we want TIP#398-fast-exit.
- */
-
- if (WaitForSingleObject(hThread, inExit ? 0 : 20) == WAIT_TIMEOUT) {
- /*
- * The thread must be blocked waiting for the pipe to become
- * readable in ReadFile(). There isn't a clean way to exit the
- * thread from this condition. We should terminate the child
- * process instead to get the reader thread to fall out of
- * ReadFile with a FALSE. (below) is not the correct way to do
- * this, but will stay here until a better solution is found.
- *
- * Note that we need to guard against terminating the thread
- * while it is in the middle of Tcl_ThreadAlert because it
- * won't be able to release the notifier lock.
- *
- * Also note that terminating threads during their
- * initialization or teardown phase may result in ntdll.dll's
- * LoaderLock to remain locked indefinitely. This causes
- * ntdll.dll's LdrpInitializeThread() to deadlock trying to
- * acquire LoaderLock. LdrpInitializeThread() is executed
- * within new threads to perform initialization and to execute
- * DllMain() of all loaded dlls. As a result, all new threads
- * are deadlocked in their initialization phase and never
- * execute, even though CreateThread() reports successful
- * thread creation. This results in a very weird process-wide
- * behavior, which is extremely hard to debug.
- *
- * THREADS SHOULD NEVER BE TERMINATED. Period.
- *
- * But for now, check if thread is exiting, and if so, let it
- * die peacefully.
- *
- * Also don't terminate if in exit (otherwise deadlocked in
- * ntdll.dll's).
- */
-
- if (pipeTI->state != PTI_STATE_DOWN
- && WaitForSingleObject(hThread,
- inExit ? 50 : 5000) != WAIT_OBJECT_0) {
- /* BUG: this leaks memory */
- if (inExit || !TerminateThread(hThread, 0)) {
- /*
- * in exit or terminate fails, just give thread a
- * chance to exit
- */
-
- if (InterlockedExchange(&pipeTI->state,
- PTI_STATE_STOP) != PTI_STATE_DOWN) {
- pipeTI = NULL;
- }
- }
- }
- }
- }
- }
-
- *pipeTIPtr = NULL;
- if (pipeTI) {
- if (pipeTI->evWakeUp) {
- SetEvent(pipeTI->evWakeUp);
- }
- CloseHandle(pipeTI->evControl);
-#ifndef _PTI_USE_CKALLOC
- free(pipeTI);
-#else
- ckfree(pipeTI);
-#endif /* !_PTI_USE_CKALLOC */
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclPipeThreadExit --
- *
- * Clean-up for the pipe thread (removes owned TI-structure in worker).
- *
- * Should be executed on worker exit, to inform the main thread or
- * free TI-structure (if owned).
- *
- * After calling of this function, TI-structure pointer given via pipeTIPtr
- * is not accessible (owned by main thread or released here).
- *
- * Results:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TclPipeThreadExit(
- TclPipeThreadInfo **pipeTIPtr)
-{
- LONG state;
- TclPipeThreadInfo *pipeTI = *pipeTIPtr;
-
- /*
- * If state of thread was set to stop (exactly), we can sane free its info
- * structure, otherwise it is shared with main thread, so main thread will
- * own it.
- */
-
- if (!pipeTI) {
- return;
- }
- *pipeTIPtr = NULL;
- state = InterlockedExchange(&pipeTI->state, PTI_STATE_DOWN);
- if (state == PTI_STATE_STOP) {
- CloseHandle(pipeTI->evControl);
- if (pipeTI->evWakeUp) {
- SetEvent(pipeTI->evWakeUp);
- }
-#ifndef _PTI_USE_CKALLOC
- free(pipeTI);
-#else
- ckfree(pipeTI);
- /* be sure all subsystems used are finalized */
- Tcl_FinalizeThread();
-#endif /* !_PTI_USE_CKALLOC */
- }
-}
-
-/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff --git a/win/tclWinPort.h b/win/tclWinPort.h
index 9eb949b..b2bf1d7 100644
--- a/win/tclWinPort.h
+++ b/win/tclWinPort.h
@@ -14,26 +14,9 @@
#ifndef _TCLWINPORT
#define _TCLWINPORT
-#if !defined(_WIN64) && !defined(__MINGW_USE_VC2005_COMPAT)
+#ifndef _WIN64
/* See [Bug 3354324]: file mtime sets wrong time */
-# define __MINGW_USE_VC2005_COMPAT
-#endif
-#if defined(_MSC_VER) && defined(_WIN64) && !defined(STATIC_BUILD) \
- && !defined(MP_32BIT) && !defined(MP_64BIT)
-# define MP_64BIT
-#endif
-
-/*
- * We must specify the lower version we intend to support.
- *
- * WINVER = 0x0601 means Windows 7 and above
- */
-
-#ifndef WINVER
-# define WINVER 0x0601
-#endif
-#ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0601
+# define _USE_32BIT_TIME_T
#endif
#define WIN32_LEAN_AND_MEAN
@@ -49,28 +32,17 @@ typedef DWORD_PTR * PDWORD_PTR;
/*
* Ask for the winsock function typedefs, also.
*/
-#ifndef INCL_WINSOCK_API_TYPEDEFS
-# define INCL_WINSOCK_API_TYPEDEFS 1
-#endif
+#define INCL_WINSOCK_API_TYPEDEFS 1
#include <winsock2.h>
-#include <ws2tcpip.h>
-#ifdef HAVE_WSPIAPI_H
-# include <wspiapi.h>
-#endif
-/*
- * Pull in the typedef of TCHAR for windows.
- */
-#include <tchar.h>
-#ifndef _TCHAR_DEFINED
- /* Borland seems to forget to set this. */
- typedef _TCHAR TCHAR;
+#ifdef CHECK_UNICODE_CALLS
+# define _UNICODE
+# define UNICODE
+# define __TCHAR_DEFINED
+ typedef float *_TCHAR;
# define _TCHAR_DEFINED
-#endif
-#if defined(_MSC_VER) && defined(__STDC__)
- /* VS2005 SP1 misses this. See [Bug #3110161] */
- typedef _TCHAR TCHAR;
-#endif
+ typedef float *TCHAR;
+#endif /* CHECK_UNICODE_CALLS */
/*
*---------------------------------------------------------------------------
@@ -80,18 +52,18 @@ typedef DWORD_PTR * PDWORD_PTR;
*/
#include <time.h>
-#include <wchar.h>
#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <float.h>
#include <malloc.h>
#include <process.h>
#include <signal.h>
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
+#include <string.h>
#include <limits.h>
+
#ifndef __GNUC__
# define strncasecmp _strnicmp
# define strcasecmp _stricmp
@@ -105,170 +77,116 @@ typedef DWORD_PTR * PDWORD_PTR;
#ifndef __MWERKS__
#include <sys/stat.h>
#include <sys/timeb.h>
-#include <sys/utime.h>
+# ifdef __BORLANDC__
+# include <utime.h>
+# else
+# include <sys/utime.h>
+# endif /* __BORLANDC__ */
#endif /* __MWERKS__ */
/*
+ * Define EINPROGRESS in terms of WSAEINPROGRESS.
+ */
+
+#undef EINPROGRESS
+#define EINPROGRESS WSAEINPROGRESS
+
+/*
+ * Define ENOTSUP to a value that will never occur.
+ */
+
+#undef ENOTSUP
+#define ENOTSUP -1030507
+
+/* Those codes, from Visual Studio 2010, conflict with other values */
+#undef ENODATA
+#undef ENOMSG
+#undef ENOSR
+#undef ENOSTR
+#undef EPROTO
+
+/*
* The following defines redefine the Windows Socket errors as
* BSD errors so Tcl_PosixError can do the right thing.
*/
-#ifndef ENOTEMPTY
-# define ENOTEMPTY 41 /* Directory not empty */
-#endif
-#ifndef EREMOTE
-# define EREMOTE 66 /* The object is remote */
-#endif
-#ifndef EPFNOSUPPORT
-# define EPFNOSUPPORT 96 /* Protocol family not supported */
-#endif
-#ifndef EADDRINUSE
-# define EADDRINUSE 100 /* Address already in use */
-#endif
-#ifndef EADDRNOTAVAIL
-# define EADDRNOTAVAIL 101 /* Can't assign requested address */
-#endif
-#ifndef EAFNOSUPPORT
-# define EAFNOSUPPORT 102 /* Address family not supported */
-#endif
-#ifndef EALREADY
-# define EALREADY 103 /* Operation already in progress */
-#endif
-#ifndef EBADMSG
-# define EBADMSG 104 /* Not a data message */
-#endif
-#ifndef ECANCELED
-# define ECANCELED 105 /* Canceled */
-#endif
-#ifndef ECONNABORTED
-# define ECONNABORTED 106 /* Software caused connection abort */
-#endif
-#ifndef ECONNREFUSED
-# define ECONNREFUSED 107 /* Connection refused */
-#endif
-#ifndef ECONNRESET
-# define ECONNRESET 108 /* Connection reset by peer */
-#endif
-#ifndef EDESTADDRREQ
-# define EDESTADDRREQ 109 /* Destination address required */
-#endif
-#ifndef EHOSTUNREACH
-# define EHOSTUNREACH 110 /* No route to host */
-#endif
-#ifndef EIDRM
-# define EIDRM 111 /* Identifier removed */
-#endif
-#ifndef EINPROGRESS
-# define EINPROGRESS 112 /* Operation now in progress */
-#endif
-#ifndef EISCONN
-# define EISCONN 113 /* Socket is already connected */
-#endif
-#ifndef ELOOP
-# define ELOOP 114 /* Symbolic link loop */
-#endif
-#ifndef EMSGSIZE
-# define EMSGSIZE 115 /* Message too long */
-#endif
-#ifndef ENETDOWN
-# define ENETDOWN 116 /* Network is down */
-#endif
-#ifndef ENETRESET
-# define ENETRESET 117 /* Network dropped connection on reset */
-#endif
-#ifndef ENETUNREACH
-# define ENETUNREACH 118 /* Network is unreachable */
-#endif
-#ifndef ENOBUFS
-# define ENOBUFS 119 /* No buffer space available */
-#endif
-#ifndef ENODATA
-# define ENODATA 120 /* No data available */
-#endif
-#ifndef ENOLINK
-# define ENOLINK 121 /* Link has be severed */
-#endif
-#ifndef ENOMSG
-# define ENOMSG 122 /* No message of desired type */
-#endif
-#ifndef ENOPROTOOPT
-# define ENOPROTOOPT 123 /* Protocol not available */
-#endif
-#ifndef ENOSR
-# define ENOSR 124 /* Out of stream resources */
-#endif
-#ifndef ENOSTR
-# define ENOSTR 125 /* Not a stream device */
-#endif
-#ifndef ENOTCONN
-# define ENOTCONN 126 /* Socket is not connected */
-#endif
-#ifndef ENOTRECOVERABLE
-# define ENOTRECOVERABLE 127 /* Not recoverable */
-#endif
-#ifndef ENOTSOCK
-# define ENOTSOCK 128 /* Socket operation on non-socket */
-#endif
-#ifndef ENOTSUP
-# define ENOTSUP 129 /* Operation not supported */
-#endif
-#ifndef EOPNOTSUPP
-# define EOPNOTSUPP 130 /* Operation not supported on socket */
-#endif
-#ifndef EOTHER
-# define EOTHER 131 /* Other error */
-#endif
-#ifndef EOVERFLOW
-# define EOVERFLOW 132 /* File too big */
-#endif
-#ifndef EOWNERDEAD
-# define EOWNERDEAD 133 /* Owner dead */
-#endif
-#ifndef EPROTO
-# define EPROTO 134 /* Protocol error */
-#endif
-#ifndef EPROTONOSUPPORT
-# define EPROTONOSUPPORT 135 /* Protocol not supported */
-#endif
-#ifndef EPROTOTYPE
-# define EPROTOTYPE 136 /* Protocol wrong type for socket */
-#endif
-#ifndef ETIME
-# define ETIME 137 /* Timer expired */
-#endif
-#ifndef ETIMEDOUT
-# define ETIMEDOUT 138 /* Connection timed out */
-#endif
-#ifndef ETXTBSY
-# define ETXTBSY 139 /* Text file or pseudo-device busy */
-#endif
-#ifndef EWOULDBLOCK
-# define EWOULDBLOCK 140 /* Operation would block */
-#endif
+#undef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#undef EALREADY
+#define EALREADY 149 /* operation already in progress */
+#undef ENOTSOCK
+#define ENOTSOCK 95 /* Socket operation on non-socket */
+#undef EDESTADDRREQ
+#define EDESTADDRREQ 96 /* Destination address required */
+#undef EMSGSIZE
+#define EMSGSIZE 97 /* Message too long */
+#undef EPROTOTYPE
+#define EPROTOTYPE 98 /* Protocol wrong type for socket */
+#undef ENOPROTOOPT
+#define ENOPROTOOPT 99 /* Protocol not available */
+#undef EPROTONOSUPPORT
+#define EPROTONOSUPPORT 120 /* Protocol not supported */
+#undef ESOCKTNOSUPPORT
+#define ESOCKTNOSUPPORT 121 /* Socket type not supported */
+#undef EOPNOTSUPP
+#define EOPNOTSUPP 122 /* Operation not supported on socket */
+#undef EPFNOSUPPORT
+#define EPFNOSUPPORT 123 /* Protocol family not supported */
+#undef EAFNOSUPPORT
+#define EAFNOSUPPORT 124 /* Address family not supported */
+#undef EADDRINUSE
+#define EADDRINUSE 125 /* Address already in use */
+#undef EADDRNOTAVAIL
+#define EADDRNOTAVAIL 126 /* Can't assign requested address */
+#undef ENETDOWN
+#define ENETDOWN 127 /* Network is down */
+#undef ENETUNREACH
+#define ENETUNREACH 128 /* Network is unreachable */
+#undef ENETRESET
+#define ENETRESET 129 /* Network dropped connection on reset */
+#undef ECONNABORTED
+#define ECONNABORTED 130 /* Software caused connection abort */
+#undef ECONNRESET
+#define ECONNRESET 131 /* Connection reset by peer */
+#undef ENOBUFS
+#define ENOBUFS 132 /* No buffer space available */
+#undef EISCONN
+#define EISCONN 133 /* Socket is already connected */
+#undef ENOTCONN
+#define ENOTCONN 134 /* Socket is not connected */
+#undef ESHUTDOWN
+#define ESHUTDOWN 143 /* Can't send after socket shutdown */
+#undef ETOOMANYREFS
+#define ETOOMANYREFS 144 /* Too many references: can't splice */
+#undef ETIMEDOUT
+#define ETIMEDOUT 145 /* Connection timed out */
+#undef ECONNREFUSED
+#define ECONNREFUSED 146 /* Connection refused */
+#undef ELOOP
+#define ELOOP 90 /* Symbolic link loop */
+#undef EHOSTDOWN
+#define EHOSTDOWN 147 /* Host is down */
+#undef EHOSTUNREACH
+#define EHOSTUNREACH 148 /* No route to host */
+#undef ENOTEMPTY
+#define ENOTEMPTY 93 /* directory not empty */
+#undef EUSERS
+#define EUSERS 94 /* Too many users (for UFS) */
+#undef EDQUOT
+#define EDQUOT 69 /* Disc quota exceeded */
+#undef ESTALE
+#define ESTALE 151 /* Stale NFS file handle */
+#undef EREMOTE
+#define EREMOTE 66 /* The object is remote */
+/*
+ * It is very hard to determine how Windows reacts to attempting to
+ * set a file pointer outside the input datatype's representable
+ * region. So we fake the error code ourselves.
+ */
-/* Visual Studio doesn't have these, so just choose some high numbers */
-#ifndef ESOCKTNOSUPPORT
-# define ESOCKTNOSUPPORT 240 /* Socket type not supported */
-#endif
-#ifndef ESHUTDOWN
-# define ESHUTDOWN 241 /* Can't send after socket shutdown */
-#endif
-#ifndef ETOOMANYREFS
-# define ETOOMANYREFS 242 /* Too many references: can't splice */
-#endif
-#ifndef EHOSTDOWN
-# define EHOSTDOWN 243 /* Host is down */
-#endif
-#ifndef EUSERS
-# define EUSERS 244 /* Too many users (for UFS) */
-#endif
-#ifndef EDQUOT
-# define EDQUOT 245 /* Disc quota exceeded */
-#endif
-#ifndef ESTALE
-# define ESTALE 246 /* Stale NFS file handle */
-#endif
+#undef EOVERFLOW
+#define EOVERFLOW EFBIG /* The object couldn't fit in the datatype */
/*
* Signals not known to the standard ANSI signal.h. These are used
@@ -287,7 +205,7 @@ typedef DWORD_PTR * PDWORD_PTR;
* defined in header files above.
*/
-#ifdef TCL_UNION_WAIT
+#if TCL_UNION_WAIT
# define WAIT_STATUS_TYPE union wait
#else
# define WAIT_STATUS_TYPE int
@@ -306,7 +224,7 @@ typedef DWORD_PTR * PDWORD_PTR;
#endif
#ifndef WTERMSIG
-# define WTERMSIG(stat) ((*((int *) &(stat))) & 0x7F)
+# define WTERMSIG(stat) ((*((int *) &(stat))) & 0x7f)
#endif
#ifndef WIFSTOPPED
@@ -314,7 +232,7 @@ typedef DWORD_PTR * PDWORD_PTR;
#endif
#ifndef WSTOPSIG
-# define WSTOPSIG(stat) (((*((int *) &(stat))) >> 8) & 0xFF)
+# define WSTOPSIG(stat) (((*((int *) &(stat))) >> 8) & 0xff)
#endif
/*
@@ -355,20 +273,6 @@ typedef DWORD_PTR * PDWORD_PTR;
# define S_IFLNK 0120000 /* Symbolic Link */
#endif
-/*
- * Windows compilers do not define S_IFBLK. However, Tcl uses it in
- * GetTypeFromMode to identify blockSpecial devices based on the
- * value in the statsbuf st_mode field. We have no other way to pass this
- * from NativeStat on Windows so are forced to define it here.
- * The definition here is essentially what is seen on Linux and MingW.
- * XXX - the root problem is Tcl using Unix definitions instead of
- * abstracting the structure into a platform independent one. Sigh - perhaps
- * Tcl 9
- */
-#ifndef S_IFBLK
-# define S_IFBLK (S_IFDIR | S_IFCHR)
-#endif
-
#ifndef S_ISREG
# ifdef S_IFREG
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
@@ -429,10 +333,10 @@ typedef DWORD_PTR * PDWORD_PTR;
* Define pid_t and uid_t if they're not already defined.
*/
-#if !defined(TCL_PID_T)
+#if ! TCL_PID_T
# define pid_t int
#endif /* !TCL_PID_T */
-#if !defined(TCL_UID_T)
+#if ! TCL_UID_T
# define uid_t int
#endif /* !TCL_UID_T */
@@ -444,24 +348,50 @@ typedef DWORD_PTR * PDWORD_PTR;
#if defined(_MSC_VER) || defined(__MSVCRT__)
# define environ _environ
+# if defined(_MSC_VER) && (_MSC_VER < 1600)
+# define hypot _hypot
+# endif
# define exception _exception
# undef EDEADLOCK
-# if defined(_MSC_VER)
+# if defined(_MSC_VER) && (_MSC_VER >= 1700)
# define timezone _timezone
# endif
#endif /* _MSC_VER || __MSVCRT__ */
-#if defined(_MSC_VER)
-# pragma warning(disable:4090) /* see: https://developercommunity.visualstudio.com/t/c-compiler-incorrect-propagation-of-const-qualifie/390711 */
-# pragma warning(disable:4146)
-# pragma warning(disable:4244)
-#if !defined(_WIN64)
-# pragma warning(disable:4305)
+/*
+ * Borland's timezone and environ functions.
+ */
+
+#ifdef __BORLANDC__
+# define timezone _timezone
+# define environ _environ
+#endif /* __BORLANDC__ */
+
+#ifdef __WATCOMC__
+# if !defined(__CHAR_SIGNED__)
+# error "You must use the -j switch to ensure char is signed."
+# endif
#endif
+
+
+/*
+ * MSVC 8.0 started to mark many standard C library functions depreciated
+ * including the *printf family and others. Tell it to shut up.
+ * (_MSC_VER is 1200 for VC6, 1300 or 1310 for vc7.net, 1400 for 8.0)
+ */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+# pragma warning(disable:4244)
# pragma warning(disable:4267)
# pragma warning(disable:4996)
#endif
+
+/*
+ * There is no platform-specific panic routine for Windows in the Tcl internals.
+ */
+
+#define TclpPanic ((Tcl_PanicProc *) NULL)
+
/*
*---------------------------------------------------------------------------
* The following macros and declarations represent the interface between
@@ -527,7 +457,7 @@ typedef DWORD_PTR * PDWORD_PTR;
* address platform-specific issues.
*/
-#define TclpReleaseFile(file) ckfree(file)
+#define TclpReleaseFile(file) ckfree((char *) file)
/*
* The following macros and declarations wrap the C runtime library
@@ -544,7 +474,4 @@ typedef DWORD_PTR * PDWORD_PTR;
# define LABEL_SECURITY_INFORMATION (0x00000010L)
#endif
-#define Tcl_DirEntry void
-#define TclDIR void
-
#endif /* _TCLWINPORT */
diff --git a/win/tclWinReg.c b/win/tclWinReg.c
index a0b4e90..a6ce2ce 100644
--- a/win/tclWinReg.c
+++ b/win/tclWinReg.c
@@ -12,41 +12,36 @@
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#undef STATIC_BUILD
-#ifndef USE_TCL_STUBS
-# define USE_TCL_STUBS
-#endif
#include "tclInt.h"
+#include "tclPort.h"
#ifdef _MSC_VER
# pragma comment (lib, "advapi32.lib")
#endif
#include <stdlib.h>
/*
- * Ensure that we can say which registry is being accessed.
+ * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the
+ * Registry_Init declaration is in the source file itself, which is only
+ * accessed when we are building a library.
*/
-#ifndef KEY_WOW64_64KEY
-# define KEY_WOW64_64KEY (0x0100)
-#endif
-#ifndef KEY_WOW64_32KEY
-# define KEY_WOW64_32KEY (0x0200)
-#endif
+#undef TCL_STORAGE_CLASS
+#define TCL_STORAGE_CLASS DLLEXPORT
/*
* The maximum length of a sub-key name.
*/
#ifndef MAX_KEY_LENGTH
-# define MAX_KEY_LENGTH 256
+#define MAX_KEY_LENGTH 256
#endif
/*
* The following macros convert between different endian ints.
*/
-#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
-#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
+#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
+#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
/*
* The following flag is used in OpenKeys to indicate that the specified key
@@ -60,7 +55,7 @@
* system predefined keys.
*/
-static const char *const rootKeyNames[] = {
+static CONST char *rootKeyNames[] = {
"HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT",
"HKEY_CURRENT_USER", "HKEY_CURRENT_CONFIG",
"HKEY_PERFORMANCE_DATA", "HKEY_DYN_DATA", NULL
@@ -71,7 +66,7 @@ static const HKEY rootKeys[] = {
HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, HKEY_DYN_DATA
};
-static const char REGISTRY_ASSOC_KEY[] = "registry::command";
+static CONST char REGISTRY_ASSOC_KEY[] = "registry::command";
/*
* The following table maps from registry types to strings. Note that the
@@ -79,50 +74,108 @@ static const char REGISTRY_ASSOC_KEY[] = "registry::command";
* types so we don't need a separate table to hold the mapping.
*/
-static const char *const typeNames[] = {
+static CONST char *typeNames[] = {
"none", "sz", "expand_sz", "binary", "dword",
"dword_big_endian", "link", "multi_sz", "resource_list", NULL
};
static DWORD lastType = REG_RESOURCE_LIST;
-#if (TCL_MAJOR_VERSION < 9) && defined(TCL_MINOR_VERSION) && (TCL_MINOR_VERSION < 7)
-# if TCL_UTF_MAX > 3
-# define Tcl_WCharToUtfDString(a,b,c) Tcl_WinTCharToUtf((TCHAR *)(a),(b)*sizeof(WCHAR),c)
-# define Tcl_UtfToWCharDString(a,b,c) (WCHAR *)Tcl_WinUtfToTChar(a,b,c)
-# else
-# define Tcl_WCharToUtfDString Tcl_UniCharToUtfDString
-# define Tcl_UtfToWCharDString Tcl_UtfToUniCharDString
-# endif
-#ifndef Tcl_Size
-# define Tcl_Size int
-#endif
-#ifndef Tcl_CreateObjCommand2
-# define Tcl_CreateObjCommand2 Tcl_CreateObjCommand
-#endif
-#endif
+/*
+ * The following structures allow us to select between the Unicode and ASCII
+ * interfaces at run time based on whether Unicode APIs are available. The
+ * Unicode APIs are preferable because they will handle characters outside of
+ * the current code page.
+ */
+
+typedef struct RegWinProcs {
+ int useWide;
+
+ LONG (WINAPI *regConnectRegistryProc)(CONST TCHAR *, HKEY, PHKEY);
+ LONG (WINAPI *regCreateKeyExProc)(HKEY, CONST TCHAR *, DWORD, TCHAR *,
+ DWORD, REGSAM, SECURITY_ATTRIBUTES *, HKEY *, DWORD *);
+ LONG (WINAPI *regDeleteKeyProc)(HKEY, CONST TCHAR *);
+ LONG (WINAPI *regDeleteValueProc)(HKEY, CONST TCHAR *);
+ LONG (WINAPI *regEnumKeyProc)(HKEY, DWORD, TCHAR *, DWORD);
+ LONG (WINAPI *regEnumKeyExProc)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
+ TCHAR *, DWORD *, FILETIME *);
+ LONG (WINAPI *regEnumValueProc)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
+ DWORD *, BYTE *, DWORD *);
+ LONG (WINAPI *regOpenKeyExProc)(HKEY, CONST TCHAR *, DWORD, REGSAM,
+ HKEY *);
+ LONG (WINAPI *regQueryValueExProc)(HKEY, CONST TCHAR *, DWORD *, DWORD *,
+ BYTE *, DWORD *);
+ LONG (WINAPI *regSetValueExProc)(HKEY, CONST TCHAR *, DWORD, DWORD,
+ CONST BYTE*, DWORD);
+} RegWinProcs;
+
+static RegWinProcs *regWinProcs;
+
+static RegWinProcs asciiProcs = {
+ 0,
+
+ (LONG (WINAPI *)(CONST TCHAR *, HKEY, PHKEY)) RegConnectRegistryA,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, TCHAR *,
+ DWORD, REGSAM, SECURITY_ATTRIBUTES *, HKEY *,
+ DWORD *)) RegCreateKeyExA,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *)) RegDeleteKeyA,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *)) RegDeleteValueA,
+ (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD)) RegEnumKeyA,
+ (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
+ TCHAR *, DWORD *, FILETIME *)) RegEnumKeyExA,
+ (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
+ DWORD *, BYTE *, DWORD *)) RegEnumValueA,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, REGSAM,
+ HKEY *)) RegOpenKeyExA,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD *, DWORD *,
+ BYTE *, DWORD *)) RegQueryValueExA,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, DWORD,
+ CONST BYTE*, DWORD)) RegSetValueExA,
+};
+
+static RegWinProcs unicodeProcs = {
+ 1,
+
+ (LONG (WINAPI *)(CONST TCHAR *, HKEY, PHKEY)) RegConnectRegistryW,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, TCHAR *,
+ DWORD, REGSAM, SECURITY_ATTRIBUTES *, HKEY *,
+ DWORD *)) RegCreateKeyExW,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *)) RegDeleteKeyW,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *)) RegDeleteValueW,
+ (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD)) RegEnumKeyW,
+ (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
+ TCHAR *, DWORD *, FILETIME *)) RegEnumKeyExW,
+ (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
+ DWORD *, BYTE *, DWORD *)) RegEnumValueW,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, REGSAM,
+ HKEY *)) RegOpenKeyExW,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD *, DWORD *,
+ BYTE *, DWORD *)) RegQueryValueExW,
+ (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, DWORD,
+ CONST BYTE*, DWORD)) RegSetValueExW,
+};
+
/*
* Declarations for functions defined in this file.
*/
static void AppendSystemError(Tcl_Interp *interp, DWORD error);
-static int BroadcastValue(Tcl_Interp *interp, Tcl_Size objc,
- Tcl_Obj *const objv[]);
+static int BroadcastValue(Tcl_Interp *interp, int objc,
+ Tcl_Obj * CONST objv[]);
static DWORD ConvertDWORD(DWORD type, DWORD value);
-static void DeleteCmd(void *clientData);
-static int DeleteKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
- REGSAM mode);
+static void DeleteCmd(ClientData clientData);
+static int DeleteKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj);
static int DeleteValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
- Tcl_Obj *valueNameObj, REGSAM mode);
+ Tcl_Obj *valueNameObj);
static int GetKeyNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
- Tcl_Obj *patternObj, REGSAM mode);
+ Tcl_Obj *patternObj);
static int GetType(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
- Tcl_Obj *valueNameObj, REGSAM mode);
+ Tcl_Obj *valueNameObj);
static int GetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
- Tcl_Obj *valueNameObj, REGSAM mode);
+ Tcl_Obj *valueNameObj);
static int GetValueNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
- Tcl_Obj *patternObj, REGSAM mode);
+ Tcl_Obj *patternObj);
static int OpenKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
REGSAM mode, int flags, HKEY *keyPtr);
static DWORD OpenSubKey(char *hostName, HKEY rootKey,
@@ -132,27 +185,16 @@ static int ParseKeyName(Tcl_Interp *interp, char *name,
char **hostNamePtr, HKEY *rootKeyPtr,
char **keyNamePtr);
static DWORD RecursiveDeleteKey(HKEY hStartKey,
- const WCHAR * pKeyName, REGSAM mode);
-static int RegistryObjCmd(void *clientData,
- Tcl_Interp *interp, Tcl_Size objc,
- Tcl_Obj *const objv[]);
+ CONST TCHAR * pKeyName);
+static int RegistryObjCmd(ClientData clientData,
+ Tcl_Interp *interp, int objc,
+ Tcl_Obj * CONST objv[]);
static int SetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
Tcl_Obj *valueNameObj, Tcl_Obj *dataObj,
- Tcl_Obj *typeObj, REGSAM mode);
+ Tcl_Obj *typeObj);
-#ifdef __cplusplus
-extern "C" {
-#endif
-DLLEXPORT int Registry_Init(Tcl_Interp *interp);
-DLLEXPORT int Registry_Unload(Tcl_Interp *interp, int flags);
-#if TCL_MAJOR_VERSION < 9
-/* With those additional entries, "load tclregistry13.dll" works without 3th argument */
-DLLEXPORT int Tclregistry_Init(Tcl_Interp *interp);
-DLLEXPORT int Tclregistry_Unload(Tcl_Interp *interp, int flags);
-#endif
-#ifdef __cplusplus
-}
-#endif
+EXTERN int Registry_Init(Tcl_Interp *interp);
+EXTERN int Registry_Unload(Tcl_Interp *interp, int flags);
/*
*----------------------------------------------------------------------
@@ -176,23 +218,26 @@ Registry_Init(
{
Tcl_Command cmd;
- if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
+ if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
return TCL_ERROR;
}
- cmd = Tcl_CreateObjCommand2(interp, "registry", RegistryObjCmd,
- interp, DeleteCmd);
- Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, cmd);
- return Tcl_PkgProvideEx(interp, "registry", "1.3.7", NULL);
-}
-#if TCL_MAJOR_VERSION < 9
-int
-Tclregistry_Init(
- Tcl_Interp *interp)
-{
- return Registry_Init(interp);
+ /*
+ * Determine if the unicode interfaces are available and select the
+ * appropriate registry function table.
+ */
+
+ if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
+ regWinProcs = &unicodeProcs;
+ } else {
+ regWinProcs = &asciiProcs;
+ }
+
+ cmd = Tcl_CreateObjCommand(interp, "registry", RegistryObjCmd,
+ (ClientData)interp, DeleteCmd);
+ Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, (ClientData)cmd);
+ return Tcl_PkgProvide(interp, "registry", "1.2.2");
}
-#endif
/*
*----------------------------------------------------------------------
@@ -217,7 +262,6 @@ Registry_Unload(
{
Tcl_Command cmd;
Tcl_Obj *objv[3];
- (void)flags;
/*
* Unregister the registry package. There is no Tcl_PkgForget()
@@ -239,15 +283,6 @@ Registry_Unload(
return TCL_OK;
}
-#if TCL_MAJOR_VERSION < 9
-int
-Tclregistry_Unload(
- Tcl_Interp *interp,
- int flags)
-{
- return Registry_Unload(interp, flags);
-}
-#endif
/*
*----------------------------------------------------------------------
@@ -268,11 +303,10 @@ Tclregistry_Unload(
static void
DeleteCmd(
- void *clientData)
+ ClientData clientData)
{
- Tcl_Interp *interp = (Tcl_Interp *)clientData;
-
- Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, NULL);
+ Tcl_Interp *interp = clientData;
+ Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, (ClientData)NULL);
}
/*
@@ -293,129 +327,92 @@ DeleteCmd(
static int
RegistryObjCmd(
- void *dummy, /* Not used. */
+ ClientData clientData, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
- Tcl_Size objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument values. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj * CONST objv[]) /* Argument values. */
{
- Tcl_Size n = 1, argc;
int index;
- REGSAM mode = 0;
- const char *errString = NULL;
+ char *errString = NULL;
- static const char *const subcommands[] = {
+ static CONST char *subcommands[] = {
"broadcast", "delete", "get", "keys", "set", "type", "values", NULL
};
enum SubCmdIdx {
BroadcastIdx, DeleteIdx, GetIdx, KeysIdx, SetIdx, TypeIdx, ValuesIdx
};
- static const char *const modes[] = {
- "-32bit", "-64bit", NULL
- };
- (void)dummy;
if (objc < 2) {
- wrongArgs:
- Tcl_WrongNumArgs(interp, 1, objv, "?-32bit|-64bit? option ?arg ...?");
+ Tcl_WrongNumArgs(interp, objc, objv, "option ?arg arg ...?");
return TCL_ERROR;
}
- if (Tcl_GetString(objv[n])[0] == '-') {
- if (Tcl_GetIndexFromObj(interp, objv[n++], modes, "mode", 0,
- &index) != TCL_OK) {
- return TCL_ERROR;
- }
- switch (index) {
- case 0: /* -32bit */
- mode |= KEY_WOW64_32KEY;
- break;
- case 1: /* -64bit */
- mode |= KEY_WOW64_64KEY;
- break;
- }
- if (objc < 3) {
- goto wrongArgs;
- }
- }
-
- if (Tcl_GetIndexFromObj(interp, objv[n++], subcommands, "option", 0,
- &index) != TCL_OK) {
+ if (Tcl_GetIndexFromObj(interp, objv[1], subcommands, "option", 0, &index)
+ != TCL_OK) {
return TCL_ERROR;
}
- argc = (objc - n);
switch (index) {
case BroadcastIdx: /* broadcast */
- if (argc == 1 || argc == 3) {
- int res = BroadcastValue(interp, argc, objv + n);
-
- if (res != TCL_BREAK) {
- return res;
- }
- }
- errString = "keyName ?-timeout milliseconds?";
+ return BroadcastValue(interp, objc, objv);
break;
case DeleteIdx: /* delete */
- if (argc == 1) {
- return DeleteKey(interp, objv[n], mode);
- } else if (argc == 2) {
- return DeleteValue(interp, objv[n], objv[n+1], mode);
+ if (objc == 3) {
+ return DeleteKey(interp, objv[2]);
+ } else if (objc == 4) {
+ return DeleteValue(interp, objv[2], objv[3]);
}
errString = "keyName ?valueName?";
break;
case GetIdx: /* get */
- if (argc == 2) {
- return GetValue(interp, objv[n], objv[n+1], mode);
+ if (objc == 4) {
+ return GetValue(interp, objv[2], objv[3]);
}
errString = "keyName valueName";
break;
case KeysIdx: /* keys */
- if (argc == 1) {
- return GetKeyNames(interp, objv[n], NULL, mode);
- } else if (argc == 2) {
- return GetKeyNames(interp, objv[n], objv[n+1], mode);
+ if (objc == 3) {
+ return GetKeyNames(interp, objv[2], NULL);
+ } else if (objc == 4) {
+ return GetKeyNames(interp, objv[2], objv[3]);
}
errString = "keyName ?pattern?";
break;
case SetIdx: /* set */
- if (argc == 1) {
+ if (objc == 3) {
HKEY key;
/*
* Create the key and then close it immediately.
*/
- mode |= KEY_ALL_ACCESS;
- if (OpenKey(interp, objv[n], mode, 1, &key) != TCL_OK) {
+ if (OpenKey(interp, objv[2], KEY_ALL_ACCESS, 1, &key) != TCL_OK) {
return TCL_ERROR;
}
RegCloseKey(key);
return TCL_OK;
- } else if (argc == 3) {
- return SetValue(interp, objv[n], objv[n+1], objv[n+2], NULL,
- mode);
- } else if (argc == 4) {
- return SetValue(interp, objv[n], objv[n+1], objv[n+2], objv[n+3],
- mode);
+ } else if (objc == 5 || objc == 6) {
+ Tcl_Obj *typeObj = (objc == 5) ? NULL : objv[5];
+ return SetValue(interp, objv[2], objv[3], objv[4], typeObj);
}
errString = "keyName ?valueName data ?type??";
break;
case TypeIdx: /* type */
- if (argc == 2) {
- return GetType(interp, objv[n], objv[n+1], mode);
+ if (objc == 4) {
+ return GetType(interp, objv[2], objv[3]);
}
errString = "keyName valueName";
break;
case ValuesIdx: /* values */
- if (argc == 1) {
- return GetValueNames(interp, objv[n], NULL, mode);
- } else if (argc == 2) {
- return GetValueNames(interp, objv[n], objv[n+1], mode);
+ if (objc == 3) {
+ return GetValueNames(interp, objv[2], NULL);
+ } else if (objc == 4) {
+ return GetValueNames(interp, objv[2], objv[3]);
}
errString = "keyName ?pattern?";
break;
}
- Tcl_WrongNumArgs(interp, (mode ? 3 : 2), objv, errString);
+ Tcl_WrongNumArgs(interp, 2, objv, errString);
return TCL_ERROR;
}
@@ -438,36 +435,33 @@ RegistryObjCmd(
static int
DeleteKey(
Tcl_Interp *interp, /* Current interpreter. */
- Tcl_Obj *keyNameObj, /* Name of key to delete. */
- REGSAM mode) /* Mode flags to pass. */
+ Tcl_Obj *keyNameObj) /* Name of key to delete. */
{
char *tail, *buffer, *hostName, *keyName;
- const WCHAR *nativeTail;
+ CONST char *nativeTail;
HKEY rootKey, subkey;
DWORD result;
+ int length;
Tcl_DString buf;
- REGSAM saveMode = mode;
- Tcl_Size len;
/*
* Find the parent of the key being deleted and open it.
*/
- keyName = Tcl_GetStringFromObj(keyNameObj, &len);
- buffer = (char *)Tcl_Alloc(len + 1);
+ keyName = Tcl_GetStringFromObj(keyNameObj, &length);
+ buffer = ckalloc((unsigned int) length + 1);
strcpy(buffer, keyName);
if (ParseKeyName(interp, buffer, &hostName, &rootKey,
&keyName) != TCL_OK) {
- Tcl_Free(buffer);
+ ckfree(buffer);
return TCL_ERROR;
}
if (*keyName == '\0') {
- Tcl_SetObjResult(interp,
- Tcl_NewStringObj("bad key: cannot delete root keys", -1));
- Tcl_SetErrorCode(interp, "WIN_REG", "DEL_ROOT_KEY", (void *)NULL);
- Tcl_Free(buffer);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "bad key: cannot delete root keys", -1));
+ ckfree(buffer);
return TCL_ERROR;
}
@@ -479,15 +473,15 @@ DeleteKey(
keyName = NULL;
}
- mode |= KEY_ENUMERATE_SUB_KEYS | DELETE;
- result = OpenSubKey(hostName, rootKey, keyName, mode, 0, &subkey);
+ result = OpenSubKey(hostName, rootKey, keyName,
+ KEY_ENUMERATE_SUB_KEYS | DELETE, 0, &subkey);
if (result != ERROR_SUCCESS) {
- Tcl_Free(buffer);
+ ckfree(buffer);
if (result == ERROR_FILE_NOT_FOUND) {
return TCL_OK;
}
- Tcl_SetObjResult(interp,
- Tcl_NewStringObj("unable to delete key: ", -1));
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "unable to delete key: ", -1));
AppendSystemError(interp, result);
return TCL_ERROR;
}
@@ -496,9 +490,8 @@ DeleteKey(
* Now we recursively delete the key and everything below it.
*/
- Tcl_DStringInit(&buf);
- nativeTail = Tcl_UtfToWCharDString(tail, -1, &buf);
- result = RecursiveDeleteKey(subkey, nativeTail, saveMode);
+ nativeTail = Tcl_WinUtfToTChar(tail, -1, &buf);
+ result = RecursiveDeleteKey(subkey, nativeTail);
Tcl_DStringFree(&buf);
if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
@@ -511,7 +504,7 @@ DeleteKey(
}
RegCloseKey(subkey);
- Tcl_Free(buffer);
+ ckfree(buffer);
return result;
}
@@ -535,33 +528,31 @@ static int
DeleteValue(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Obj *keyNameObj, /* Name of key. */
- Tcl_Obj *valueNameObj, /* Name of value to delete. */
- REGSAM mode) /* Mode flags to pass. */
+ Tcl_Obj *valueNameObj) /* Name of value to delete. */
{
HKEY key;
char *valueName;
+ int length;
DWORD result;
Tcl_DString ds;
- Tcl_Size len;
/*
* Attempt to open the key for deletion.
*/
- mode |= KEY_SET_VALUE;
- if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
+ if (OpenKey(interp, keyNameObj, KEY_SET_VALUE, 0, &key)
+ != TCL_OK) {
return TCL_ERROR;
}
- valueName = Tcl_GetStringFromObj(valueNameObj, &len);
- Tcl_DStringInit(&ds);
- Tcl_UtfToWCharDString(valueName, len, &ds);
- result = RegDeleteValueW(key, (const WCHAR *)Tcl_DStringValue(&ds));
+ valueName = Tcl_GetStringFromObj(valueNameObj, &length);
+ Tcl_WinUtfToTChar(valueName, length, &ds);
+ result = (*regWinProcs->regDeleteValueProc)(key, Tcl_DStringValue(&ds));
Tcl_DStringFree(&ds);
if (result != ERROR_SUCCESS) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unable to delete value \"%s\" from key \"%s\": ",
- Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
+ Tcl_AppendResult(interp, "unable to delete value \"",
+ Tcl_GetString(valueNameObj), "\" from key \"",
+ Tcl_GetString(keyNameObj), "\": ", NULL);
AppendSystemError(interp, result);
result = TCL_ERROR;
} else {
@@ -594,13 +585,11 @@ static int
GetKeyNames(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Obj *keyNameObj, /* Key to enumerate. */
- Tcl_Obj *patternObj, /* Optional match pattern. */
- REGSAM mode) /* Mode flags to pass. */
+ Tcl_Obj *patternObj) /* Optional match pattern. */
{
- const char *pattern; /* Pattern being matched against subkeys */
+ char *pattern; /* Pattern being matched against subkeys */
HKEY key; /* Handle to the key being examined */
- WCHAR buffer[MAX_KEY_LENGTH];
- /* Buffer to hold the subkey name */
+ TCHAR buffer[MAX_KEY_LENGTH*2]; /* Buffer to hold the subkey name */
DWORD bufSize; /* Size of the buffer */
DWORD index; /* Position of the current subkey */
char *name; /* Subkey name */
@@ -614,38 +603,40 @@ GetKeyNames(
pattern = NULL;
}
- /*
- * Attempt to open the key for enumeration.
- */
+ /* Attempt to open the key for enumeration. */
- mode |= KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS;
- if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
+ if (OpenKey(interp, keyNameObj,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ 0, &key) != TCL_OK) {
return TCL_ERROR;
}
- /*
- * Enumerate the subkeys.
- */
+ /* Enumerate the subkeys */
resultPtr = Tcl_NewObj();
for (index = 0;; ++index) {
bufSize = MAX_KEY_LENGTH;
- result = RegEnumKeyExW(key, index, buffer, &bufSize,
- NULL, NULL, NULL, NULL);
+ result = (*regWinProcs->regEnumKeyExProc)
+ (key, index, buffer, &bufSize, NULL, NULL, NULL, NULL);
if (result != ERROR_SUCCESS) {
if (result == ERROR_NO_MORE_ITEMS) {
result = TCL_OK;
} else {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unable to enumerate subkeys of \"%s\": ",
- Tcl_GetString(keyNameObj)));
+ Tcl_SetObjResult(interp, Tcl_NewObj());
+ Tcl_AppendResult(interp,
+ "unable to enumerate subkeys of \"",
+ Tcl_GetString(keyNameObj), "\": ", NULL);
AppendSystemError(interp, result);
result = TCL_ERROR;
}
break;
}
- Tcl_DStringInit(&ds);
- name = Tcl_WCharToUtfDString(buffer, bufSize, &ds);
+ if (regWinProcs->useWide) {
+ Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize * sizeof(WCHAR), &ds);
+ } else {
+ Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize, &ds);
+ }
+ name = Tcl_DStringValue(&ds);
if (pattern && !Tcl_StringMatch(name, pattern)) {
Tcl_DStringFree(&ds);
continue;
@@ -688,22 +679,22 @@ static int
GetType(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Obj *keyNameObj, /* Name of key. */
- Tcl_Obj *valueNameObj, /* Name of value to get. */
- REGSAM mode) /* Mode flags to pass. */
+ Tcl_Obj *valueNameObj) /* Name of value to get. */
{
HKEY key;
- DWORD result, type;
+ DWORD result;
+ DWORD type;
Tcl_DString ds;
- const char *valueName;
- const WCHAR *nativeValue;
- Tcl_Size len;
+ char *valueName;
+ CONST char *nativeValue;
+ int length;
/*
* Attempt to open the key for reading.
*/
- mode |= KEY_QUERY_VALUE;
- if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
+ if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key)
+ != TCL_OK) {
return TCL_ERROR;
}
@@ -711,18 +702,17 @@ GetType(
* Get the type of the value.
*/
- valueName = Tcl_GetStringFromObj(valueNameObj, &len);
- Tcl_DStringInit(&ds);
- nativeValue = Tcl_UtfToWCharDString(valueName, len, &ds);
- result = RegQueryValueExW(key, nativeValue, NULL, &type,
+ valueName = Tcl_GetStringFromObj(valueNameObj, &length);
+ nativeValue = Tcl_WinUtfToTChar(valueName, length, &ds);
+ result = (*regWinProcs->regQueryValueExProc)(key, nativeValue, NULL, &type,
NULL, NULL);
Tcl_DStringFree(&ds);
RegCloseKey(key);
if (result != ERROR_SUCCESS) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unable to get type of value \"%s\" from key \"%s\": ",
- Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
+ Tcl_AppendResult(interp, "unable to get type of value \"",
+ Tcl_GetString(valueNameObj), "\" from key \"",
+ Tcl_GetString(keyNameObj), "\": ", NULL);
AppendSystemError(interp, result);
return TCL_ERROR;
}
@@ -761,22 +751,20 @@ static int
GetValue(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Obj *keyNameObj, /* Name of key. */
- Tcl_Obj *valueNameObj, /* Name of value to get. */
- REGSAM mode) /* Mode flags to pass. */
+ Tcl_Obj *valueNameObj) /* Name of value to get. */
{
HKEY key;
- const char *valueName;
- const WCHAR *nativeValue;
+ char *valueName;
+ CONST char *nativeValue;
DWORD result, length, type;
Tcl_DString data, buf;
- Tcl_Size len;
+ int nameLen;
/*
* Attempt to open the key for reading.
*/
- mode |= KEY_QUERY_VALUE;
- if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
+ if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key) != TCL_OK) {
return TCL_ERROR;
}
@@ -786,19 +774,18 @@ GetValue(
* length to TCL_DSTRING_STATIC_SIZE, but this should be safer if the
* implementation of Dstrings changes.
*
- * This allows short values to be read from the registry in one call.
+ * This allows short values to be read from the registy in one call.
* Longer values need a second call with an expanded DString.
*/
Tcl_DStringInit(&data);
Tcl_DStringSetLength(&data, TCL_DSTRING_STATIC_SIZE - 1);
- length = TCL_DSTRING_STATIC_SIZE/sizeof(WCHAR) - 1;
+ length = TCL_DSTRING_STATIC_SIZE / (regWinProcs->useWide ? 2 : 1) - 1;
- valueName = Tcl_GetStringFromObj(valueNameObj, &len);
- Tcl_DStringInit(&buf);
- nativeValue = Tcl_UtfToWCharDString(valueName, len, &buf);
+ valueName = Tcl_GetStringFromObj(valueNameObj, &nameLen);
+ nativeValue = Tcl_WinUtfToTChar(valueName, nameLen, &buf);
- result = RegQueryValueExW(key, nativeValue, NULL, &type,
+ result = (*regWinProcs->regQueryValueExProc)(key, nativeValue, NULL, &type,
(BYTE *) Tcl_DStringValue(&data), &length);
while (result == ERROR_MORE_DATA) {
/*
@@ -807,17 +794,17 @@ GetValue(
* HKEY_PERFORMANCE_DATA
*/
- length = Tcl_DStringLength(&data) * (2 / sizeof(WCHAR));
- Tcl_DStringSetLength(&data, length * sizeof(WCHAR));
- result = RegQueryValueExW(key, nativeValue,
+ length = Tcl_DStringLength(&data) * (regWinProcs->useWide ? 1 : 2);
+ Tcl_DStringSetLength(&data, (int) length * (regWinProcs->useWide ? 2 : 1));
+ result = (*regWinProcs->regQueryValueExProc)(key, (char *) nativeValue,
NULL, &type, (BYTE *) Tcl_DStringValue(&data), &length);
}
Tcl_DStringFree(&buf);
RegCloseKey(key);
if (result != ERROR_SUCCESS) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unable to get value \"%s\" from key \"%s\": ",
- Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
+ Tcl_AppendResult(interp, "unable to get value \"",
+ Tcl_GetString(valueNameObj), "\" from key \"",
+ Tcl_GetString(keyNameObj), "\": ", NULL);
AppendSystemError(interp, result);
Tcl_DStringFree(&data);
return TCL_ERROR;
@@ -832,7 +819,7 @@ GetValue(
if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) {
Tcl_SetObjResult(interp, Tcl_NewIntObj((int) ConvertDWORD(type,
- *((DWORD *) Tcl_DStringValue(&data)))));
+ *((DWORD*) Tcl_DStringValue(&data)))));
} else if (type == REG_MULTI_SZ) {
char *p = Tcl_DStringValue(&data);
char *end = Tcl_DStringValue(&data) + length;
@@ -844,24 +831,24 @@ GetValue(
* we get bogus data.
*/
- while ((p < end) && *((WCHAR *) p) != 0) {
- WCHAR *wp = (WCHAR *) p;
-
- Tcl_DStringInit(&buf);
- Tcl_WCharToUtfDString(wp, wcslen(wp), &buf);
+ while (p < end && ((regWinProcs->useWide)
+ ? *((Tcl_UniChar *)p) : *p) != 0) {
+ Tcl_WinTCharToUtf((TCHAR *) p, -1, &buf);
Tcl_ListObjAppendElement(interp, resultPtr,
Tcl_NewStringObj(Tcl_DStringValue(&buf),
Tcl_DStringLength(&buf)));
-
- while (*wp++ != 0); /* empty loop body */
- p = (char *) wp;
+ if (regWinProcs->useWide) {
+ Tcl_UniChar* up = (Tcl_UniChar*) p;
+ while (*up++ != 0) {}
+ p = (char*) up;
+ } else {
+ while (*p++ != '\0') {}
+ }
Tcl_DStringFree(&buf);
}
Tcl_SetObjResult(interp, resultPtr);
} else if ((type == REG_SZ) || (type == REG_EXPAND_SZ)) {
- WCHAR *wp = (WCHAR *) Tcl_DStringValue(&data);
- Tcl_DStringInit(&buf);
- Tcl_WCharToUtfDString((const WCHAR *)Tcl_DStringValue(&data), wcslen(wp), &buf);
+ Tcl_WinTCharToUtf((TCHAR *) Tcl_DStringValue(&data), -1, &buf);
Tcl_DStringResult(interp, &buf);
} else {
/*
@@ -869,7 +856,7 @@ GetValue(
*/
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(
- (BYTE *) Tcl_DStringValue(&data), length));
+ (BYTE *) Tcl_DStringValue(&data), (int) length));
}
Tcl_DStringFree(&data);
return result;
@@ -880,7 +867,7 @@ GetValue(
*
* GetValueNames --
*
- * This function enumerates the values of the given key. If the
+ * This function enumerates the values of the a given key. If the
* optional pattern is supplied, then only value names that match the
* pattern will be returned.
*
@@ -898,27 +885,27 @@ static int
GetValueNames(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Obj *keyNameObj, /* Key to enumerate. */
- Tcl_Obj *patternObj, /* Optional match pattern. */
- REGSAM mode) /* Mode flags to pass. */
+ Tcl_Obj *patternObj) /* Optional match pattern. */
{
HKEY key;
Tcl_Obj *resultPtr;
DWORD index, size, result;
Tcl_DString buffer, ds;
- const char *pattern, *name;
+ char *pattern, *name;
/*
* Attempt to open the key for enumeration.
*/
- mode |= KEY_QUERY_VALUE;
- if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
+ if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key)
+ != TCL_OK) {
return TCL_ERROR;
}
resultPtr = Tcl_NewObj();
Tcl_DStringInit(&buffer);
- Tcl_DStringSetLength(&buffer, MAX_KEY_LENGTH * sizeof(WCHAR));
+ Tcl_DStringSetLength(&buffer,
+ (int) ((regWinProcs->useWide) ? MAX_KEY_LENGTH*2 : MAX_KEY_LENGTH));
index = 0;
result = TCL_OK;
@@ -935,10 +922,16 @@ GetValueNames(
*/
size = MAX_KEY_LENGTH;
- while (RegEnumValueW(key,index, (WCHAR *)Tcl_DStringValue(&buffer),
- &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString((const WCHAR *)Tcl_DStringValue(&buffer), size, &ds);
+ while ((*regWinProcs->regEnumValueProc)(key, index,
+ Tcl_DStringValue(&buffer), &size, NULL, NULL, NULL, NULL)
+ == ERROR_SUCCESS) {
+
+ if (regWinProcs->useWide) {
+ size *= 2;
+ }
+
+ Tcl_WinTCharToUtf((TCHAR *) Tcl_DStringValue(&buffer), (int) size,
+ &ds);
name = Tcl_DStringValue(&ds);
if (!pattern || Tcl_StringMatch(name, pattern)) {
result = Tcl_ListObjAppendElement(interp, resultPtr,
@@ -985,12 +978,12 @@ OpenKey(
HKEY *keyPtr) /* Returned HKEY. */
{
char *keyName, *buffer, *hostName;
+ int length;
HKEY rootKey;
DWORD result;
- Tcl_Size len;
- keyName = Tcl_GetStringFromObj(keyNameObj, &len);
- buffer = (char *)Tcl_Alloc(len + 1);
+ keyName = Tcl_GetStringFromObj(keyNameObj, &length);
+ buffer = ckalloc((unsigned int) length + 1);
strcpy(buffer, keyName);
result = ParseKeyName(interp, buffer, &hostName, &rootKey, &keyName);
@@ -1006,7 +999,7 @@ OpenKey(
}
}
- Tcl_Free(buffer);
+ ckfree(buffer);
return result;
}
@@ -1015,7 +1008,7 @@ OpenKey(
*
* OpenSubKey --
*
- * Opens a given subkey of the given root key on the specified
+ * This function opens a given subkey of a root key on the specified
* host.
*
* Results:
@@ -1045,9 +1038,8 @@ OpenSubKey(
*/
if (hostName) {
- Tcl_DStringInit(&buf);
- hostName = (char *) Tcl_UtfToWCharDString(hostName, -1, &buf);
- result = RegConnectRegistryW((WCHAR *)hostName, rootKey,
+ hostName = (char *) Tcl_WinUtfToTChar(hostName, -1, &buf);
+ result = (*regWinProcs->regConnectRegistryProc)(hostName, rootKey,
&rootKey);
Tcl_DStringFree(&buf);
if (result != ERROR_SUCCESS) {
@@ -1060,30 +1052,23 @@ OpenSubKey(
* this key must be closed by the caller.
*/
- if (keyName) {
- Tcl_DStringInit(&buf);
- keyName = (char *) Tcl_UtfToWCharDString(keyName, -1, &buf);
- }
+ keyName = (char *) Tcl_WinUtfToTChar(keyName, -1, &buf);
if (flags & REG_CREATE) {
DWORD create;
-
- result = RegCreateKeyExW(rootKey, (WCHAR *)keyName, 0, NULL,
+ result = (*regWinProcs->regCreateKeyExProc)(rootKey, keyName, 0, NULL,
REG_OPTION_NON_VOLATILE, mode, NULL, keyPtr, &create);
} else if (rootKey == HKEY_PERFORMANCE_DATA) {
/*
* Here we fudge it for this special root key. See MSDN for more info
* on HKEY_PERFORMANCE_DATA and the peculiarities surrounding it.
*/
-
*keyPtr = HKEY_PERFORMANCE_DATA;
result = ERROR_SUCCESS;
} else {
- result = RegOpenKeyExW(rootKey, (WCHAR *)keyName, 0, mode,
+ result = (*regWinProcs->regOpenKeyExProc)(rootKey, keyName, 0, mode,
keyPtr);
}
- if (keyName) {
- Tcl_DStringFree(&buf);
- }
+ Tcl_DStringFree(&buf);
/*
* Be sure to close the root key since we are done with it now.
@@ -1100,7 +1085,7 @@ OpenSubKey(
*
* ParseKeyName --
*
- * Parses a key name into the host, root, and subkey parts.
+ * This function parses a key name into the host, root, and subkey parts.
*
* Results:
* The pointers to the start of the host and subkey names are returned in
@@ -1144,9 +1129,8 @@ ParseKeyName(
rootName = name;
}
if (!rootName) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "bad key \"%s\": must start with a valid root", name));
- Tcl_SetErrorCode(interp, "WIN_REG", "NO_ROOT_KEY", (void *)NULL);
+ Tcl_AppendResult(interp, "bad key \"", name,
+ "\": must start with a valid root", NULL);
return TCL_ERROR;
}
@@ -1198,16 +1182,12 @@ ParseKeyName(
static DWORD
RecursiveDeleteKey(
HKEY startKey, /* Parent of key to be deleted. */
- const WCHAR *keyName, /* Name of key to be deleted in external
+ CONST char *keyName) /* Name of key to be deleted in external
* encoding, not UTF. */
- REGSAM mode) /* Mode flags to pass. */
{
DWORD result, size;
Tcl_DString subkey;
HKEY hKey;
- REGSAM saveMode = mode;
- static int checkExProc = 0;
- static LONG (* regDeleteKeyExProc) (HKEY, LPCWSTR, REGSAM, DWORD) = (LONG (*) (HKEY, LPCWSTR, REGSAM, DWORD)) NULL;
/*
* Do not allow NULL or empty key name.
@@ -1217,48 +1197,29 @@ RecursiveDeleteKey(
return ERROR_BADKEY;
}
- mode |= KEY_ENUMERATE_SUB_KEYS | DELETE | KEY_QUERY_VALUE;
- result = RegOpenKeyExW(startKey, keyName, 0, mode, &hKey);
+ result = (*regWinProcs->regOpenKeyExProc)(startKey, keyName, 0,
+ KEY_ENUMERATE_SUB_KEYS | DELETE | KEY_QUERY_VALUE, &hKey);
if (result != ERROR_SUCCESS) {
return result;
}
Tcl_DStringInit(&subkey);
- Tcl_DStringSetLength(&subkey, MAX_KEY_LENGTH * sizeof(WCHAR));
+ Tcl_DStringSetLength(&subkey,
+ (int) ((regWinProcs->useWide) ? MAX_KEY_LENGTH * 2 : MAX_KEY_LENGTH));
- mode = saveMode;
while (result == ERROR_SUCCESS) {
/*
* Always get index 0 because key deletion changes ordering.
*/
size = MAX_KEY_LENGTH;
- result = RegEnumKeyExW(hKey, 0, (WCHAR *)Tcl_DStringValue(&subkey),
- &size, NULL, NULL, NULL, NULL);
+ result=(*regWinProcs->regEnumKeyExProc)(hKey, 0,
+ Tcl_DStringValue(&subkey), &size, NULL, NULL, NULL, NULL);
if (result == ERROR_NO_MORE_ITEMS) {
- /*
- * RegDeleteKeyEx doesn't exist on non-64bit XP platforms, so we
- * can't compile with it in. We need to check for it at runtime
- * and use it if we find it.
- */
-
- if (mode && !checkExProc) {
- HMODULE handle;
-
- checkExProc = 1;
- handle = GetModuleHandleW(L"ADVAPI32");
- regDeleteKeyExProc = (LONG (*) (HKEY, LPCWSTR, REGSAM, DWORD))
- (void *)GetProcAddress(handle, "RegDeleteKeyExW");
- }
- if (mode && regDeleteKeyExProc) {
- result = regDeleteKeyExProc(startKey, keyName, mode, 0);
- } else {
- result = RegDeleteKeyW(startKey, keyName);
- }
+ result = (*regWinProcs->regDeleteKeyProc)(startKey, keyName);
break;
} else if (result == ERROR_SUCCESS) {
- result = RecursiveDeleteKey(hKey,
- (const WCHAR *) Tcl_DStringValue(&subkey), mode);
+ result = RecursiveDeleteKey(hKey, Tcl_DStringValue(&subkey));
}
}
Tcl_DStringFree(&subkey);
@@ -1290,33 +1251,30 @@ SetValue(
Tcl_Obj *keyNameObj, /* Name of key. */
Tcl_Obj *valueNameObj, /* Name of value to set. */
Tcl_Obj *dataObj, /* Data to be written. */
- Tcl_Obj *typeObj, /* Type of data to be written. */
- REGSAM mode) /* Mode flags to pass. */
+ Tcl_Obj *typeObj) /* Type of data to be written. */
{
int type;
DWORD result;
HKEY key;
- const char *valueName;
+ int length;
+ char *valueName;
Tcl_DString nameBuf;
- Tcl_Size len;
if (typeObj == NULL) {
type = REG_SZ;
} else if (Tcl_GetIndexFromObj(interp, typeObj, typeNames, "type",
0, (int *) &type) != TCL_OK) {
- if (Tcl_GetIntFromObj(NULL, typeObj, (int *) &type) != TCL_OK) {
+ if (Tcl_GetIntFromObj(NULL, typeObj, (int*) &type) != TCL_OK) {
return TCL_ERROR;
}
Tcl_ResetResult(interp);
}
- mode |= KEY_ALL_ACCESS;
- if (OpenKey(interp, keyNameObj, mode, 1, &key) != TCL_OK) {
+ if (OpenKey(interp, keyNameObj, KEY_ALL_ACCESS, 1, &key) != TCL_OK) {
return TCL_ERROR;
}
- valueName = Tcl_GetStringFromObj(valueNameObj, &len);
- Tcl_DStringInit(&nameBuf);
- valueName = (char *) Tcl_UtfToWCharDString(valueName, len, &nameBuf);
+ valueName = Tcl_GetStringFromObj(valueNameObj, &length);
+ valueName = (char *) Tcl_WinUtfToTChar(valueName, length, &nameBuf);
if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) {
int value;
@@ -1327,12 +1285,12 @@ SetValue(
return TCL_ERROR;
}
- value = ConvertDWORD((DWORD) type, (DWORD) value);
- result = RegSetValueExW(key, (WCHAR *) valueName, 0,
+ value = ConvertDWORD((DWORD)type, (DWORD)value);
+ result = (*regWinProcs->regSetValueExProc)(key, valueName, 0,
(DWORD) type, (BYTE *) &value, sizeof(DWORD));
} else if (type == REG_MULTI_SZ) {
Tcl_DString data, buf;
- Tcl_Size objc, i;
+ int objc, i;
Tcl_Obj **objv;
if (Tcl_ListObjGetElements(interp, dataObj, &objc, &objv) != TCL_OK) {
@@ -1349,52 +1307,53 @@ SetValue(
Tcl_DStringInit(&data);
for (i = 0; i < objc; i++) {
- const char *bytes = Tcl_GetStringFromObj(objv[i], &len);
-
- Tcl_DStringAppend(&data, bytes, len);
+ Tcl_DStringAppend(&data, Tcl_GetString(objv[i]), -1);
/*
- * Add a null character to separate this value from the next.
+ * Add a null character to separate this value from the next. We
+ * accomplish this by growing the string by one byte. Since the
+ * DString always tacks on an extra null byte, the new byte will
+ * already be set to null.
*/
- Tcl_DStringAppend(&data, "", 1); /* NUL-terminated string */
+ Tcl_DStringSetLength(&data, Tcl_DStringLength(&data)+1);
}
- Tcl_DStringInit(&buf);
- Tcl_UtfToWCharDString(Tcl_DStringValue(&data), Tcl_DStringLength(&data)+1,
+ Tcl_WinUtfToTChar(Tcl_DStringValue(&data), Tcl_DStringLength(&data)+1,
&buf);
- result = RegSetValueExW(key, (WCHAR *) valueName, 0,
- (DWORD) type, (BYTE *) Tcl_DStringValue(&buf),
+ result = (*regWinProcs->regSetValueExProc)(key, valueName, 0,
+ (DWORD) type, (BYTE *) Tcl_DStringValue(&buf),
(DWORD) Tcl_DStringLength(&buf));
Tcl_DStringFree(&data);
Tcl_DStringFree(&buf);
} else if (type == REG_SZ || type == REG_EXPAND_SZ) {
Tcl_DString buf;
- const char *data = Tcl_GetStringFromObj(dataObj, &len);
+ CONST char *data = Tcl_GetStringFromObj(dataObj, &length);
- Tcl_DStringInit(&buf);
- data = (char *) Tcl_UtfToWCharDString(data, len, &buf);
+ data = Tcl_WinUtfToTChar(data, length, &buf);
/*
- * Include the null in the length, padding if needed for WCHAR.
+ * Include the null in the length, padding if needed for Unicode.
*/
- Tcl_DStringSetLength(&buf, Tcl_DStringLength(&buf)+1);
+ if (regWinProcs->useWide) {
+ Tcl_DStringSetLength(&buf, Tcl_DStringLength(&buf)+1);
+ }
+ length = Tcl_DStringLength(&buf) + 1;
- result = RegSetValueExW(key, (WCHAR *) valueName, 0,
- (DWORD) type, (BYTE *) data, (DWORD) Tcl_DStringLength(&buf) + 1);
+ result = (*regWinProcs->regSetValueExProc)(key, valueName, 0,
+ (DWORD) type, (BYTE *) data, (DWORD) length);
Tcl_DStringFree(&buf);
} else {
BYTE *data;
- Tcl_Size bytelength;
/*
* Store binary data in the registry.
*/
- data = (BYTE *) Tcl_GetByteArrayFromObj(dataObj, &bytelength);
- result = RegSetValueExW(key, (WCHAR *) valueName, 0,
- (DWORD) type, data, (DWORD) bytelength);
+ data = (BYTE *) Tcl_GetByteArrayFromObj(dataObj, &length);
+ result = (*regWinProcs->regSetValueExProc)(key, valueName, 0,
+ (DWORD) type, data, (DWORD) length);
}
Tcl_DStringFree(&nameBuf);
@@ -1429,46 +1388,48 @@ SetValue(
static int
BroadcastValue(
Tcl_Interp *interp, /* Current interpreter. */
- Tcl_Size objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument values. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *CONST objv[]) /* Argument values. */
{
LRESULT result;
DWORD_PTR sendResult;
- int timeout = 3000;
- Tcl_Size len;
- const char *str;
+ UINT timeout = 3000;
+ int len;
+ CONST char *str;
Tcl_Obj *objPtr;
- WCHAR *wstr;
- Tcl_DString ds;
- if (objc == 3) {
- str = Tcl_GetStringFromObj(objv[1], &len);
- if ((len < 2) || (*str != '-') || strncmp(str, "-timeout", len)) {
- return TCL_BREAK;
+ if ((objc != 3) && (objc != 5)) {
+ Tcl_WrongNumArgs(interp, 2, objv, "keyName ?-timeout millisecs?");
+ return TCL_ERROR;
+ }
+
+ if (objc > 3) {
+ str = Tcl_GetStringFromObj(objv[3], &len);
+ if ((len < 2) || (*str != '-')
+ || strncmp(str, "-timeout", (size_t) len)) {
+ Tcl_WrongNumArgs(interp, 2, objv, "keyName ?-timeout millisecs?");
+ return TCL_ERROR;
}
- if (Tcl_GetIntFromObj(interp, objv[2], &timeout) != TCL_OK) {
+ if (Tcl_GetIntFromObj(interp, objv[4], (int *) &timeout) != TCL_OK) {
return TCL_ERROR;
}
}
- str = Tcl_GetStringFromObj(objv[0], &len);
- Tcl_DStringInit(&ds);
- wstr = Tcl_UtfToWCharDString(str, len, &ds);
- if (Tcl_DStringLength(&ds) == 0) {
- wstr = NULL;
+ str = Tcl_GetStringFromObj(objv[2], &len);
+ if (len == 0) {
+ str = NULL;
}
/*
* Use the ignore the result.
*/
- result = SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE,
- (WPARAM) 0, (LPARAM) wstr, SMTO_ABORTIFHUNG, (UINT) timeout, &sendResult);
- Tcl_DStringFree(&ds);
+ result = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE,
+ (WPARAM) 0, (LPARAM) str, SMTO_ABORTIFHUNG, timeout, &sendResult);
objPtr = Tcl_NewObj();
- Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewWideIntObj((Tcl_WideInt) result));
- Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewWideIntObj((Tcl_WideInt) sendResult));
+ Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewLongObj((long) result));
+ Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewLongObj((long) sendResult));
Tcl_SetObjResult(interp, objPtr);
return TCL_OK;
@@ -1479,7 +1440,7 @@ BroadcastValue(
*
* AppendSystemError --
*
- * Formats a Windows system error message and places it into
+ * This routine formats a Windows system error message and places it into
* the interpreter result.
*
* Results:
@@ -1497,8 +1458,8 @@ AppendSystemError(
DWORD error) /* Result code from error. */
{
int length;
- WCHAR *tMsgPtr, **tMsgPtrPtr = &tMsgPtr;
- const char *msg;
+ WCHAR *wMsgPtr, **wMsgPtrPtr = &wMsgPtr;
+ char *msg;
char id[TCL_INTEGER_SPACE], msgBuf[24 + TCL_INTEGER_SPACE];
Tcl_DString ds;
Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
@@ -1508,37 +1469,54 @@ AppendSystemError(
}
length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (WCHAR *) tMsgPtrPtr,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (WCHAR *) wMsgPtrPtr,
0, NULL);
if (length == 0) {
- snprintf(msgBuf, sizeof(msgBuf), "unknown error: %ld", error);
- msg = msgBuf;
- } else {
char *msgPtr;
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString(tMsgPtr, wcslen(tMsgPtr), &ds);
- LocalFree(tMsgPtr);
+ length = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *) &msgPtr,
+ 0, NULL);
+ if (length > 0) {
+ wMsgPtr = (WCHAR *) LocalAlloc(LPTR, (length + 1) * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, msgPtr, length + 1, wMsgPtr,
+ length + 1);
+ LocalFree(msgPtr);
+ }
+ }
+ if (length == 0) {
+ if (error == ERROR_CALL_NOT_IMPLEMENTED) {
+ msg = "function not supported under Win32s";
+ } else {
+ sprintf(msgBuf, "unknown error: %ld", error);
+ msg = msgBuf;
+ }
+ } else {
+ Tcl_Encoding encoding;
+
+ encoding = Tcl_GetEncoding(NULL, "unicode");
+ Tcl_ExternalToUtfDString(encoding, (char *) wMsgPtr, -1, &ds);
+ Tcl_FreeEncoding(encoding);
+ LocalFree(wMsgPtr);
- msgPtr = Tcl_DStringValue(&ds);
+ msg = Tcl_DStringValue(&ds);
length = Tcl_DStringLength(&ds);
/*
* Trim the trailing CR/LF from the system message.
*/
- if (msgPtr[length-1] == '\n') {
- --length;
+ if (msg[length-1] == '\n') {
+ msg[--length] = 0;
}
- if (msgPtr[length-1] == '\r') {
- --length;
+ if (msg[length-1] == '\r') {
+ msg[--length] = 0;
}
- msgPtr[length] = 0;
- msg = msgPtr;
}
- snprintf(id, sizeof(id), "%ld", error);
- Tcl_SetErrorCode(interp, "WINDOWS", id, msg, (void *)NULL);
+ sprintf(id, "%ld", error);
+ Tcl_SetErrorCode(interp, "WINDOWS", id, msg, NULL);
Tcl_AppendToObj(resultPtr, msg, length);
Tcl_SetObjResult(interp, resultPtr);
@@ -1552,7 +1530,7 @@ AppendSystemError(
*
* ConvertDWORD --
*
- * Determines whether a DWORD needs to be byte swapped, and
+ * This function determines whether a DWORD needs to be byte swapped, and
* returns the appropriately swapped value.
*
* Results:
@@ -1569,15 +1547,14 @@ ConvertDWORD(
DWORD type, /* Either REG_DWORD or REG_DWORD_BIG_ENDIAN */
DWORD value) /* The value to be converted. */
{
- const DWORD order = 1;
+ DWORD order = 1;
DWORD localType;
/*
* Check to see if the low bit is in the first byte.
*/
- localType = (*((const char *) &order) == 1)
- ? REG_DWORD : REG_DWORD_BIG_ENDIAN;
+ localType = (*((char*) &order) == 1) ? REG_DWORD : REG_DWORD_BIG_ENDIAN;
return (type != localType) ? (DWORD) SWAPLONG(value) : value;
}
diff --git a/win/tclWinSerial.c b/win/tclWinSerial.c
index 635e978..83f1866 100644
--- a/win/tclWinSerial.c
+++ b/win/tclWinSerial.c
@@ -4,7 +4,7 @@
* This file implements the Windows-specific serial port functions, and
* the "serial" channel driver.
*
- * Copyright © 1999 Scriptics Corp.
+ * Copyright (c) 1999 by Scriptics Corp.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -44,15 +44,6 @@ TCL_DECLARE_MUTEX(serialMutex)
#define SERIAL_ERROR (1<<4)
/*
- * Bit masks used for noting whether to drain or discard output on close. They
- * are disjoint from each other; at most one may be set at a time.
- */
-
-#define SERIAL_CLOSE_DRAIN (1<<6) /* Drain all output on close. */
-#define SERIAL_CLOSE_DISCARD (1<<7) /* Discard all output on close. */
-#define SERIAL_CLOSE_MASK (3<<6) /* Both two bits above. */
-
-/*
* Default time to block between checking status on the serial port.
*/
@@ -85,7 +76,7 @@ typedef struct SerialInfo {
int readable; /* Flag that the channel is readable. */
int writable; /* Flag that the channel is writable. */
int blockTime; /* Maximum blocktime in msec. */
- unsigned long long lastEventTime; /* Time in milliseconds since last readable
+ unsigned int lastEventTime; /* Time in milliseconds since last readable
* event. */
/* Next readable event only after blockTime */
DWORD error; /* pending error code returned by
@@ -102,12 +93,17 @@ typedef struct SerialInfo {
* threads. */
OVERLAPPED osRead; /* OVERLAPPED structure for read operations. */
OVERLAPPED osWrite; /* OVERLAPPED structure for write operations */
- TclPipeThreadInfo *writeTI; /* Thread info structure of writer worker. */
HANDLE writeThread; /* Handle to writer thread. */
CRITICAL_SECTION csWrite; /* Writer thread synchronisation. */
HANDLE evWritable; /* Manual-reset event to signal when the
* writer thread has finished waiting for the
* current buffer to be written. */
+ HANDLE evStartWriter; /* Auto-reset event used by the main thread to
+ * signal when the writer thread should
+ * attempt to write to the serial. */
+ HANDLE evStopWriter; /* Auto-reset event used by the main thread to
+ * signal when the writer thread should close.
+ */
DWORD writeError; /* An error caused by the last background
* write. Set to 0 if no error has been
* detected. This word is shared with the
@@ -124,7 +120,7 @@ typedef struct SerialInfo {
* [fconfigure -queue] */
} SerialInfo;
-typedef struct {
+typedef struct ThreadSpecificData {
/*
* The following pointer refers to the head of the list of serials that
* are being watched for file events.
@@ -140,7 +136,7 @@ static Tcl_ThreadDataKey dataKey;
* events are generated.
*/
-typedef struct {
+typedef struct SerialEvent {
Tcl_Event header; /* Information that is standard for all
* events. */
SerialInfo *infoPtr; /* Pointer to serial info structure. Note that
@@ -165,30 +161,30 @@ static COMMTIMEOUTS no_timeout = {
* Declarations for functions used only in this file.
*/
-static int SerialBlockProc(void *instanceData, int mode);
-static void SerialCheckProc(void *clientData, int flags);
-static int SerialCloseProc(void *instanceData,
- Tcl_Interp *interp, int flags);
+static int SerialBlockProc(ClientData instanceData, int mode);
+static void SerialCheckProc(ClientData clientData, int flags);
+static int SerialCloseProc(ClientData instanceData,
+ Tcl_Interp *interp);
static int SerialEventProc(Tcl_Event *evPtr, int flags);
-static void SerialExitHandler(void *clientData);
-static int SerialGetHandleProc(void *instanceData,
- int direction, void **handlePtr);
+static void SerialExitHandler(ClientData clientData);
+static int SerialGetHandleProc(ClientData instanceData,
+ int direction, ClientData *handlePtr);
static ThreadSpecificData *SerialInit(void);
-static int SerialInputProc(void *instanceData, char *buf,
+static int SerialInputProc(ClientData instanceData, char *buf,
int toRead, int *errorCode);
-static int SerialOutputProc(void *instanceData,
- const char *buf, int toWrite, int *errorCode);
-static void SerialSetupProc(void *clientData, int flags);
-static void SerialWatchProc(void *instanceData, int mask);
-static void ProcExitHandler(void *clientData);
-static int SerialGetOptionProc(void *instanceData,
- Tcl_Interp *interp, const char *optionName,
+static int SerialOutputProc(ClientData instanceData,
+ CONST char *buf, int toWrite, int *errorCode);
+static void SerialSetupProc(ClientData clientData, int flags);
+static void SerialWatchProc(ClientData instanceData, int mask);
+static void ProcExitHandler(ClientData clientData);
+static int SerialGetOptionProc(ClientData instanceData,
+ Tcl_Interp *interp, CONST char *optionName,
Tcl_DString *dsPtr);
-static int SerialSetOptionProc(void *instanceData,
- Tcl_Interp *interp, const char *optionName,
- const char *value);
+static int SerialSetOptionProc(ClientData instanceData,
+ Tcl_Interp *interp, CONST char *optionName,
+ CONST char *value);
static DWORD WINAPI SerialWriterThread(LPVOID arg);
-static void SerialThreadActionProc(void *instanceData,
+static void SerialThreadActionProc(ClientData instanceData,
int action);
static int SerialBlockingRead(SerialInfo *infoPtr, LPVOID buf,
DWORD bufSize, LPDWORD lpRead, LPOVERLAPPED osPtr);
@@ -201,10 +197,10 @@ static int SerialBlockingWrite(SerialInfo *infoPtr, LPVOID buf,
* based IO.
*/
-static const Tcl_ChannelType serialChannelType = {
+static Tcl_ChannelType serialChannelType = {
"serial", /* Type name. */
TCL_CHANNEL_VERSION_5, /* v5 channel */
- TCL_CLOSE2PROC, /* Close proc. */
+ SerialCloseProc, /* Close proc. */
SerialInputProc, /* Input proc. */
SerialOutputProc, /* Output proc. */
NULL, /* Seek proc. */
@@ -212,13 +208,13 @@ static const Tcl_ChannelType serialChannelType = {
SerialGetOptionProc, /* Get option proc. */
SerialWatchProc, /* Set up notifier to watch the channel. */
SerialGetHandleProc, /* Get an OS handle from channel. */
- SerialCloseProc, /* close2proc. */
+ NULL, /* close2proc. */
SerialBlockProc, /* Set blocking or non-blocking mode.*/
NULL, /* flush proc. */
NULL, /* handler proc. */
NULL, /* wide seek proc */
SerialThreadActionProc, /* thread action proc */
- NULL /* truncate */
+ NULL, /* truncate */
};
/*
@@ -285,7 +281,7 @@ SerialInit(void)
static void
SerialExitHandler(
- TCL_UNUSED(void *))
+ ClientData clientData) /* Old window proc */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
SerialInfo *infoPtr;
@@ -323,7 +319,7 @@ SerialExitHandler(
static void
ProcExitHandler(
- TCL_UNUSED(void *))
+ ClientData clientData) /* Old window proc */
{
Tcl_MutexLock(&serialMutex);
initialized = 0;
@@ -335,7 +331,7 @@ ProcExitHandler(
*
* SerialBlockTime --
*
- * Wrapper to set Tcl's block time in msec.
+ * Wrapper to set Tcl's block time in msec
*
* Results:
* None.
@@ -373,14 +369,14 @@ SerialBlockTime(
*----------------------------------------------------------------------
*/
-static unsigned long long
+static unsigned int
SerialGetMilliseconds(void)
{
Tcl_Time time;
- Tcl_GetTime(&time);
+ TclpGetTime(&time);
- return ((unsigned long long)time.sec * 1000 + (unsigned long)time.usec / 1000);
+ return (time.sec * 1000 + time.usec / 1000);
}
/*
@@ -400,13 +396,9 @@ SerialGetMilliseconds(void)
*----------------------------------------------------------------------
*/
-#ifdef __cplusplus
-#define min(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
void
SerialSetupProc(
- TCL_UNUSED(void *),
+ ClientData data, /* Not used. */
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
SerialInfo *infoPtr;
@@ -461,7 +453,7 @@ SerialSetupProc(
static void
SerialCheckProc(
- TCL_UNUSED(void *),
+ ClientData data, /* Not used. */
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
SerialInfo *infoPtr;
@@ -469,7 +461,7 @@ SerialCheckProc(
int needEvent;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
COMSTAT cStat;
- unsigned long long time;
+ unsigned int time;
if (!(flags & TCL_FILE_EVENTS)) {
return;
@@ -519,8 +511,8 @@ SerialCheckProc(
(infoPtr->error & SERIAL_READ_ERRORS)) {
infoPtr->readable = 1;
time = SerialGetMilliseconds();
- if ((time - infoPtr->lastEventTime)
- >= (unsigned long long) infoPtr->blockTime) {
+ if ((unsigned int) (time - infoPtr->lastEventTime)
+ >= (unsigned int) infoPtr->blockTime) {
needEvent = 1;
infoPtr->lastEventTime = time;
}
@@ -535,7 +527,7 @@ SerialCheckProc(
if (needEvent) {
infoPtr->flags |= SERIAL_PENDING;
- evPtr = (SerialEvent *)ckalloc(sizeof(SerialEvent));
+ evPtr = (SerialEvent *) ckalloc(sizeof(SerialEvent));
evPtr->header.proc = SerialEventProc;
evPtr->infoPtr = infoPtr;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
@@ -561,7 +553,7 @@ SerialCheckProc(
static int
SerialBlockProc(
- void *instanceData, /* Instance data for channel. */
+ ClientData instanceData, /* Instance data for channel. */
int mode) /* TCL_MODE_BLOCKING or
* TCL_MODE_NONBLOCKING. */
{
@@ -600,19 +592,16 @@ SerialBlockProc(
static int
SerialCloseProc(
- void *instanceData, /* Pointer to SerialInfo structure. */
- TCL_UNUSED(Tcl_Interp *),
- int flags)
+ ClientData instanceData, /* Pointer to SerialInfo structure. */
+ Tcl_Interp *interp) /* For error reporting. */
{
SerialInfo *serialPtr = (SerialInfo *) instanceData;
- int errorCode = 0, result = 0;
+ int errorCode, result = 0;
SerialInfo *infoPtr, **nextPtrPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ DWORD exitCode;
- if ((flags & (TCL_CLOSE_READ | TCL_CLOSE_WRITE)) != 0) {
- return EINVAL;
- }
-
+ errorCode = 0;
if (serialPtr->validMask & TCL_READABLE) {
PurgeComm(serialPtr->handle, PURGE_RXABORT | PURGE_RXCLEAR);
@@ -620,12 +609,56 @@ SerialCloseProc(
}
serialPtr->validMask &= ~TCL_READABLE;
- if (serialPtr->writeThread) {
- TclPipeThreadStop(&serialPtr->writeTI, serialPtr->writeThread);
+ if (serialPtr->validMask & TCL_WRITABLE) {
+ /*
+ * Generally we cannot wait for a pending write operation because it
+ * may hang due to handshake
+ * WaitForSingleObject(serialPtr->evWritable, INFINITE);
+ */
+ /*
+ * The thread may have already closed on it's own. Check it's exit
+ * code.
+ */
+
+ GetExitCodeThread(serialPtr->writeThread, &exitCode);
+
+ if (exitCode == STILL_ACTIVE) {
+ /*
+ * Set the stop event so that if the writer thread is blocked in
+ * SerialWriterThread on WaitForMultipleEvents, it will exit
+ * cleanly.
+ */
+
+ SetEvent(serialPtr->evStopWriter);
+
+ /*
+ * Wait at most 20 milliseconds for the writer thread to close.
+ */
+
+ if (WaitForSingleObject(serialPtr->writeThread,
+ 20) == WAIT_TIMEOUT) {
+ /*
+ * Forcibly terminate the background thread as a last resort.
+ * Note that we need to guard against terminating the thread
+ * while it is in the middle of Tcl_ThreadAlert because it
+ * won't be able to release the notifier lock.
+ */
+
+ Tcl_MutexLock(&serialMutex);
+
+ /* BUG: this leaks memory */
+ TerminateThread(serialPtr->writeThread, 0);
+
+ Tcl_MutexUnlock(&serialMutex);
+ }
+ }
+
+ CloseHandle(serialPtr->writeThread);
CloseHandle(serialPtr->osWrite.hEvent);
CloseHandle(serialPtr->evWritable);
- CloseHandle(serialPtr->writeThread);
+ CloseHandle(serialPtr->evStartWriter);
+ CloseHandle(serialPtr->evStopWriter);
serialPtr->writeThread = NULL;
PurgeComm(serialPtr->handle, PURGE_TXABORT | PURGE_TXCLEAR);
@@ -645,7 +678,7 @@ SerialCloseProc(
&& (GetStdHandle(STD_OUTPUT_HANDLE) != serialPtr->handle)
&& (GetStdHandle(STD_ERROR_HANDLE) != serialPtr->handle))) {
if (CloseHandle(serialPtr->handle) == FALSE) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
errorCode = errno;
}
}
@@ -673,7 +706,7 @@ SerialCloseProc(
ckfree(serialPtr->writeBuf);
serialPtr->writeBuf = NULL;
}
- ckfree(serialPtr);
+ ckfree((char*) serialPtr);
if (errorCode == 0) {
return result;
@@ -855,7 +888,7 @@ SerialBlockingWrite(
static int
SerialInputProc(
- void *instanceData, /* Serial state. */
+ ClientData instanceData, /* Serial state. */
char *buf, /* Where to store data read. */
int bufSize, /* How much space is available in the
* buffer? */
@@ -899,12 +932,12 @@ SerialInputProc(
bufSize = cStat.cbInQue;
}
} else {
- errno = *errorCode = EWOULDBLOCK;
+ errno = *errorCode = EAGAIN;
return -1;
}
} else {
/*
- * BLOCKING mode: Tcl tries to read a full buffer of 4 kBytes here.
+ * BLOCKING mode: Tcl trys to read a full buffer of 4 kBytes here.
*/
if (cStat.cbInQue > 0) {
@@ -918,7 +951,7 @@ SerialInputProc(
}
if (bufSize == 0) {
- return 0;
+ return bytesRead = 0;
}
/*
@@ -928,7 +961,7 @@ SerialInputProc(
if (SerialBlockingRead(infoPtr, (LPVOID) buf, (DWORD) bufSize, &bytesRead,
&infoPtr->osRead) == FALSE) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
*errorCode = errno;
return -1;
}
@@ -962,8 +995,8 @@ SerialInputProc(
static int
SerialOutputProc(
- void *instanceData, /* Serial state. */
- const char *buf, /* The data buffer. */
+ ClientData instanceData, /* Serial state. */
+ CONST char *buf, /* The data buffer. */
int toWrite, /* How many bytes to write? */
int *errorCode) /* Where to store error code. */
{
@@ -973,9 +1006,9 @@ SerialOutputProc(
*errorCode = 0;
/*
- * At EXIT Tcl tries to flush all open channels in blocking mode. We avoid
+ * At EXIT Tcl trys to flush all open channels in blocking mode. We avoid
* blocking output after ExitProc or CloseHandler(chan) has been called by
- * checking the corresponding variables.
+ * checking the corrresponding variables.
*/
if (!initialized || TclInExit()) {
@@ -1010,7 +1043,7 @@ SerialOutputProc(
*/
if (infoPtr->writeError) {
- Tcl_WinConvertError(infoPtr->writeError);
+ TclWinConvertError(infoPtr->writeError);
infoPtr->writeError = 0;
goto error1;
}
@@ -1038,12 +1071,12 @@ SerialOutputProc(
ckfree(infoPtr->writeBuf);
}
infoPtr->writeBufLen = toWrite;
- infoPtr->writeBuf = (char *)ckalloc(toWrite);
+ infoPtr->writeBuf = ckalloc((unsigned int) toWrite);
}
- memcpy(infoPtr->writeBuf, buf, toWrite);
+ memcpy(infoPtr->writeBuf, buf, (size_t) toWrite);
infoPtr->toWrite = toWrite;
ResetEvent(infoPtr->evWritable);
- TclPipeThreadSignal(&infoPtr->writeTI);
+ SetEvent(infoPtr->evStartWriter);
bytesWritten = (DWORD) toWrite;
} else {
@@ -1069,7 +1102,7 @@ SerialOutputProc(
return (int) bytesWritten;
writeError:
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
error:
/*
@@ -1192,7 +1225,7 @@ SerialEventProc(
static void
SerialWatchProc(
- void *instanceData, /* Serial state. */
+ ClientData instanceData, /* Serial state. */
int mask) /* What events to watch for, OR-ed combination
* of TCL_READABLE, TCL_WRITABLE and
* TCL_EXCEPTION. */
@@ -1249,13 +1282,13 @@ SerialWatchProc(
static int
SerialGetHandleProc(
- void *instanceData, /* The serial state. */
- TCL_UNUSED(int) /*direction*/,
- void **handlePtr) /* Where to store the handle. */
+ ClientData instanceData, /* The serial state. */
+ int direction, /* TCL_READABLE or TCL_WRITABLE */
+ ClientData *handlePtr) /* Where to store the handle. */
{
SerialInfo *infoPtr = (SerialInfo *) instanceData;
- *handlePtr = (void *)infoPtr->handle;
+ *handlePtr = (ClientData) infoPtr->handle;
return TCL_OK;
}
@@ -1280,26 +1313,39 @@ static DWORD WINAPI
SerialWriterThread(
LPVOID arg)
{
- TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *)arg;
- SerialInfo *infoPtr = NULL; /* access info only after success init/wait */
- DWORD bytesWritten, toWrite;
+ SerialInfo *infoPtr = (SerialInfo *)arg;
+ DWORD bytesWritten, toWrite, waitResult;
char *buf;
OVERLAPPED myWrite; /* Have an own OVERLAPPED in this thread. */
+ HANDLE wEvents[2];
+
+ /*
+ * The stop event takes precedence by being first in the list.
+ */
+
+ wEvents[0] = infoPtr->evStopWriter;
+ wEvents[1] = infoPtr->evStartWriter;
for (;;) {
/*
* Wait for the main thread to signal before attempting to write.
*/
- if (!TclPipeThreadWaitForSignal(&pipeTI)) {
- /* exit */
+
+ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE);
+
+ if (waitResult != (WAIT_OBJECT_0 + 1)) {
+ /*
+ * The start event was not signaled. It might be the stop event or
+ * an error, so exit.
+ */
+
break;
}
- infoPtr = (SerialInfo *) pipeTI->clientData;
buf = infoPtr->writeBuf;
toWrite = infoPtr->toWrite;
- myWrite.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+ myWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
/*
* Loop until all of the bytes are written or an error occurs.
@@ -1358,27 +1404,6 @@ SerialWriterThread(
Tcl_MutexUnlock(&serialMutex);
}
- /*
- * We're about to close, so do any drain or discard required.
- */
-
- if (infoPtr) {
- switch (infoPtr->flags & SERIAL_CLOSE_MASK) {
- case SERIAL_CLOSE_DRAIN:
- FlushFileBuffers(infoPtr->handle);
- break;
- case SERIAL_CLOSE_DISCARD:
- PurgeComm(infoPtr->handle, PURGE_TXABORT | PURGE_TXCLEAR);
- break;
- }
- }
-
- /*
- * Worker exit, so inform the main thread or free TI-structure (if owned).
- */
-
- TclPipeThreadExit(&pipeTI);
-
return 0;
}
@@ -1390,7 +1415,7 @@ SerialWriterThread(
* Opens or Reopens the serial port with the OVERLAPPED FLAG set
*
* Results:
- * Returns the new handle, or INVALID_HANDLE_VALUE.
+ * Returns the new handle, or INVALID_HANDLE_VALUE.
* If an existing channel is specified it is closed and reopened.
*
* Side effects:
@@ -1402,7 +1427,7 @@ SerialWriterThread(
HANDLE
TclWinSerialOpen(
HANDLE handle,
- const WCHAR *name,
+ CONST TCHAR *name,
DWORD access)
{
SerialInit();
@@ -1411,7 +1436,7 @@ TclWinSerialOpen(
* If an open channel is specified, close it
*/
- if (handle != INVALID_HANDLE_VALUE && CloseHandle(handle) == FALSE) {
+ if ( handle != INVALID_HANDLE_VALUE && CloseHandle(handle) == FALSE) {
return INVALID_HANDLE_VALUE;
}
@@ -1421,8 +1446,8 @@ TclWinSerialOpen(
* finished
*/
- handle = CreateFileW(name, access, 0, 0, OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED, 0);
+ handle = (*tclWinProcs->createFileProc)(name, access, 0, 0,
+ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
return handle;
}
@@ -1452,13 +1477,14 @@ TclWinOpenSerialChannel(
int permissions)
{
SerialInfo *infoPtr;
+ DWORD id;
SerialInit();
- infoPtr = (SerialInfo *)ckalloc(sizeof(SerialInfo));
+ infoPtr = (SerialInfo *) ckalloc((unsigned) sizeof(SerialInfo));
memset(infoPtr, 0, sizeof(SerialInfo));
- infoPtr->validMask = permissions & (TCL_READABLE|TCL_WRITABLE);
+ infoPtr->validMask = permissions;
infoPtr->handle = handle;
infoPtr->channel = (Tcl_Channel) NULL;
infoPtr->readable = 0;
@@ -1476,9 +1502,10 @@ TclWinOpenSerialChannel(
* are shared between multiple channels (stdin/stdout).
*/
- TclWinGenerateChannelName(channelName, "file", infoPtr);
+ sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t)infoPtr);
+
infoPtr->channel = Tcl_CreateChannel(&serialChannelType, channelName,
- infoPtr, permissions);
+ (ClientData) infoPtr, permissions);
SetupComm(handle, infoPtr->sysBufRead, infoPtr->sysBufWrite);
@@ -1493,18 +1520,19 @@ TclWinOpenSerialChannel(
InitializeCriticalSection(&infoPtr->csWrite);
if (permissions & TCL_READABLE) {
- infoPtr->osRead.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+ infoPtr->osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
if (permissions & TCL_WRITABLE) {
/*
* Initially the channel is writable and the writeThread is idle.
*/
- infoPtr->osWrite.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
- infoPtr->evWritable = CreateEventW(NULL, TRUE, TRUE, NULL);
+ infoPtr->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ infoPtr->evWritable = CreateEvent(NULL, TRUE, TRUE, NULL);
+ infoPtr->evStartWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
+ infoPtr->evStopWriter = CreateEvent(NULL, FALSE, FALSE, NULL);
infoPtr->writeThread = CreateThread(NULL, 256, SerialWriterThread,
- TclPipeThreadCreateTI(&infoPtr->writeTI, infoPtr,
- infoPtr->evWritable), 0, NULL);
+ infoPtr, 0, &id);
}
/*
@@ -1513,7 +1541,7 @@ TclWinOpenSerialChannel(
*/
Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto");
- Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\x1A {}");
+ Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}");
return infoPtr->channel;
}
@@ -1563,7 +1591,7 @@ SerialErrorStr(
if (error & ~((DWORD) (SERIAL_READ_ERRORS | SERIAL_WRITE_ERRORS))) {
char buf[TCL_INTEGER_SPACE + 1];
- snprintf(buf, sizeof(buf), "%ld", error);
+ wsprintfA(buf, "%d", error);
Tcl_DStringAppendElement(dsPtr, buf);
}
}
@@ -1618,19 +1646,19 @@ SerialModemStatusStr(
static int
SerialSetOptionProc(
- void *instanceData, /* File state. */
+ ClientData instanceData, /* File state. */
Tcl_Interp *interp, /* For error reporting - can be NULL. */
- const char *optionName, /* Which option to set? */
- const char *value) /* New value for option. */
+ CONST char *optionName, /* Which option to set? */
+ CONST char *value) /* New value for option. */
{
SerialInfo *infoPtr;
DCB dcb;
BOOL result, flag;
size_t len, vlen;
Tcl_DString ds;
- const WCHAR *native;
- Tcl_Size argc;
- const char **argv;
+ CONST TCHAR *native;
+ int argc;
+ CONST char **argv;
infoPtr = (SerialInfo *) instanceData;
@@ -1643,50 +1671,24 @@ SerialSetOptionProc(
vlen = strlen(value);
/*
- * Option -closemode drain|discard|default
- */
-
- if ((len > 2) && (strncmp(optionName, "-closemode", len) == 0)) {
- if (strncasecmp(value, "DEFAULT", vlen) == 0) {
- infoPtr->flags &= ~SERIAL_CLOSE_MASK;
- } else if (strncasecmp(value, "DRAIN", vlen) == 0) {
- infoPtr->flags &= ~SERIAL_CLOSE_MASK;
- infoPtr->flags |= SERIAL_CLOSE_DRAIN;
- } else if (strncasecmp(value, "DISCARD", vlen) == 0) {
- infoPtr->flags &= ~SERIAL_CLOSE_MASK;
- infoPtr->flags |= SERIAL_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", (char *)NULL);
- }
- return TCL_ERROR;
- }
- return TCL_OK;
- }
-
- /*
* Option -mode baud,parity,databits,stopbits
*/
if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) {
if (!GetCommState(infoPtr->handle, &dcb)) {
- goto getStateFailed;
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "can't get comm state", NULL);
+ }
+ return TCL_ERROR;
}
- Tcl_DStringInit(&ds);
- native = Tcl_UtfToWCharDString(value, TCL_INDEX_NONE, &ds);
- result = BuildCommDCBW(native, &dcb);
+ native = Tcl_WinUtfToTChar(value, -1, &ds);
+ result = (*tclWinProcs->buildCommDCBProc)(native, &dcb);
Tcl_DStringFree(&ds);
if (result == FALSE) {
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "bad value \"%s\" for -mode: should be baud,parity,data,stop",
- value));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", (char *)NULL);
+ Tcl_AppendResult(interp, "bad value \"", value,
+ "\" for -mode: should be baud,parity,data,stop", NULL);
}
return TCL_ERROR;
}
@@ -1701,7 +1703,10 @@ SerialSetOptionProc(
dcb.fAbortOnError = FALSE;
if (!SetCommState(infoPtr->handle, &dcb)) {
- goto setStateFailed;
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "can't set comm state", NULL);
+ }
+ return TCL_ERROR;
}
return TCL_OK;
}
@@ -1712,7 +1717,10 @@ SerialSetOptionProc(
if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) {
if (!GetCommState(infoPtr->handle, &dcb)) {
- goto getStateFailed;
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "can't get comm state", NULL);
+ }
+ return TCL_ERROR;
}
/*
@@ -1747,16 +1755,18 @@ SerialSetOptionProc(
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
} else {
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "bad value \"%s\" for -handshake: must be one of"
- " xonxoff, rtscts, dtrdsr or none", value));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "HANDSHAKE", (char *)NULL);
+ Tcl_AppendResult(interp, "bad value \"", value,
+ "\" for -handshake: must be one of xonxoff, rtscts, "
+ "dtrdsr or none", NULL);
}
return TCL_ERROR;
}
if (!SetCommState(infoPtr->handle, &dcb)) {
- goto setStateFailed;
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "can't set comm state", NULL);
+ }
+ return TCL_ERROR;
}
return TCL_OK;
}
@@ -1767,7 +1777,10 @@ SerialSetOptionProc(
if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) {
if (!GetCommState(infoPtr->handle, &dcb)) {
- goto getStateFailed;
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "can't get comm state", NULL);
+ }
+ return TCL_ERROR;
}
if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
@@ -1776,12 +1789,11 @@ SerialSetOptionProc(
if (argc != 2) {
badXchar:
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "bad value for -xchar: should be a list of"
- " two elements with each a single 8-bit character", TCL_INDEX_NONE));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "XCHAR", (char *)NULL);
+ Tcl_AppendResult(interp, "bad value for -xchar: should be "
+ "a list of two elements with each a single character",
+ NULL);
}
- ckfree(argv);
+ ckfree((char *) argv);
return TCL_ERROR;
}
@@ -1798,24 +1810,27 @@ SerialSetOptionProc(
dcb.XonChar = argv[0][0];
dcb.XoffChar = argv[1][0];
if (argv[0][0] & 0x80 || argv[1][0] & 0x80) {
- Tcl_UniChar character = 0;
+ Tcl_UniChar character;
int charLen;
- charLen = TclUtfToUniChar(argv[0], &character);
- if ((character > 0xFF) || argv[0][charLen]) {
+ charLen = Tcl_UtfToUniChar(argv[0], &character);
+ if (argv[0][charLen]) {
goto badXchar;
}
dcb.XonChar = (char) character;
- charLen = TclUtfToUniChar(argv[1], &character);
- if ((character > 0xFF) || argv[1][charLen]) {
+ charLen = Tcl_UtfToUniChar(argv[1], &character);
+ if (argv[1][charLen]) {
goto badXchar;
}
dcb.XoffChar = (char) character;
}
- ckfree(argv);
+ ckfree((char *) argv);
if (!SetCommState(infoPtr->handle, &dcb)) {
- goto setStateFailed;
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "can't set comm state", NULL);
+ }
+ return TCL_ERROR;
}
return TCL_OK;
}
@@ -1825,79 +1840,66 @@ SerialSetOptionProc(
*/
if ((len > 4) && (strncmp(optionName, "-ttycontrol", len) == 0)) {
- Tcl_Size i;
- int res = TCL_OK;
+ int i, result = TCL_OK;
if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
return TCL_ERROR;
}
if ((argc % 2) == 1) {
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "bad value \"%s\" for -ttycontrol: should be "
- "a list of signal,value pairs", value));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTYCONTROL", (char *)NULL);
+ Tcl_AppendResult(interp, "bad value \"", value,
+ "\" for -ttycontrol: should be a list of "
+ "signal,value pairs", NULL);
}
- ckfree(argv);
+ ckfree((char *) argv);
return TCL_ERROR;
}
for (i = 0; i < argc - 1; i += 2) {
if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) {
- res = TCL_ERROR;
+ result = TCL_ERROR;
break;
}
if (strncasecmp(argv[i], "DTR", strlen(argv[i])) == 0) {
if (!EscapeCommFunction(infoPtr->handle,
(DWORD) (flag ? SETDTR : CLRDTR))) {
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "can't set DTR signal", TCL_INDEX_NONE));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION",
- "FCONFIGURE", "TTY_SIGNAL", (char *)NULL);
+ Tcl_AppendResult(interp, "can't set DTR signal", NULL);
}
- res = TCL_ERROR;
+ result = TCL_ERROR;
break;
}
} else if (strncasecmp(argv[i], "RTS", strlen(argv[i])) == 0) {
if (!EscapeCommFunction(infoPtr->handle,
(DWORD) (flag ? SETRTS : CLRRTS))) {
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "can't set RTS signal", TCL_INDEX_NONE));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION",
- "FCONFIGURE", "TTY_SIGNAL", (char *)NULL);
+ Tcl_AppendResult(interp, "can't set RTS signal", NULL);
}
- res = TCL_ERROR;
+ result = TCL_ERROR;
break;
}
} else if (strncasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) {
if (!EscapeCommFunction(infoPtr->handle,
(DWORD) (flag ? SETBREAK : CLRBREAK))) {
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "can't set BREAK signal", TCL_INDEX_NONE));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION",
- "FCONFIGURE", "TTY_SIGNAL", (char *)NULL);
+ Tcl_AppendResult(interp,"can't set BREAK signal",NULL);
}
- res = TCL_ERROR;
+ result = TCL_ERROR;
break;
}
} else {
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "bad signal name \"%s\" for -ttycontrol: must be"
- " DTR, RTS or BREAK", argv[i]));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTY_SIGNAL",
- (char *)NULL);
+ Tcl_AppendResult(interp, "bad signal name \"", argv[i],
+ "\" for -ttycontrol: must be DTR, RTS or BREAK",
+ NULL);
}
- res = TCL_ERROR;
+ result = TCL_ERROR;
break;
}
}
- ckfree(argv);
- return res;
+ ckfree((char *) argv);
+ return result;
}
/*
@@ -1910,7 +1912,7 @@ SerialSetOptionProc(
* -sysbuffer 4096 or -sysbuffer {64536 4096}
*/
- int inSize = -1, outSize = -1;
+ size_t inSize = (size_t) -1, outSize = (size_t) -1;
if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
return TCL_ERROR;
@@ -1922,24 +1924,20 @@ SerialSetOptionProc(
inSize = atoi(argv[0]);
outSize = atoi(argv[1]);
}
- ckfree(argv);
+ ckfree((char *) argv);
if ((argc < 1) || (argc > 2) || (inSize <= 0) || (outSize <= 0)) {
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "bad value \"%s\" for -sysbuffer: should be "
- "a list of one or two integers > 0", value));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "SYS_BUFFER", (char *)NULL);
+ Tcl_AppendResult(interp, "bad value \"", value,
+ "\" for -sysbuffer: should be a list of one or two "
+ "integers > 0", NULL);
}
return TCL_ERROR;
}
if (!SetupComm(infoPtr->handle, inSize, outSize)) {
if (interp != NULL) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't setup comm buffers: %s",
- Tcl_PosixError(interp)));
+ Tcl_AppendResult(interp, "can't setup comm buffers", NULL);
}
return TCL_ERROR;
}
@@ -1952,12 +1950,18 @@ SerialSetOptionProc(
*/
if (!GetCommState(infoPtr->handle, &dcb)) {
- goto getStateFailed;
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "can't get comm state", NULL);
+ }
+ return TCL_ERROR;
}
dcb.XonLim = (WORD) (infoPtr->sysBufRead*1/2);
dcb.XoffLim = (WORD) (infoPtr->sysBufRead*1/4);
if (!SetCommState(infoPtr->handle, &dcb)) {
- goto setStateFailed;
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "can't set comm state", NULL);
+ }
+ return TCL_ERROR;
}
return TCL_OK;
}
@@ -1987,10 +1991,7 @@ SerialSetOptionProc(
tout.ReadTotalTimeoutConstant = msec;
if (!SetCommTimeouts(infoPtr->handle, &tout)) {
if (interp != NULL) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't set comm timeouts: %s",
- Tcl_PosixError(interp)));
+ Tcl_AppendResult(interp, "can't set comm timeouts", NULL);
}
return TCL_ERROR;
}
@@ -1999,24 +2000,7 @@ SerialSetOptionProc(
}
return Tcl_BadChannelOption(interp, optionName,
- "closemode mode handshake pollinterval sysbuffer timeout "
- "ttycontrol xchar");
-
- getStateFailed:
- if (interp != NULL) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't get comm state: %s", Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
-
- setStateFailed:
- if (interp != NULL) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't set comm state: %s", Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
+ "mode handshake pollinterval sysbuffer timeout ttycontrol xchar");
}
/*
@@ -2042,9 +2026,9 @@ SerialSetOptionProc(
static int
SerialGetOptionProc(
- void *instanceData, /* File state. */
+ ClientData instanceData, /* File state. */
Tcl_Interp *interp, /* For error reporting - can be NULL. */
- const char *optionName, /* Option to get. */
+ CONST char *optionName, /* Option to get. */
Tcl_DString *dsPtr) /* Where to store value(s). */
{
SerialInfo *infoPtr;
@@ -2061,27 +2045,6 @@ SerialGetOptionProc(
}
/*
- * Get option -closemode
- */
-
- if (len == 0) {
- Tcl_DStringAppendElement(dsPtr, "-closemode");
- }
- if (len==0 || (len>1 && strncmp(optionName, "-closemode", len)==0)) {
- switch (infoPtr->flags & SERIAL_CLOSE_MASK) {
- case SERIAL_CLOSE_DRAIN:
- Tcl_DStringAppendElement(dsPtr, "drain");
- break;
- case SERIAL_CLOSE_DISCARD:
- Tcl_DStringAppendElement(dsPtr, "discard");
- break;
- default:
- Tcl_DStringAppendElement(dsPtr, "default");
- break;
- }
- }
-
- /*
* Get option -mode
*/
@@ -2090,14 +2053,12 @@ SerialGetOptionProc(
}
if (len==0 || (len>2 && (strncmp(optionName, "-mode", len) == 0))) {
char parity;
- const char *stop;
+ char *stop;
char buf[2 * TCL_INTEGER_SPACE + 16];
if (!GetCommState(infoPtr->handle, &dcb)) {
if (interp != NULL) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't get comm state: %s", Tcl_PosixError(interp)));
+ Tcl_AppendResult(interp, "can't get comm state", NULL);
}
return TCL_ERROR;
}
@@ -2110,7 +2071,7 @@ SerialGetOptionProc(
stop = (dcb.StopBits == ONESTOPBIT) ? "1" :
(dcb.StopBits == ONE5STOPBITS) ? "1.5" : "2";
- snprintf(buf, sizeof(buf), "%ld,%c,%d,%s", dcb.BaudRate, parity,
+ wsprintfA(buf, "%d,%c,%d,%s", dcb.BaudRate, parity,
dcb.ByteSize, stop);
Tcl_DStringAppendElement(dsPtr, buf);
}
@@ -2126,7 +2087,7 @@ SerialGetOptionProc(
char buf[TCL_INTEGER_SPACE + 1];
valid = 1;
- snprintf(buf, sizeof(buf), "%d", infoPtr->blockTime);
+ wsprintfA(buf, "%d", infoPtr->blockTime);
Tcl_DStringAppendElement(dsPtr, buf);
}
@@ -2142,9 +2103,9 @@ SerialGetOptionProc(
char buf[TCL_INTEGER_SPACE + 1];
valid = 1;
- snprintf(buf, sizeof(buf), "%ld", infoPtr->sysBufRead);
+ wsprintfA(buf, "%d", infoPtr->sysBufRead);
Tcl_DStringAppendElement(dsPtr, buf);
- snprintf(buf, sizeof(buf), "%ld", infoPtr->sysBufWrite);
+ wsprintfA(buf, "%d", infoPtr->sysBufWrite);
Tcl_DStringAppendElement(dsPtr, buf);
}
if (len == 0) {
@@ -2165,15 +2126,13 @@ SerialGetOptionProc(
if (!GetCommState(infoPtr->handle, &dcb)) {
if (interp != NULL) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't get comm state: %s", Tcl_PosixError(interp)));
+ Tcl_AppendResult(interp, "can't get comm state", NULL);
}
return TCL_ERROR;
}
- buf[Tcl_UniCharToUtf(UCHAR(dcb.XonChar), buf)] = '\0';
+ sprintf(buf, "%c", dcb.XonChar);
Tcl_DStringAppendElement(dsPtr, buf);
- buf[Tcl_UniCharToUtf(UCHAR(dcb.XoffChar), buf)] = '\0';
+ sprintf(buf, "%c", dcb.XoffChar);
Tcl_DStringAppendElement(dsPtr, buf);
}
if (len == 0) {
@@ -2225,9 +2184,9 @@ SerialGetOptionProc(
count = (int) cStat.cbOutQue + infoPtr->writeQueue;
LeaveCriticalSection(&infoPtr->csWrite);
- snprintf(buf, sizeof(buf), "%ld", inBuffered + cStat.cbInQue);
+ wsprintfA(buf, "%d", inBuffered + cStat.cbInQue);
Tcl_DStringAppendElement(dsPtr, buf);
- snprintf(buf, sizeof(buf), "%d", outBuffered + count);
+ wsprintfA(buf, "%d", outBuffered + count);
Tcl_DStringAppendElement(dsPtr, buf);
}
@@ -2243,9 +2202,7 @@ SerialGetOptionProc(
if (!GetCommModemStatus(infoPtr->handle, &status)) {
if (interp != NULL) {
- Tcl_WinConvertError(GetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't get tty status: %s", Tcl_PosixError(interp)));
+ Tcl_AppendResult(interp, "can't get tty status", NULL);
}
return TCL_ERROR;
}
@@ -2255,10 +2212,10 @@ SerialGetOptionProc(
if (valid) {
return TCL_OK;
+ } else {
+ return Tcl_BadChannelOption(interp, optionName,
+ "mode pollinterval lasterror queue sysbuffer ttystatus xchar");
}
- return Tcl_BadChannelOption(interp, optionName,
- "closemode mode pollinterval lasterror queue sysbuffer ttystatus "
- "xchar");
}
/*
@@ -2279,7 +2236,7 @@ SerialGetOptionProc(
static void
SerialThreadActionProc(
- void *instanceData,
+ ClientData instanceData,
int action)
{
SerialInfo *infoPtr = (SerialInfo *) instanceData;
@@ -2287,7 +2244,7 @@ SerialThreadActionProc(
/*
* We do not access firstSerialPtr in the thread structures. This is not
* for all serials managed by the thread, but only those we are watching.
- * Removal of the fileevent handlers before transfer thus takes care of
+ * Removal of the filevent handlers before transfer thus takes care of
* this structure.
*/
diff --git a/win/tclWinSock.c b/win/tclWinSock.c
index 0dd7871..8f565b9 100644
--- a/win/tclWinSock.c
+++ b/win/tclWinSock.c
@@ -3,15 +3,12 @@
*
* This file contains Windows-specific socket related code.
*
- * Copyright © 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* -----------------------------------------------------------------------
- * The order and naming of functions in this file should minimize
- * the file diff to tclUnixSock.c.
- * -----------------------------------------------------------------------
*
* General information on how this module works.
*
@@ -55,17 +52,20 @@
#endif
/*
- * 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.
+ * Support for control over sockets' KEEPALIVE and NODELAY behavior is
+ * currently disabled.
*/
-#define SET_BITS(var, bits) ((var) |= (bits))
-#define CLEAR_BITS(var, bits) ((var) &= ~(bits))
-#define GOT_BITS(var, bits) (((var) & (bits)) != 0)
+#undef TCL_FEATURE_KEEPALIVE_NAGLE
+
+/*
+ * Make sure to remove the redirection defines set in tclWinPort.h that is in
+ * use in other sections of the core, except for us.
+ */
-/* "sock" + a pointer in hex + \0 */
-#define SOCK_CHAN_LENGTH (16 + TCL_INTEGER_SPACE)
+#undef getservbyname
+#undef getsockopt
+#undef setsockopt
/*
* The following variable is used to tell whether this module has been
@@ -74,111 +74,58 @@
*/
static int initialized = 0;
-static const WCHAR className[] = L"TclSocket";
TCL_DECLARE_MUTEX(socketMutex)
/*
- * The following defines declare the messages used on socket windows.
+ * The following variable holds the network name of this host.
*/
-#define SOCKET_MESSAGE WM_USER+1
-#define SOCKET_SELECT WM_USER+2
-#define SOCKET_TERMINATE WM_USER+3
-#define SELECT TRUE
-#define UNSELECT FALSE
+static TclInitProcessGlobalValueProc InitializeHostName;
+static ProcessGlobalValue hostName = {
+ 0, 0, NULL, NULL, InitializeHostName, NULL, NULL
+};
/*
- * This is needed to comply with the strict aliasing rules of GCC, but it also
- * simplifies casting between the different sockaddr types.
+ * The following defines declare the messages used on socket windows.
*/
-typedef union {
- struct sockaddr sa;
- struct sockaddr_in sa4;
- struct sockaddr_in6 sa6;
- struct sockaddr_storage sas;
-} address;
-
-#ifndef IN6_ARE_ADDR_EQUAL
-#define IN6_ARE_ADDR_EQUAL IN6_ADDR_EQUAL
-#endif
+#define SOCKET_MESSAGE WM_USER+1
+#define SOCKET_SELECT WM_USER+2
+#define SOCKET_TERMINATE WM_USER+3
+#define SELECT TRUE
+#define UNSELECT FALSE
/*
- * This structure describes per-instance state of a tcp-based channel.
+ * The following structure is used to store the data associated with each
+ * socket.
+ * All members modified by the notifier thread are defined as volatile.
*/
-typedef struct TcpState TcpState;
-
-typedef struct TcpFdList {
- TcpState *statePtr;
- SOCKET fd;
- struct TcpFdList *next;
-} TcpFdList;
-
-struct TcpState {
+typedef struct SocketInfo {
Tcl_Channel channel; /* Channel associated with this socket. */
- int flags; /* Bit field comprised of the flags described
+ SOCKET socket; /* Windows SOCKET handle. */
+ volatile int flags; /* Bit field comprised of the flags described
* below. */
- struct TcpFdList *sockets; /* Windows SOCKET handle. */
int watchEvents; /* OR'ed combination of FD_READ, FD_WRITE,
* FD_CLOSE, FD_ACCEPT and FD_CONNECT that
* indicate which events are interesting. */
volatile int readyEvents; /* OR'ed combination of FD_READ, FD_WRITE,
* FD_CLOSE, FD_ACCEPT and FD_CONNECT that
- * indicate which events have occurred.
- * Set by notifier thread, access must be
- * protected by semaphore */
+ * indicate which events have occurred. */
int selectEvents; /* OR'ed combination of FD_READ, FD_WRITE,
* FD_CLOSE, FD_ACCEPT and FD_CONNECT that
* indicate which events are currently being
* selected. */
volatile int acceptEventCount;
/* Count of the current number of FD_ACCEPTs
- * that have arrived and not yet processed.
- * Set by notifier thread, access must be
- * protected by semaphore */
+ * that have arrived and not yet processed. */
Tcl_TcpAcceptProc *acceptProc;
/* Proc to call on accept. */
- void *acceptProcData; /* The data for the accept proc. */
-
- /*
- * Only needed for client sockets
- */
-
- struct addrinfo *addrlist; /* Addresses to connect to. */
- struct addrinfo *addr; /* Iterator over addrlist. */
- struct addrinfo *myaddrlist;/* Local address. */
- struct addrinfo *myaddr; /* Iterator over myaddrlist. */
- int connectError; /* Cache status of async socket. */
- int cachedBlocking; /* Cache blocking mode of async socket. */
- volatile int notifierConnectError;
- /* Async connect error set by notifier thread.
- * This error is still a windows error code.
- * Access must be protected by semaphore */
- struct TcpState *nextPtr; /* The next socket on the per-thread socket
+ ClientData acceptProcData; /* The data for the accept proc. */
+ volatile int lastError; /* Error code from last message. */
+ struct SocketInfo *nextPtr; /* The next socket on the per-thread socket
* list. */
-};
-
-/*
- * These bits may be OR'ed together into the "flags" field of a TcpState
- * structure.
- */
-
-#define TCP_NONBLOCKING (1<<0) /* Socket with non-blocking I/O */
-#define TCP_ASYNC_CONNECT (1<<1) /* Async connect in progress. */
-#define SOCKET_EOF (1<<2) /* A zero read happened on the
- * socket. */
-#define SOCKET_PENDING (1<<3) /* A message has been sent for this
- * socket */
-#define TCP_ASYNC_PENDING (1<<4) /* TcpConnect was called to
- * process an async connect. This
- * flag indicates that reentry is
- * still pending */
-#define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */
-
-#define TCP_ASYNC_TEST_MODE (1<<8) /* Async testing activated. Do not
- * automatically continue connection
- * process */
+} SocketInfo;
/*
* The following structure is what is added to the Tcl event queue when a
@@ -189,8 +136,8 @@ typedef struct {
Tcl_Event header; /* Information that is standard for all
* events. */
SOCKET socket; /* Socket descriptor that is ready. Used to
- * find the TcpState structure for the file
- * (can't point directly to the TcpState
+ * find the SocketInfo structure for the file
+ * (can't point directly to the SocketInfo
* structure because it could go away while
* the event is queued). */
} SocketEvent;
@@ -201,6 +148,17 @@ typedef struct {
#define TCP_BUFFER_SIZE 4096
+/*
+ * The following macros may be used to set the flags field of a SocketInfo
+ * structure.
+ */
+
+#define SOCKET_ASYNC (1<<0) /* The socket is in blocking mode. */
+#define SOCKET_EOF (1<<1) /* A zero read happened on the
+ * socket. */
+#define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async connect. */
+#define SOCKET_PENDING (1<<3) /* A message has been sent for this
+ * socket */
typedef struct {
HWND hwnd; /* Handle to window for socket messages. */
@@ -211,44 +169,44 @@ typedef struct {
* socketThread has been initialized and has
* started. */
HANDLE socketListLock; /* Win32 Event to lock the socketList */
- TcpState *pendingTcpState;
+ SocketInfo *pendingSocketInfo;
/* This socket is opened but not jet in the
* list. This value is also checked by
* the event structure. */
- TcpState *socketList; /* Every open socket in this thread has an
+ SocketInfo *socketList; /* Every open socket in this thread has an
* entry on this list. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
-static WNDCLASSW windowClass;
+static WNDCLASS windowClass;
/*
- * Static routines for this file:
+ * Static functions defined in this file.
*/
-static int TcpConnect(Tcl_Interp *interp,
- TcpState *state);
-static void InitSocketWindowClass(void);
-static TcpState * NewSocketInfo(SOCKET socket);
-static void SocketExitHandler(void *clientData);
+static SocketInfo * CreateSocket(Tcl_Interp *interp, int port,
+ const char *host, int server, const char *myaddr,
+ int myport, int async);
+static int CreateSocketAddress(LPSOCKADDR_IN sockaddrPtr,
+ const char *host, int port);
+static void InitSockets(void);
+static SocketInfo * NewSocketInfo(SOCKET socket);
+static void SocketExitHandler(ClientData clientData);
static LRESULT CALLBACK SocketProc(HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam);
-static void TcpAccept(TcpFdList *fds, SOCKET newSocket, address addr);
-static int WaitForConnect(TcpState *statePtr, int *errorCodePtr);
-static int WaitForSocketEvent(TcpState *statePtr, int events,
+static int SocketsEnabled(void);
+static void TcpAccept(SocketInfo *infoPtr);
+static int WaitForSocketEvent(SocketInfo *infoPtr, int events,
int *errorCodePtr);
-static void AddSocketInfoFd(TcpState *statePtr, SOCKET socket);
-static int FindFDInList(TcpState *statePtr, SOCKET socket);
static DWORD WINAPI SocketThread(LPVOID arg);
-static void TcpThreadActionProc(void *instanceData,
+static void TcpThreadActionProc(ClientData instanceData,
int action);
static Tcl_EventCheckProc SocketCheckProc;
static Tcl_EventProc SocketEventProc;
static Tcl_EventSetupProc SocketSetupProc;
-static Tcl_DriverBlockModeProc TcpBlockModeProc;
+static Tcl_DriverBlockModeProc TcpBlockProc;
static Tcl_DriverCloseProc TcpCloseProc;
-static Tcl_DriverClose2Proc TcpClose2Proc;
static Tcl_DriverSetOptionProc TcpSetOptionProc;
static Tcl_DriverGetOptionProc TcpGetOptionProc;
static Tcl_DriverInputProc TcpInputProc;
@@ -258,235 +216,192 @@ static Tcl_DriverGetHandleProc TcpGetHandleProc;
/*
* This structure describes the channel type structure for TCP socket
- * based IO:
+ * based IO.
*/
-static const Tcl_ChannelType tcpChannelType = {
- "tcp", /* Type name. */
- TCL_CHANNEL_VERSION_5, /* v5 channel */
-#ifndef TCL_NO_DEPRECATED
- TcpCloseProc, /* Close proc. */
-#else
- TCL_CLOSE2PROC, /* Close proc. */
-#endif
- TcpInputProc, /* Input proc. */
- TcpOutputProc, /* Output proc. */
- NULL, /* Seek proc. */
- TcpSetOptionProc, /* Set option proc. */
- TcpGetOptionProc, /* Get option proc. */
- TcpWatchProc, /* Initialize notifier. */
- TcpGetHandleProc, /* Get OS handles out of channel. */
- TcpClose2Proc, /* Close2 proc. */
- TcpBlockModeProc, /* Set blocking or non-blocking mode.*/
- NULL, /* flush proc. */
- NULL, /* handler proc. */
- NULL, /* wide seek proc. */
- TcpThreadActionProc, /* thread action proc. */
- NULL /* truncate proc. */
+static Tcl_ChannelType tcpChannelType = {
+ "tcp", /* Type name. */
+ TCL_CHANNEL_VERSION_5, /* v5 channel */
+ TcpCloseProc, /* Close proc. */
+ TcpInputProc, /* Input proc. */
+ TcpOutputProc, /* Output proc. */
+ NULL, /* Seek proc. */
+ TcpSetOptionProc, /* Set option proc. */
+ TcpGetOptionProc, /* Get option proc. */
+ TcpWatchProc, /* Set up notifier to watch this channel. */
+ TcpGetHandleProc, /* Get an OS handle from channel. */
+ NULL, /* close2proc. */
+ TcpBlockProc, /* Set socket into (non-)blocking mode. */
+ NULL, /* flush proc. */
+ NULL, /* handler proc. */
+ NULL, /* wide seek proc */
+ TcpThreadActionProc, /* thread action proc */
+ NULL, /* truncate */
};
-
-/*
- * The following variable holds the network name of this host.
- */
-
-static TclInitProcessGlobalValueProc InitializeHostName;
-static ProcessGlobalValue hostName =
- {0, 0, NULL, NULL, InitializeHostName, NULL, NULL};
-
-/*
- * Simple wrapper round the SendMessage syscall.
- */
-
-#define SendSelectMessage(tsdPtr, message, payload) \
- SendMessageW((tsdPtr)->hwnd, SOCKET_SELECT, \
- (WPARAM) (message), (LPARAM) (payload))
-
-
-/*
- * Address print debug functions
- */
-#if 0
-void
-printaddrinfo(
- struct addrinfo *ai,
- char *prefix)
-{
- char host[NI_MAXHOST], port[NI_MAXSERV];
-
- getnameinfo(ai->ai_addr, ai->ai_addrlen,
- host, sizeof(host), port, sizeof(port),
- NI_NUMERICHOST|NI_NUMERICSERV);
-}
-
-void
-printaddrinfolist(
- struct addrinfo *addrlist,
- char *prefix)
-{
- struct addrinfo *ai;
-
- for (ai = addrlist; ai != NULL; ai = ai->ai_next) {
- printaddrinfo(ai, prefix);
- }
-}
-#endif
/*
*----------------------------------------------------------------------
*
- * InitializeHostName --
+ * InitSockets --
*
- * This routine sets the process global value of the name of the local
- * host on which the process is running.
+ * Initialize the socket module. If winsock startup is successful,
+ * registers the event window for the socket notifier code.
+ *
+ * Assumes socketMutex is held.
*
* Results:
* None.
*
+ * Side effects:
+ * Initializes winsock, registers a new window class and creates a
+ * window for use in asynchronous socket notification.
+ *
*----------------------------------------------------------------------
*/
-void
-InitializeHostName(
- char **valuePtr,
- TCL_HASH_TYPE *lengthPtr,
- Tcl_Encoding *encodingPtr)
+static void
+InitSockets(void)
{
- WCHAR wbuf[256];
- DWORD length = sizeof(wbuf)/sizeof(WCHAR);
- Tcl_DString ds;
+ DWORD id;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ TclThreadDataKeyGet(&dataKey);
+
+ if (!initialized) {
+ initialized = 1;
+ TclCreateLateExitHandler(SocketExitHandler, (ClientData) NULL);
- Tcl_DStringInit(&ds);
- if (GetComputerNameExW(ComputerNamePhysicalDnsFullyQualified, wbuf, &length) != 0) {
/*
- * Convert string from native to UTF then change to lowercase.
+ * Create the async notification window with a new class. We must
+ * create a new class to avoid a Windows 95 bug that causes us to get
+ * the wrong message number for socket events if the message window is
+ * a subclass of a static control.
*/
- Tcl_UtfToLower(Tcl_WCharToUtfDString(wbuf, TCL_INDEX_NONE, &ds));
+ windowClass.style = 0;
+ windowClass.cbClsExtra = 0;
+ windowClass.cbWndExtra = 0;
+ windowClass.hInstance = TclWinGetTclInstance();
+ windowClass.hbrBackground = NULL;
+ windowClass.lpszMenuName = NULL;
+ windowClass.lpszClassName = "TclSocket";
+ windowClass.lpfnWndProc = SocketProc;
+ windowClass.hIcon = NULL;
+ windowClass.hCursor = NULL;
+
+ if (!RegisterClassA(&windowClass)) {
+ TclWinConvertError(GetLastError());
+ goto initFailure;
+ }
+
+ }
+
+ /*
+ * Check for per-thread initialization.
+ */
+
+ if (tsdPtr == NULL) {
+ tsdPtr = TCL_TSD_INIT(&dataKey);
+ tsdPtr->pendingSocketInfo = NULL;
+ tsdPtr->socketList = NULL;
+ tsdPtr->hwnd = NULL;
+ tsdPtr->threadId = Tcl_GetCurrentThread();
+ tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (tsdPtr->readyEvent == NULL) {
+ goto initFailure;
+ }
+ tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
+ if (tsdPtr->socketListLock == NULL) {
+ goto initFailure;
+ }
+ tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr,
+ 0, &id);
+ if (tsdPtr->socketThread == NULL) {
+ goto initFailure;
+ }
+
+ SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
- } else {
- TclInitSockets();
/*
- * The buffer size of 256 is recommended by the MSDN page that
- * documents gethostname() as being always adequate.
+ * Wait for the thread to signal when the window has been created and
+ * if it is ready to go.
*/
- Tcl_DString inDs;
+ WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
- Tcl_DStringInit(&inDs);
- Tcl_DStringSetLength(&inDs, 256);
- if (gethostname(Tcl_DStringValue(&inDs),
- Tcl_DStringLength(&inDs)) == 0) {
- Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&inDs),
- TCL_INDEX_NONE, &ds);
+ if (tsdPtr->hwnd == NULL) {
+ goto initFailure; /* Trouble creating the window */
}
- Tcl_DStringFree(&inDs);
+
+ Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
}
+ return;
- *encodingPtr = Tcl_GetEncoding(NULL, "utf-8");
- *lengthPtr = Tcl_DStringLength(&ds);
- *valuePtr = (char *)ckalloc(*lengthPtr + 1);
- memcpy(*valuePtr, Tcl_DStringValue(&ds), *lengthPtr + 1);
- Tcl_DStringFree(&ds);
+ initFailure:
+ TclpFinalizeSockets();
+ initialized = -1;
+ return;
}
/*
*----------------------------------------------------------------------
*
- * Tcl_GetHostName --
+ * SocketsEnabled --
*
- * Returns the name of the local host.
+ * Check that the WinSock was successfully initialized.
*
* Results:
- * A string containing the network name for this machine, or an empty
- * string if we can't figure out the name. The caller must not modify or
- * free this string.
+ * 1 if it is.
*
* Side effects:
- * Caches the name to return for future calls.
+ * None.
*
*----------------------------------------------------------------------
*/
-const char *
-Tcl_GetHostName(void)
+ /* ARGSUSED */
+static int
+SocketsEnabled(void)
{
- return Tcl_GetString(TclGetProcessGlobalValue(&hostName));
+ int enabled;
+ Tcl_MutexLock(&socketMutex);
+ enabled = (initialized == 1);
+ Tcl_MutexUnlock(&socketMutex);
+ return enabled;
}
+
/*
*----------------------------------------------------------------------
*
- * TclInitSockets --
+ * SocketExitHandler --
*
- * Initialization of sockets for the thread. Also creates message
- * handling window class for the process if needed.
+ * Callback invoked during exit clean up to delete the socket
+ * communication window and to release the WinSock DLL.
*
* Results:
- * Nothing. Panics on failure.
+ * None.
*
* Side effects:
- * If not already prepared, initializes the TSD structure and socket
- * message handling thread associated to the calling thread for the
- * subsystem of the driver.
+ * None.
*
*----------------------------------------------------------------------
*/
-void
-TclInitSockets(void)
+ /* ARGSUSED */
+static void
+SocketExitHandler(
+ ClientData clientData) /* Not used. */
{
- /* Then Per thread initialization. */
- DWORD id;
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
-
- if (tsdPtr != NULL) {
- return;
- }
-
- InitSocketWindowClass();
-
- /*
- * OK, this thread has never done anything with sockets before. Construct
- * a worker thread to handle asynchronous events related to sockets
- * assigned to _this_ thread.
- */
-
- tsdPtr = TCL_TSD_INIT(&dataKey);
- tsdPtr->pendingTcpState = NULL;
- tsdPtr->socketList = NULL;
- tsdPtr->hwnd = NULL;
- tsdPtr->threadId = Tcl_GetCurrentThread();
- tsdPtr->readyEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
- if (tsdPtr->readyEvent == NULL) {
- goto initFailure;
- }
- tsdPtr->socketListLock = CreateEventW(NULL, FALSE, TRUE, NULL);
- if (tsdPtr->socketListLock == NULL) {
- goto initFailure;
- }
- tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr, 0,
- &id);
- if (tsdPtr->socketThread == NULL) {
- goto initFailure;
- }
-
- SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
-
+ Tcl_MutexLock(&socketMutex);
/*
- * Wait for the thread to signal when the window has been created and if
- * it is ready to go.
+ * Make sure the socket event handling window is cleaned-up for, at
+ * most, this thread.
*/
- WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
-
- if (tsdPtr->hwnd != NULL) {
- Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
- return;
- }
-
- initFailure:
- Tcl_Panic("InitSockets failed");
- return;
+ TclpFinalizeSockets();
+ UnregisterClass("TclSocket", TclWinGetTclInstance());
+ initialized = 0;
+ Tcl_MutexUnlock(&socketMutex);
}
/*
@@ -511,507 +426,346 @@ TclInitSockets(void)
void
TclpFinalizeSockets(void)
{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
-
- /*
- * Careful! This is a finalizer!
- */
-
- if (tsdPtr == NULL) {
- return;
- }
-
- if (tsdPtr->socketThread != NULL) {
- if (tsdPtr->hwnd != NULL) {
- PostMessageW(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
-
- /*
- * Wait for the thread to exit. This ensures that we are
- * completely cleaned up before we leave this function.
- */
+ ThreadSpecificData *tsdPtr;
- WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
- tsdPtr->hwnd = NULL;
+ tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey);
+ if (tsdPtr != NULL) {
+ if (tsdPtr->socketThread != NULL) {
+ if (tsdPtr->hwnd != NULL) {
+ if (PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0)) {
+ /*
+ * Wait for the thread to exit. This ensures that we are
+ * completely cleaned up before we leave this function.
+ */
+ WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
+ }
+ tsdPtr->hwnd = NULL;
+ }
+ CloseHandle(tsdPtr->socketThread);
+ tsdPtr->socketThread = NULL;
}
- CloseHandle(tsdPtr->socketThread);
- tsdPtr->socketThread = NULL;
- }
- if (tsdPtr->readyEvent != NULL) {
- CloseHandle(tsdPtr->readyEvent);
- tsdPtr->readyEvent = NULL;
- }
- if (tsdPtr->socketListLock != NULL) {
- CloseHandle(tsdPtr->socketListLock);
- tsdPtr->socketListLock = NULL;
+ if (tsdPtr->readyEvent != NULL) {
+ CloseHandle(tsdPtr->readyEvent);
+ tsdPtr->readyEvent = NULL;
+ }
+ if (tsdPtr->socketListLock != NULL) {
+ CloseHandle(tsdPtr->socketListLock);
+ tsdPtr->socketListLock = NULL;
+ }
+ Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
}
- Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
}
/*
*----------------------------------------------------------------------
*
- * TcpBlockModeProc --
+ * TclpHasSockets --
*
- * This function is invoked by the generic IO level to set blocking and
- * nonblocking mode on a TCP socket based channel.
+ * This function determines whether sockets are available on the current
+ * system and returns an error in interp if they are not. Note that
+ * interp may be NULL.
*
* Results:
- * 0 if successful, errno when failed.
+ * Returns TCL_OK if the system supports sockets, or TCL_ERROR with an
+ * error in interp (if non-NULL).
*
* Side effects:
- * Sets the device into blocking or nonblocking mode.
+ * If not already prepared, initializes the TSD structure and socket
+ * message handling thread associated to the calling thread for the
+ * subsystem of the driver.
*
*----------------------------------------------------------------------
*/
-static int
-TcpBlockModeProc(
- void *instanceData, /* Socket state. */
- int mode) /* The mode to set. Can be one of
- * TCL_MODE_BLOCKING or
- * TCL_MODE_NONBLOCKING. */
+int
+TclpHasSockets(
+ Tcl_Interp *interp) /* Where to write an error message if sockets
+ * are not present, or NULL if no such message
+ * is to be written. */
{
- TcpState *statePtr = (TcpState *)instanceData;
+ Tcl_MutexLock(&socketMutex);
+ InitSockets();
+ Tcl_MutexUnlock(&socketMutex);
- if (mode == TCL_MODE_NONBLOCKING) {
- SET_BITS(statePtr->flags, TCP_NONBLOCKING);
- } else {
- CLEAR_BITS(statePtr->flags, TCP_NONBLOCKING);
+ if (SocketsEnabled()) {
+ return TCL_OK;
}
- return 0;
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "sockets are not available on this system",
+ NULL);
+ }
+ return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
- * WaitForConnect --
- *
- * Check the state of an async connect process. If a connection attempt
- * terminated, process it, which may finalize it or may start the next
- * attempt. If a connect error occures, it is saved in
- * statePtr->connectError to be reported by 'fconfigure -error'.
+ * SocketSetupProc --
*
- * There are two modes of operation, defined by errorCodePtr:
- * * non-NULL: Called by explicite read/write command. Block if socket
- * is blocking.
- * May return two error codes:
- * * EWOULDBLOCK: if connect is still in progress
- * * ENOTCONN: if connect failed. This would be the error message
- * of a recv or sendto syscall so this is emulated here.
- * * Null: Called by a background operation. Do not block and don't
- * return any error code.
+ * This function is invoked before Tcl_DoOneEvent blocks waiting for an
+ * event.
*
* Results:
- * 0 if the connection has completed, -1 if still in progress or there is
- * an error.
+ * None.
*
* Side effects:
- * Processes socket events off the system queue. May process
- * asynchronous connect.
+ * Adjusts the block time if needed.
*
*----------------------------------------------------------------------
*/
-static int
-WaitForConnect(
- TcpState *statePtr, /* State of the socket. */
- int *errorCodePtr) /* Where to store errors? A passed
- * null-pointer activates background mode. */
+void
+SocketSetupProc(
+ ClientData data, /* Not used. */
+ int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
- int result;
- int oldMode;
- ThreadSpecificData *tsdPtr;
-
- /*
- * Check if an async connect failed already and error reporting is
- * demanded, return the error ENOTCONN.
- */
+ SocketInfo *infoPtr;
+ Tcl_Time blockTime = { 0, 0 };
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- if (errorCodePtr != NULL && GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
- *errorCodePtr = ENOTCONN;
- return -1;
+ if (!(flags & TCL_FILE_EVENTS)) {
+ return;
}
/*
- * Check if an async connect is running. If not return ok
+ * Check to see if there is a ready socket. If so, poll.
*/
- if (!GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
- return 0;
+ WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
+ for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
+ infoPtr = infoPtr->nextPtr) {
+ if (infoPtr->readyEvents & infoPtr->watchEvents) {
+ Tcl_SetMaxBlockTime(&blockTime);
+ break;
+ }
}
+ SetEvent(tsdPtr->socketListLock);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SocketCheckProc --
+ *
+ * This function is called by Tcl_DoOneEvent to check the socket event
+ * source for events.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * May queue an event.
+ *
+ *----------------------------------------------------------------------
+ */
- /*
- * In socket test mode do not continue with the connect
- * Exceptions are:
- * - Call by recv/send and blocking socket
- * (errorCodePtr != NULL && !GOT_BITS(flags, TCP_NONBLOCKING))
- * - Call by the event queue (errorCodePtr == NULL)
- */
+static void
+SocketCheckProc(
+ ClientData data, /* Not used. */
+ int flags) /* Event flags as passed to Tcl_DoOneEvent. */
+{
+ SocketInfo *infoPtr;
+ SocketEvent *evPtr;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- if (GOT_BITS(statePtr->flags, TCP_ASYNC_TEST_MODE)
- && errorCodePtr != NULL
- && GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
- *errorCodePtr = EWOULDBLOCK;
- return -1;
+ if (!(flags & TCL_FILE_EVENTS)) {
+ return;
}
/*
- * Be sure to disable event servicing so we are truly modal.
- */
-
- oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
-
- /*
- * Loop in the blocking case until the connect signal is present
+ * Queue events for any ready sockets that don't already have events
+ * queued (caused by persistent states that won't generate WinSock
+ * events).
*/
- while (1) {
- /*
- * Get the statePtr lock.
- */
-
- tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
-
- /*
- * Check for connect event.
- */
-
- if (GOT_BITS(statePtr->readyEvents, FD_CONNECT)) {
- /*
- * Consume the connect event.
- */
-
- CLEAR_BITS(statePtr->readyEvents, FD_CONNECT);
-
- /*
- * For blocking sockets and foreground processing, disable async
- * connect as we continue now synchronously.
- */
-
- if (errorCodePtr != NULL &&
- !GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
- CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
- }
-
- /*
- * Free list lock.
- */
-
- SetEvent(tsdPtr->socketListLock);
-
- /*
- * Continue connect. If switched to synchronous connect, the
- * connect is terminated.
- */
-
- result = TcpConnect(NULL, statePtr);
-
- /*
- * Restore event service mode.
- */
-
- (void) Tcl_SetServiceMode(oldMode);
-
- /*
- * Check for Successful connect or async connect restart
- */
-
- if (result == TCL_OK) {
- /*
- * Check for async connect restart (not possible for
- * foreground blocking operation)
- */
-
- if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
- if (errorCodePtr != NULL) {
- *errorCodePtr = EWOULDBLOCK;
- }
- return -1;
- }
- return 0;
- }
-
- /*
- * Connect finally failed. For foreground operation return
- * ENOTCONN.
- */
-
- if (errorCodePtr != NULL) {
- *errorCodePtr = ENOTCONN;
- }
- return -1;
- }
-
- /*
- * Free list lock.
- */
-
- SetEvent(tsdPtr->socketListLock);
-
- /*
- * Background operation returns with no action as there was no connect
- * event
- */
-
- if (errorCodePtr == NULL) {
- return -1;
- }
-
- /*
- * A non blocking socket waiting for an asynchronous connect
- * returns directly the error EWOULDBLOCK
- */
-
- if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
- *errorCodePtr = EWOULDBLOCK;
- return -1;
+ WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
+ for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
+ infoPtr = infoPtr->nextPtr) {
+ if ((infoPtr->readyEvents & infoPtr->watchEvents)
+ && !(infoPtr->flags & SOCKET_PENDING)) {
+ infoPtr->flags |= SOCKET_PENDING;
+ evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent));
+ evPtr->header.proc = SocketEventProc;
+ evPtr->socket = infoPtr->socket;
+ Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
}
-
- /*
- * Wait until something happens.
- */
-
- WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
}
+ SetEvent(tsdPtr->socketListLock);
}
/*
*----------------------------------------------------------------------
*
- * TcpInputProc --
+ * SocketEventProc --
*
- * This function is invoked by the generic IO level to read input from a
- * TCP socket based channel.
+ * This function is called by Tcl_ServiceEvent when a socket event
+ * reaches the front of the event queue. This function is responsible for
+ * notifying the generic channel code.
*
* Results:
- * The number of bytes read is returned or -1 on error. An output
- * argument contains the POSIX error code on error, or zero if no error
- * occurred.
+ * Returns 1 if the event was handled, meaning it should be removed from
+ * the queue. Returns 0 if the event was not handled, meaning it should
+ * stay on the queue. The only time the event isn't handled is if the
+ * TCL_FILE_EVENTS flag bit isn't set.
*
* Side effects:
- * Reads input from the input device of the channel.
+ * Whatever the channel callback functions do.
*
*----------------------------------------------------------------------
*/
static int
-TcpInputProc(
- void *instanceData, /* Socket state. */
- char *buf, /* Where to store data read. */
- int bufSize, /* How much space is available in the
- * buffer? */
- int *errorCodePtr) /* Where to store error code. */
+SocketEventProc(
+ Tcl_Event *evPtr, /* Event to service. */
+ int flags) /* Flags that indicate what events to handle,
+ * such as TCL_FILE_EVENTS. */
{
- TcpState *statePtr = (TcpState *)instanceData;
- int bytesRead;
- DWORD error;
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
+ SocketInfo *infoPtr;
+ SocketEvent *eventPtr = (SocketEvent *) evPtr;
+ int mask = 0;
+ int events;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- *errorCodePtr = 0;
+ if (!(flags & TCL_FILE_EVENTS)) {
+ return 0;
+ }
/*
- * First check to see if EOF was already detected, to prevent calling the
- * socket stack after the first time EOF is detected.
+ * Find the specified socket on the socket list.
*/
- if (GOT_BITS(statePtr->flags, SOCKET_EOF)) {
- return 0;
+ WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
+ for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
+ infoPtr = infoPtr->nextPtr) {
+ if (infoPtr->socket == eventPtr->socket) {
+ break;
+ }
}
+ SetEvent(tsdPtr->socketListLock);
/*
- * Check if there is an async connect running.
- * For blocking sockets terminate connect, otherwise do one step.
- * For a non blocking socket return EWOULDBLOCK if connect not terminated
+ * Discard events that have gone stale.
*/
- if (WaitForConnect(statePtr, errorCodePtr) != 0) {
- return -1;
+ if (!infoPtr) {
+ return 1;
}
+ infoPtr->flags &= ~SOCKET_PENDING;
+
/*
- * No EOF, and it is connected, so try to read more from the socket. Note
- * that we clear the FD_READ bit because read events are level triggered
- * so a new event will be generated if there is still data available to be
- * read. We have to simulate blocking behavior here since we are always
- * using non-blocking sockets.
+ * Handle connection requests directly.
*/
- while (1) {
- SendSelectMessage(tsdPtr, UNSELECT, statePtr);
+ if (infoPtr->readyEvents & FD_ACCEPT) {
+ TcpAccept(infoPtr);
+ return 1;
+ }
- /*
- * Single fd operation: this proc is only called for a connected
- * socket.
- */
+ /*
+ * Mask off unwanted events and compute the read/write mask so we can
+ * notify the channel.
+ */
- bytesRead = recv(statePtr->sockets->fd, buf, bufSize, 0);
- CLEAR_BITS(statePtr->readyEvents, FD_READ);
+ events = infoPtr->readyEvents & infoPtr->watchEvents;
+ if (events & FD_CLOSE) {
/*
- * Check for end-of-file condition or successful read.
+ * If the socket was closed and the channel is still interested in
+ * read events, then we need to ensure that we keep polling for this
+ * event until someone does something with the channel. Note that we
+ * do this before calling Tcl_NotifyChannel so we don't have to watch
+ * out for the channel being deleted out from under us. This may cause
+ * a redundant trip through the event loop, but it's simpler than
+ * trying to do unwind protection.
*/
- if (bytesRead == 0) {
- SET_BITS(statePtr->flags, SOCKET_EOF);
- }
- if (bytesRead != SOCKET_ERROR) {
- break;
- }
-
+ Tcl_Time blockTime = { 0, 0 };
+ Tcl_SetMaxBlockTime(&blockTime);
+ mask |= TCL_READABLE|TCL_WRITABLE;
+ } else if (events & FD_READ) {
/*
- * If an error occurs after the FD_CLOSE has arrived, then ignore the
- * error and report an EOF.
+ * Throw the readable event if an async connect failed.
*/
- if (GOT_BITS(statePtr->readyEvents, FD_CLOSE)) {
- SET_BITS(statePtr->flags, SOCKET_EOF);
- bytesRead = 0;
- break;
- }
+ if (infoPtr->lastError) {
- error = WSAGetLastError();
+ mask |= TCL_READABLE;
+
+ } else {
+ fd_set readFds;
+ struct timeval timeout;
- /*
- * If an RST comes, then ignore the error and report an EOF just like
- * on Unix.
- */
+ /*
+ * We must check to see if data is really available, since someone
+ * could have consumed the data in the meantime. Turn off async
+ * notification so select will work correctly. If the socket is still
+ * readable, notify the channel driver, otherwise reset the async
+ * select handler and keep waiting.
+ */
- if (error == WSAECONNRESET) {
- SET_BITS(statePtr->flags, SOCKET_EOF);
- bytesRead = 0;
- break;
- }
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) UNSELECT, (LPARAM) infoPtr);
- /*
- * Check for error condition or underflow in non-blocking case.
- */
+ FD_ZERO(&readFds);
+ FD_SET(infoPtr->socket, &readFds);
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 0;
- if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)
- || (error != WSAEWOULDBLOCK)) {
- Tcl_WinConvertError(error);
- *errorCodePtr = Tcl_GetErrno();
- bytesRead = -1;
- break;
+ if (select(0, &readFds, NULL, NULL, &timeout) != 0) {
+ mask |= TCL_READABLE;
+ } else {
+ infoPtr->readyEvents &= ~(FD_READ);
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) SELECT, (LPARAM) infoPtr);
+ }
}
+ }
- /*
- * In the blocking case, wait until the file becomes readable or
- * closed and try again.
- */
+ /*
+ * writable event
+ */
- if (!WaitForSocketEvent(statePtr, FD_READ|FD_CLOSE, errorCodePtr)) {
- bytesRead = -1;
- break;
- }
+ if (events & FD_WRITE) {
+ mask |= TCL_WRITABLE;
}
- SendSelectMessage(tsdPtr, SELECT, statePtr);
-
- return bytesRead;
+ if (mask) {
+ Tcl_NotifyChannel(infoPtr->channel, mask);
+ }
+ return 1;
}
/*
*----------------------------------------------------------------------
*
- * TcpOutputProc --
+ * TcpBlockProc --
*
- * This function is called by the generic IO level to write data to a
- * socket based channel.
+ * Sets a socket into blocking or non-blocking mode.
*
* Results:
- * The number of bytes written or -1 on failure.
+ * 0 if successful, errno if there was an error.
*
* Side effects:
- * Produces output on the socket.
+ * None.
*
*----------------------------------------------------------------------
*/
static int
-TcpOutputProc(
- void *instanceData, /* Socket state. */
- const char *buf, /* The data buffer. */
- int toWrite, /* How many bytes to write? */
- int *errorCodePtr) /* Where to store error code. */
+TcpBlockProc(
+ ClientData instanceData, /* The socket to block/un-block. */
+ int mode) /* TCL_MODE_BLOCKING or
+ * TCL_MODE_NONBLOCKING. */
{
- TcpState *statePtr = (TcpState *)instanceData;
- int written;
- DWORD error;
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
-
- *errorCodePtr = 0;
-
- /*
- * Check if there is an async connect running.
- * For blocking sockets terminate connect, otherwise do one step.
- * For a non blocking socket return EWOULDBLOCK if connect not terminated
- */
-
- if (WaitForConnect(statePtr, errorCodePtr) != 0) {
- return -1;
- }
-
- while (1) {
- SendSelectMessage(tsdPtr, UNSELECT, statePtr);
-
- /*
- * Single fd operation: this proc is only called for a connected
- * socket.
- */
-
- written = send(statePtr->sockets->fd, buf, toWrite, 0);
- if (written != SOCKET_ERROR) {
- /*
- * Since Windows won't generate a new write event until we hit an
- * overflow condition, we need to force the event loop to poll
- * until the condition changes.
- */
-
- if (GOT_BITS(statePtr->watchEvents, FD_WRITE)) {
- Tcl_Time blockTime = { 0, 0 };
-
- Tcl_SetMaxBlockTime(&blockTime);
- }
- break;
- }
-
- /*
- * Check for error condition or overflow. In the event of overflow, we
- * need to clear the FD_WRITE flag so we can detect the next writable
- * event. Note that Windows only sends a new writable event after a
- * send fails with WSAEWOULDBLOCK.
- */
-
- error = WSAGetLastError();
- if (error == WSAEWOULDBLOCK) {
- CLEAR_BITS(statePtr->readyEvents, FD_WRITE);
- if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
- *errorCodePtr = EWOULDBLOCK;
- written = -1;
- break;
- }
- } else {
- Tcl_WinConvertError(error);
- *errorCodePtr = Tcl_GetErrno();
- written = -1;
- break;
- }
-
- /*
- * In the blocking case, wait until the file becomes writable or
- * closed and try again.
- */
+ SocketInfo *infoPtr = (SocketInfo *) instanceData;
- if (!WaitForSocketEvent(statePtr, FD_WRITE|FD_CLOSE, errorCodePtr)) {
- written = -1;
- break;
- }
+ if (mode == TCL_MODE_NONBLOCKING) {
+ infoPtr->flags |= SOCKET_ASYNC;
+ } else {
+ infoPtr->flags &= ~(SOCKET_ASYNC);
}
-
- SendSelectMessage(tsdPtr, SELECT, statePtr);
-
- return written;
+ return 0;
}
/*
@@ -1032,61 +786,50 @@ TcpOutputProc(
*----------------------------------------------------------------------
*/
+ /* ARGSUSED */
static int
TcpCloseProc(
- void *instanceData, /* The socket to close. */
- TCL_UNUSED(Tcl_Interp *))
+ ClientData instanceData, /* The socket to close. */
+ Tcl_Interp *interp) /* Unused. */
{
- TcpState *statePtr = (TcpState *)instanceData;
+ SocketInfo *infoPtr = (SocketInfo *) instanceData;
/* TIP #218 */
int errorCode = 0;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
- * Clean up the OS socket handle. The default Windows setting for a
- * socket is SO_DONTLINGER, which does a graceful shutdown in the
- * background.
+ * Check that WinSock is initialized; do not call it if not, to prevent
+ * system crashes. This can happen at exit time if the exit handler for
+ * WinSock ran before other exit handlers that want to use sockets.
*/
- while (statePtr->sockets != NULL) {
- TcpFdList *thisfd = statePtr->sockets;
+ if (SocketsEnabled()) {
+ /*
+ * Clean up the OS socket handle. The default Windows setting for a
+ * socket is SO_DONTLINGER, which does a graceful shutdown in the
+ * background.
+ */
- statePtr->sockets = thisfd->next;
- if (closesocket(thisfd->fd) == SOCKET_ERROR) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
+ if (closesocket(infoPtr->socket) == SOCKET_ERROR) {
+ TclWinConvertWSAError((DWORD) WSAGetLastError());
errorCode = Tcl_GetErrno();
}
- ckfree(thisfd);
- }
-
- if (statePtr->addrlist != NULL) {
- freeaddrinfo(statePtr->addrlist);
- }
- if (statePtr->myaddrlist != NULL) {
- freeaddrinfo(statePtr->myaddrlist);
}
/*
* Clear an eventual tsd info list pointer.
- *
* This may be called, if an async socket connect fails or is closed
* between connect and thread action callback.
*/
+ if (tsdPtr->pendingSocketInfo != NULL
+ && tsdPtr->pendingSocketInfo == infoPtr) {
- if (tsdPtr->pendingTcpState != NULL
- && tsdPtr->pendingTcpState == statePtr) {
- /*
- * Get infoPtr lock, because this concerns the notifier thread.
- */
-
+ /* get infoPtr lock, because this concerns the notifier thread */
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- tsdPtr->pendingTcpState = NULL;
-
- /*
- * Free list lock.
- */
+ tsdPtr->pendingSocketInfo = NULL;
+ /* Free list lock */
SetEvent(tsdPtr->socketListLock);
}
@@ -1097,865 +840,439 @@ TcpCloseProc(
* fear of damaging the list.
*/
- ckfree(statePtr);
+ ckfree((char *) infoPtr);
return errorCode;
}
/*
*----------------------------------------------------------------------
*
- * TcpClose2Proc --
+ * NewSocketInfo --
*
- * This function is called by the generic IO level to perform the channel
- * type specific part of a half-close: namely, a shutdown() on a socket.
+ * This function allocates and initializes a new SocketInfo structure.
*
* Results:
- * 0 if successful, the value of errno if failed.
+ * Returns a newly allocated SocketInfo.
*
* Side effects:
- * Shuts down one side of the socket.
+ * None, except for allocation of memory.
*
*----------------------------------------------------------------------
*/
-static int
-TcpClose2Proc(
- void *instanceData, /* The socket to close. */
- Tcl_Interp *interp, /* For error reporting. */
- int flags) /* Flags that indicate which side to close. */
+static SocketInfo *
+NewSocketInfo(
+ SOCKET socket)
{
- TcpState *statePtr = (TcpState *)instanceData;
- int readError = 0;
- int writeError = 0;
+ SocketInfo *infoPtr;
+ /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */
+
+ infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo));
+ infoPtr->channel = 0;
+ infoPtr->socket = socket;
+ infoPtr->flags = 0;
+ infoPtr->watchEvents = 0;
+ infoPtr->readyEvents = 0;
+ infoPtr->selectEvents = 0;
+ infoPtr->acceptEventCount = 0;
+ infoPtr->acceptProc = NULL;
+ infoPtr->acceptProcData = NULL;
+ infoPtr->lastError = 0;
/*
- * Shutdown the OS socket handle.
+ * TIP #218. Removed the code inserting the new structure into the global
+ * list. This is now handled in the thread action callbacks, and only
+ * there.
*/
- if ((flags & (TCL_CLOSE_READ|TCL_CLOSE_WRITE)) == 0) {
- return TcpCloseProc(instanceData, interp);
- }
+ infoPtr->nextPtr = NULL;
- /*
- * Single fd operation: Tcl_OpenTcpServer() does not set TCL_READABLE or
- * TCL_WRITABLE so this should never be called for a server socket.
- */
-
- if ((flags & TCL_CLOSE_READ) && (shutdown(statePtr->sockets->fd, SD_RECEIVE) == SOCKET_ERROR)) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
- readError = Tcl_GetErrno();
- }
- if ((flags & TCL_CLOSE_WRITE) && (shutdown(statePtr->sockets->fd, SD_SEND) == SOCKET_ERROR)) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
- writeError = Tcl_GetErrno();
- }
- return (readError != 0) ? readError : writeError;
+ return infoPtr;
}
/*
*----------------------------------------------------------------------
*
- * TcpSetOptionProc --
+ * CreateSocket --
*
- * Sets Tcp channel specific options.
+ * This function opens a new socket and initializes the SocketInfo
+ * structure.
*
* Results:
- * None, unless an error happens.
+ * Returns a new SocketInfo, or NULL with an error in interp.
*
* Side effects:
- * Changes attributes of the socket at the system level.
+ * None, except for allocation of memory.
*
*----------------------------------------------------------------------
*/
-static int
-TcpSetOptionProc(
- void *instanceData, /* Socket state. */
- Tcl_Interp *interp, /* For error reporting - can be NULL. */
- const char *optionName, /* Name of the option to set. */
- const char *value) /* New value for option. */
+static SocketInfo *
+CreateSocket(
+ Tcl_Interp *interp, /* For error reporting; can be NULL. */
+ int port, /* Port number to open. */
+ const char *host, /* Name of host on which to open port. */
+ int server, /* 1 if socket should be a server socket, else
+ * 0 for a client socket. */
+ const char *myaddr, /* Optional client-side address */
+ int myport, /* Optional client-side port */
+ int async) /* If nonzero, connect client socket
+ * asynchronously. */
{
- TcpState *statePtr = (TcpState *)instanceData;
- SOCKET sock;
- size_t len = 0;
-
- if (optionName != NULL) {
- len = strlen(optionName);
- }
-
- sock = statePtr->sockets->fd;
+ u_long flag = 1; /* Indicates nonblocking mode. */
+ SOCKADDR_IN sockaddr; /* Socket address */
+ SOCKADDR_IN mysockaddr; /* Socket address for client */
+ SOCKET sock = INVALID_SOCKET;
+ SocketInfo *infoPtr=NULL; /* The returned value. */
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ TclThreadDataKeyGet(&dataKey);
- if ((len > 1) && (optionName[1] == 'k') &&
- (strncmp(optionName, "-keepalive", len) == 0)) {
- BOOL boolVar;
- int rtn;
+ /*
+ * Check that WinSock is initialized; do not call it if not, to prevent
+ * system crashes. This can happen at exit time if the exit handler for
+ * WinSock ran before other exit handlers that want to use sockets.
+ */
- if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
- return TCL_ERROR;
- }
- rtn = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
- (const char *) &boolVar, sizeof(boolVar));
- if (rtn != 0) {
- Tcl_WinConvertError(WSAGetLastError());
- if (interp) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't set socket option: %s",
- Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
- }
- return TCL_OK;
+ if (!SocketsEnabled()) {
+ return NULL;
}
- if ((len > 1) && (optionName[1] == 'n') &&
- (strncmp(optionName, "-nodelay", len) == 0)) {
- BOOL boolVar;
- int rtn;
- if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
- return TCL_ERROR;
- }
- rtn = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
- (const char *) &boolVar, sizeof(boolVar));
- if (rtn != 0) {
- Tcl_WinConvertError(WSAGetLastError());
- if (interp) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't set socket option: %s",
- Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
- }
- return TCL_OK;
+ if (!CreateSocketAddress(&sockaddr, host, port)) {
+ goto error;
+ }
+ if ((myaddr != NULL || myport != 0) &&
+ !CreateSocketAddress(&mysockaddr, myaddr, myport)) {
+ goto error;
}
- return Tcl_BadChannelOption(interp, optionName, "keepalive nodelay");
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TcpGetOptionProc --
- *
- * Computes an option value for a TCP socket based channel, or a list of
- * all options and their values.
- *
- * Note: This code is based on code contributed by John Haxby.
- *
- * Results:
- * A standard Tcl result. The value of the specified option or a list of
- * all options and their values is returned in the supplied DString. Sets
- * Error message if needed.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static int
-TcpGetOptionProc(
- void *instanceData, /* Socket state. */
- Tcl_Interp *interp, /* For error reporting - can be NULL. */
- const char *optionName, /* Name of the option to retrieve the value
- * for, or NULL to get all options and their
- * values. */
- Tcl_DString *dsPtr) /* Where to store the computed value;
- * initialized by caller. */
-{
- TcpState *statePtr = (TcpState *)instanceData;
- char host[NI_MAXHOST], port[NI_MAXSERV];
- SOCKET sock;
- size_t len = 0;
- int reverseDNS = 0;
-#define SUPPRESS_RDNS_VAR "::tcl::unsupported::noReverseDNS"
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ goto error;
+ }
/*
- * Go one step in async connect
- *
- * If any error is thrown save it as background error to report eventually
- * below.
+ * Win-NT has a misfeature that sockets are inherited in child processes
+ * by default. Turn off the inherit bit.
*/
- if (!GOT_BITS(statePtr->flags, TCP_ASYNC_TEST_MODE)) {
- WaitForConnect(statePtr, NULL);
- }
+ SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
- sock = statePtr->sockets->fd;
- if (optionName != NULL) {
- len = strlen(optionName);
- }
+ /*
+ * Set kernel space buffering
+ */
- if ((len > 1) && (optionName[1] == 'e') &&
- (strncmp(optionName, "-error", len) == 0)) {
+ TclSockMinimumBuffers((void *)sock, TCP_BUFFER_SIZE);
+
+ if (server) {
/*
- * Do not return any errors if async connect is running.
+ * Bind to the specified port. Note that we must not call setsockopt
+ * with SO_REUSEADDR because Microsoft allows addresses to be reused
+ * even if they are still in use.
+ *
+ * Bind should not be affected by the socket having already been set
+ * into nonblocking mode. If there is trouble, this is one place to
+ * look for bugs.
*/
- if (!GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
- if (GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
- /*
- * In case of a failed async connect, eventually report the
- * connect error only once. Do not report the system error,
- * as this comes again and again.
- */
+ if (bind(sock, (SOCKADDR *) &sockaddr, sizeof(SOCKADDR_IN))
+ == SOCKET_ERROR) {
+ goto error;
+ }
- if (statePtr->connectError != 0) {
- Tcl_DStringAppend(dsPtr,
- Tcl_ErrnoMsg(statePtr->connectError), TCL_INDEX_NONE);
- statePtr->connectError = 0;
- }
- } else {
- /*
- * Report an eventual last error of the socket system.
- */
+ /*
+ * Set the maximum number of pending connect requests to the max value
+ * allowed on each platform (Win32 and Win32s may be different, and
+ * there may be differences between TCP/IP stacks).
+ */
- int optlen;
- int ret;
- DWORD err;
+ if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
+ goto error;
+ }
- /*
- * Populate the err variable with a POSIX error
- */
+ /*
+ * Add this socket to the global list of sockets.
+ */
- optlen = sizeof(int);
- ret = getsockopt(sock, SOL_SOCKET, SO_ERROR,
- (char *)&err, &optlen);
+ infoPtr = NewSocketInfo(sock);
- /*
- * The error was not returned directly but should be taken
- * from WSA.
- */
+ /*
+ * Set up the select mask for connection request events.
+ */
- if (ret == SOCKET_ERROR) {
- err = WSAGetLastError();
- }
+ infoPtr->selectEvents = FD_ACCEPT;
+ infoPtr->watchEvents |= FD_ACCEPT;
- /*
- * Return error message.
- */
+ /*
+ * Register for interest in events in the select mask. Note that this
+ * automatically places the socket into non-blocking mode.
+ */
+
+ ioctlsocket(sock, (long) FIONBIO, &flag);
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
+ (LPARAM) infoPtr);
- if (err) {
- Tcl_WinConvertError(err);
- Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), TCL_INDEX_NONE);
- }
+ } else {
+ /*
+ * Try to bind to a local port, if specified.
+ */
+
+ if (myaddr != NULL || myport != 0) {
+ if (bind(sock, (SOCKADDR *) &mysockaddr, sizeof(SOCKADDR_IN))
+ == SOCKET_ERROR) {
+ goto error;
}
}
- return TCL_OK;
- }
- if ((len > 1) && (optionName[1] == 'c') &&
- (strncmp(optionName, "-connecting", len) == 0)) {
- Tcl_DStringAppend(dsPtr,
- GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)
- ? "1" : "0", TCL_INDEX_NONE);
- return TCL_OK;
- }
+ /*
+ * Allocate socket info structure
+ */
- if (interp != NULL
- && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) {
- reverseDNS = NI_NUMERICHOST;
- }
+ infoPtr = NewSocketInfo(sock);
- if ((len == 0) || ((len > 1) && (optionName[1] == 'p') &&
- (strncmp(optionName, "-peername", len) == 0))) {
- address peername;
- socklen_t size = sizeof(peername);
+ /*
+ * Set the socket into nonblocking mode if the connect should be done
+ * in the background. Activate connect notification.
+ */
+
+ if (async) {
+
+ /* get infoPtr lock */
+ WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
/*
- * In async connect output an empty string
+ * Buffer new infoPtr in the tsd memory as long as it is not in
+ * the info list. This allows the event procedure to process the
+ * event.
+ * Bugfig for 336441ed59 to not ignore notifications until the
+ * infoPtr is in the list..
*/
- if (len == 0) {
- Tcl_DStringAppendElement(dsPtr, "-peername");
- Tcl_DStringAppendElement(dsPtr, "");
- } else {
- return TCL_OK;
- }
- } else if (getpeername(sock, (LPSOCKADDR) &(peername.sa),
- &size) == 0) {
+ tsdPtr->pendingSocketInfo = infoPtr;
+
/*
- * Peername fetch succeeded - output list
+ * Set connect mask to connect events
+ * This is activated by a SOCKET_SELECT message to the notifier
+ * thread.
*/
- if (len == 0) {
- Tcl_DStringAppendElement(dsPtr, "-peername");
- Tcl_DStringStartSublist(dsPtr);
- }
+ infoPtr->selectEvents |= FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE;
+ infoPtr->flags |= SOCKET_ASYNC_CONNECT;
+
+ /*
+ * Free list lock
+ */
+ SetEvent(tsdPtr->socketListLock);
- getnameinfo(&(peername.sa), size, host, sizeof(host),
- NULL, 0, NI_NUMERICHOST);
- Tcl_DStringAppendElement(dsPtr, host);
- getnameinfo(&(peername.sa), size, host, sizeof(host),
- port, sizeof(port), reverseDNS | NI_NUMERICSERV);
- Tcl_DStringAppendElement(dsPtr, host);
- Tcl_DStringAppendElement(dsPtr, port);
- if (len == 0) {
- Tcl_DStringEndSublist(dsPtr);
- } else {
- return TCL_OK;
- }
- } else {
/*
- * getpeername failed - but if we were asked for all the options
- * (len==0), don't flag an error at that point because it could be
- * an fconfigure request on a server socket (such sockets have no
- * peer). {Copied from unix/tclUnixChan.c}
+ * Activate accept notification and put in async mode
+ * Bug 336441ed59: activate notification before connect
+ * so we do not miss a notification of a fialed connect.
*/
+ ioctlsocket(sock, (long) FIONBIO, &flag);
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
+ (LPARAM) infoPtr);
- if (len) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
- if (interp) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't get peername: %s",
- Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
- }
}
- }
- if ((len == 0) || ((len > 1) && (optionName[1] == 's') &&
- (strncmp(optionName, "-sockname", len) == 0))) {
- TcpFdList *fds;
- address sockname;
- socklen_t size;
- int found = 0;
+ /*
+ * Attempt to connect to the remote socket.
+ */
+
+ if (connect(sock, (SOCKADDR *) &sockaddr,
+ sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
+ TclWinConvertWSAError((DWORD) WSAGetLastError());
+ if (Tcl_GetErrno() != EWOULDBLOCK) {
+ goto error;
+ }
- if (len == 0) {
- Tcl_DStringAppendElement(dsPtr, "-sockname");
- Tcl_DStringStartSublist(dsPtr);
- }
- if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
/*
- * In async connect output an empty string
+ * The connection is progressing in the background.
*/
- found = 1;
} else {
- for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
- sock = fds->fd;
- size = sizeof(sockname);
- if (getsockname(sock, &(sockname.sa), &size) >= 0) {
- int flags = reverseDNS;
-
- found = 1;
- getnameinfo(&sockname.sa, size, host, sizeof(host),
- NULL, 0, NI_NUMERICHOST);
- Tcl_DStringAppendElement(dsPtr, host);
- /*
- * We don't want to resolve INADDR_ANY and sin6addr_any;
- * they can sometimes cause problems (and never have a
- * name).
- */
+ /*
+ * Set up the select mask for read/write events. If the connect
+ * attempt has not completed, include connect events.
+ */
- flags |= NI_NUMERICSERV;
- if (sockname.sa.sa_family == AF_INET) {
- if (sockname.sa4.sin_addr.s_addr == INADDR_ANY) {
- flags |= NI_NUMERICHOST;
- }
- } else if (sockname.sa.sa_family == AF_INET6) {
- if ((IN6_ARE_ADDR_EQUAL(&sockname.sa6.sin6_addr,
- &in6addr_any)) ||
- (IN6_IS_ADDR_V4MAPPED(&sockname.sa6.sin6_addr)
- && sockname.sa6.sin6_addr.s6_addr[12] == 0
- && sockname.sa6.sin6_addr.s6_addr[13] == 0
- && sockname.sa6.sin6_addr.s6_addr[14] == 0
- && sockname.sa6.sin6_addr.s6_addr[15] == 0)) {
- flags |= NI_NUMERICHOST;
- }
- }
- getnameinfo(&sockname.sa, size, host, sizeof(host),
- port, sizeof(port), flags);
- Tcl_DStringAppendElement(dsPtr, host);
- Tcl_DStringAppendElement(dsPtr, port);
- }
- }
- }
- if (found) {
- if (len) {
- return TCL_OK;
- }
- Tcl_DStringEndSublist(dsPtr);
- } else {
- if (interp) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't get sockname: %s", Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
- }
- }
+ infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE;
- if ((len == 0) || ((len > 1) && (optionName[1] == 'k') &&
- (strncmp(optionName, "-keepalive", len) == 0))) {
- int optlen;
- BOOL opt = FALSE;
+ /*
+ * Register for interest in events in the select mask. Note that this
+ * automatically places the socket into non-blocking mode.
+ */
- if (len == 0) {
- sock = statePtr->sockets->fd;
- Tcl_DStringAppendElement(dsPtr, "-keepalive");
- }
- optlen = sizeof(BOOL);
- getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, &optlen);
- Tcl_DStringAppendElement(dsPtr, opt ? "1" : "0");
- if (len > 0) {
- return TCL_OK;
+ ioctlsocket(sock, (long) FIONBIO, &flag);
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
+ (LPARAM) infoPtr);
}
}
- if ((len == 0) || ((len > 1) && (optionName[1] == 'n') &&
- (strncmp(optionName, "-nodelay", len) == 0))) {
- int optlen;
- BOOL opt = FALSE;
+ return infoPtr;
- if (len == 0) {
- sock = statePtr->sockets->fd;
- Tcl_DStringAppendElement(dsPtr, "-nodelay");
- }
- optlen = sizeof(BOOL);
- getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, &optlen);
- Tcl_DStringAppendElement(dsPtr, opt ? "1" : "0");
- if (len > 0) {
- return TCL_OK;
- }
+ error:
+ TclWinConvertWSAError((DWORD) WSAGetLastError());
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "couldn't open socket: ",
+ Tcl_PosixError(interp), NULL);
}
-
- if (len > 0) {
- return Tcl_BadChannelOption(interp, optionName,
- "connecting keepalive nodelay peername sockname");
+ if (infoPtr != NULL) {
+ /*
+ * Free the allocated socket info structure and close the socket
+ */
+ TcpCloseProc(infoPtr, interp);
+ } else if (sock != INVALID_SOCKET) {
+ /*
+ * No socket structure jet - just close
+ */
+ closesocket(sock);
}
-
- return TCL_OK;
+ return NULL;
}
/*
*----------------------------------------------------------------------
*
- * TcpWatchProc --
+ * CreateSocketAddress --
*
- * Informs the channel driver of the events that the generic channel code
- * wishes to receive on this socket.
+ * This function initializes a sockaddr structure for a host and port.
*
* Results:
- * None.
+ * 1 if the host was valid, 0 if the host could not be converted to an IP
+ * address.
*
* Side effects:
- * May cause the notifier to poll if any of the specified conditions are
- * already true.
+ * Fills in the *sockaddrPtr structure.
*
*----------------------------------------------------------------------
*/
-static void
-TcpWatchProc(
- void *instanceData, /* The socket state. */
- int mask) /* Events of interest; an OR-ed combination of
- * TCL_READABLE, TCL_WRITABLE and
- * TCL_EXCEPTION. */
+static int
+CreateSocketAddress(
+ LPSOCKADDR_IN sockaddrPtr, /* Socket address */
+ const char *host, /* Host. NULL implies INADDR_ANY */
+ int port) /* Port number */
{
- TcpState *statePtr = (TcpState *)instanceData;
+ struct hostent *hostent; /* Host database entry */
+ struct in_addr addr; /* For 64/32 bit madness */
/*
- * Update the watch events mask. Only if the socket is not a server
- * socket. [Bug 557878]
+ * Check that WinSock is initialized; do not call it if not, to prevent
+ * system crashes. This can happen at exit time if the exit handler for
+ * WinSock ran before other exit handlers that want to use sockets.
*/
- if (!statePtr->acceptProc) {
- statePtr->watchEvents = 0;
- if (GOT_BITS(mask, TCL_READABLE)) {
- SET_BITS(statePtr->watchEvents, FD_READ | FD_CLOSE);
- }
- if (GOT_BITS(mask, TCL_WRITABLE)) {
- SET_BITS(statePtr->watchEvents, FD_WRITE | FD_CLOSE);
- }
-
- /*
- * If there are any conditions already set, then tell the notifier to
- * poll rather than block.
- */
-
- if (statePtr->readyEvents & statePtr->watchEvents) {
- Tcl_Time blockTime = { 0, 0 };
+ if (!SocketsEnabled()) {
+ Tcl_SetErrno(EFAULT);
+ return 0;
+ }
- Tcl_SetMaxBlockTime(&blockTime);
+ ZeroMemory(sockaddrPtr, sizeof(SOCKADDR_IN));
+ sockaddrPtr->sin_family = AF_INET;
+ sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
+ if (host == NULL) {
+ addr.s_addr = INADDR_ANY;
+ } else {
+ addr.s_addr = inet_addr(host);
+ if (addr.s_addr == INADDR_NONE) {
+ hostent = gethostbyname(host);
+ if (hostent != NULL) {
+ memcpy(&addr, hostent->h_addr, (size_t) hostent->h_length);
+ } else {
+#ifdef EHOSTUNREACH
+ Tcl_SetErrno(EHOSTUNREACH);
+#else
+#ifdef ENXIO
+ Tcl_SetErrno(ENXIO);
+#endif
+#endif
+ return 0; /* Error. */
+ }
}
}
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TcpGetHandleProc --
- *
- * Called from Tcl_GetChannelHandle to retrieve OS handles from inside a
- * TCP socket based channel.
- *
- * Results:
- * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no
- * handle for the specified direction.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static int
-TcpGetHandleProc(
- void *instanceData, /* The socket state. */
- TCL_UNUSED(int) /*direction*/,
- void **handlePtr) /* Where to store the handle. */
-{
- TcpState *statePtr = (TcpState *)instanceData;
+ /*
+ * NOTE: On 64 bit machines the assignment below is rumored to not do the
+ * right thing. Please report errors related to this if you observe
+ * incorrect behavior on 64 bit machines such as DEC Alphas. Should we
+ * modify this code to do an explicit memcpy?
+ */
- *handlePtr = INT2PTR(statePtr->sockets->fd);
- return TCL_OK;
+ sockaddrPtr->sin_addr.s_addr = addr.s_addr;
+ return 1; /* Success. */
}
/*
*----------------------------------------------------------------------
*
- * TcpConnect --
- *
- * This function opens a new socket in client mode.
+ * WaitForSocketEvent --
*
- * This might be called in 3 circumstances:
- * - By a regular socket command
- * - By the event handler to continue an asynchronously connect
- * - By a blocking socket function (gets/puts) to terminate the
- * connect synchronously
+ * Waits until one of the specified events occurs on a socket.
*
* Results:
- * TCL_OK, if the socket was successfully connected or an asynchronous
- * connection is in progress. If an error occurs, TCL_ERROR is returned
- * and an error message is left in interp.
+ * Returns 1 on success or 0 on failure, with an error code in
+ * errorCodePtr.
*
* Side effects:
- * Opens a socket.
- *
- * Remarks:
- * A single host name may resolve to more than one IP address, e.g. for
- * an IPv4/IPv6 dual stack host. For handling asynchronously connecting
- * sockets in the background for such hosts, this function can act as a
- * coroutine. On the first call, it sets up the control variables for the
- * two nested loops over the local and remote addresses. Once the first
- * connection attempt is in progress, it sets up itself as a writable
- * event handler for that socket, and returns. When the callback occurs,
- * control is transferred to the "reenter" label, right after the initial
- * return and the loops resume as if they had never been interrupted.
- * For synchronously connecting sockets, the loops work the usual way.
+ * Processes socket events off the system queue.
*
*----------------------------------------------------------------------
*/
static int
-TcpConnect(
- Tcl_Interp *interp, /* For error reporting; can be NULL. */
- TcpState *statePtr)
+WaitForSocketEvent(
+ SocketInfo *infoPtr, /* Information about this socket. */
+ int events, /* Events to look for. */
+ int *errorCodePtr) /* Where to store errors? */
{
- DWORD error;
- int async_connect = GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
- /* We are started with async connect and the
- * connect notification was not yet
- * received. */
- int async_callback = GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING);
- /* We were called by the event procedure and
- * continue our loop. */
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
-
- if (async_callback) {
- goto reenter;
- }
-
- for (statePtr->addr = statePtr->addrlist; statePtr->addr != NULL;
- statePtr->addr = statePtr->addr->ai_next) {
- for (statePtr->myaddr = statePtr->myaddrlist;
- statePtr->myaddr != NULL;
- statePtr->myaddr = statePtr->myaddr->ai_next) {
- /*
- * No need to try combinations of local and remote addresses
- * of different families.
- */
-
- if (statePtr->myaddr->ai_family != statePtr->addr->ai_family) {
- continue;
- }
-
- /*
- * Close the socket if it is still open from the last unsuccessful
- * iteration.
- */
-
- if (statePtr->sockets->fd != INVALID_SOCKET) {
- closesocket(statePtr->sockets->fd);
- }
-
- /*
- * Get statePtr lock.
- */
-
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
-
- /*
- * Reset last error from last try
- */
-
- statePtr->notifierConnectError = 0;
- Tcl_SetErrno(0);
-
- statePtr->sockets->fd = socket(statePtr->myaddr->ai_family,
- SOCK_STREAM, 0);
-
- /*
- * Free list lock.
- */
-
- SetEvent(tsdPtr->socketListLock);
-
- /*
- * Continue on socket creation error.
- */
-
- if (statePtr->sockets->fd == INVALID_SOCKET) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
- continue;
- }
-
- /*
- * Win-NT has a misfeature that sockets are inherited in child
- * processes by default. Turn off the inherit bit.
- */
-
- SetHandleInformation((HANDLE) statePtr->sockets->fd,
- HANDLE_FLAG_INHERIT, 0);
-
- /*
- * Set kernel space buffering
- */
-
- TclSockMinimumBuffers((void *) statePtr->sockets->fd,
- TCP_BUFFER_SIZE);
-
- /*
- * Try to bind to a local port.
- */
-
- if (bind(statePtr->sockets->fd, statePtr->myaddr->ai_addr,
- statePtr->myaddr->ai_addrlen) == SOCKET_ERROR) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
- continue;
- }
-
- /*
- * For asynchronous connect set the socket in nonblocking mode
- * and activate connect notification
- */
-
- if (async_connect) {
- TcpState *statePtr2;
- int in_socket_list = 0;
-
- /*
- * Get statePtr lock.
- */
-
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
-
- /*
- * Bugfig for 336441ed59 to not ignore notifications until the
- * infoPtr is in the list.
- * Check if my statePtr is already in the tsdPtr->socketList
- * It is set after this call by TcpThreadActionProc and is set
- * on a second round.
- *
- * If not, we buffer my statePtr in the tsd memory so it is
- * not lost by the event procedure
- */
-
- for (statePtr2 = tsdPtr->socketList; statePtr2 != NULL;
- statePtr2 = statePtr2->nextPtr) {
- if (statePtr2 == statePtr) {
- in_socket_list = 1;
- break;
- }
- }
- if (!in_socket_list) {
- tsdPtr->pendingTcpState = statePtr;
- }
-
- /*
- * Set connect mask to connect events
- *
- * This is activated by a SOCKET_SELECT message to the
- * notifier thread.
- */
-
- SET_BITS(statePtr->selectEvents, FD_CONNECT);
-
- /*
- * Free list lock.
- */
-
- SetEvent(tsdPtr->socketListLock);
-
- /*
- * Activate accept notification.
- */
-
- SendSelectMessage(tsdPtr, SELECT, statePtr);
- }
-
- /*
- * Attempt to connect to the remote socket.
- */
-
- connect(statePtr->sockets->fd, statePtr->addr->ai_addr,
- statePtr->addr->ai_addrlen);
-
- error = WSAGetLastError();
- Tcl_WinConvertError(error);
-
- if (async_connect && error == WSAEWOULDBLOCK) {
- /*
- * Asynchronous connect
- *
- * Remember that we jump back behind this next round
- */
-
- SET_BITS(statePtr->flags, TCP_ASYNC_PENDING);
- return TCL_OK;
-
- reenter:
- /*
- * Re-entry point for async connect after connect event or
- * blocking operation
- *
- * Clear the reenter flag
- */
-
- CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING);
-
- /*
- * Get statePtr lock.
- */
-
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
-
- /*
- * Get signaled connect error.
- */
-
- Tcl_WinConvertError((DWORD) statePtr->notifierConnectError);
-
- /*
- * Clear eventual connect flag.
- */
-
- CLEAR_BITS(statePtr->selectEvents, FD_CONNECT);
-
- /*
- * Free list lock.
- */
-
- SetEvent(tsdPtr->socketListLock);
- }
-
- /*
- * Clear the tsd socket list pointer if we did not wait for
- * the FD_CONNECT asynchronously
- */
-
- tsdPtr->pendingTcpState = NULL;
-
- if (Tcl_GetErrno() == 0) {
- goto out;
- }
- }
- }
+ int result = 1;
+ int oldMode;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ TclThreadDataKeyGet(&dataKey);
- out:
/*
- * Socket connected or connection failed
+ * Be sure to disable event servicing so we are truly modal.
*/
+ oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
+
/*
- * Async connect terminated
+ * Reset WSAAsyncSelect so we have a fresh set of events pending.
+ * Don't do that if we are waiting for a connect as we may miss
+ * a connect (bug 336441ed59).
*/
- CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
-
- if (Tcl_GetErrno() == 0) {
- /*
- * Successfully connected
- *
- * Set up the select mask for read/write events.
- */
-
- statePtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE;
-
- /*
- * Register for interest in events in the select mask. Note that this
- * automatically places the socket into non-blocking mode.
- */
-
- SendSelectMessage(tsdPtr, SELECT, statePtr);
- } else {
- /*
- * Connect failed
- *
- * For async connect schedule a writable event to report the fail.
- */
-
- if (async_callback) {
- /*
- * Set up the select mask for read/write events.
- */
-
- statePtr->selectEvents = FD_WRITE|FD_READ;
-
- /*
- * Get statePtr lock.
- */
-
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
-
- /*
- * Signal ready readable and writable events.
- */
-
- SET_BITS(statePtr->readyEvents, FD_WRITE | FD_READ);
-
- /*
- * Flag error to event routine.
- */
-
- SET_BITS(statePtr->flags, TCP_ASYNC_FAILED);
-
- /*
- * Save connect error to be reported by 'fconfigure -error'.
- */
-
- statePtr->connectError = Tcl_GetErrno();
-
- /*
- * Free list lock.
- */
+ if ( 0 == (events & FD_CONNECT) ) {
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT,
+ (LPARAM) infoPtr);
+
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
+ (LPARAM) infoPtr);
+ }
- SetEvent(tsdPtr->socketListLock);
+ while (1) {
+ if (infoPtr->lastError) {
+ *errorCodePtr = infoPtr->lastError;
+ result = 0;
+ break;
+ } else if (infoPtr->readyEvents & events) {
+ break;
+ } else if (infoPtr->flags & SOCKET_ASYNC) {
+ *errorCodePtr = EWOULDBLOCK;
+ result = 0;
+ break;
}
/*
- * Error message on synchronous connect
+ * Wait until something happens.
*/
- if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't open socket: %s", Tcl_PosixError(interp)));
- }
- return TCL_ERROR;
+ WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
}
- return TCL_OK;
+
+ (void) Tcl_SetServiceMode(oldMode);
+ return result;
}
/*
@@ -1982,62 +1299,40 @@ Tcl_OpenTcpClient(
const char *host, /* Host on which to open port. */
const char *myaddr, /* Client-side address */
int myport, /* Client-side port */
- int async) /* If nonzero, attempt to do an asynchronous
- * connect. Otherwise we do a blocking
- * connect. */
+ int async) /* If nonzero, should connect client socket
+ * asynchronously. */
{
- TcpState *statePtr;
- const char *errorMsg = NULL;
- struct addrinfo *addrlist = NULL, *myaddrlist = NULL;
- char channelName[SOCK_CHAN_LENGTH];
-
- TclInitSockets();
-
- /*
- * Do the name lookups for the local and remote addresses.
- */
+ SocketInfo *infoPtr;
+ char channelName[16 + TCL_INTEGER_SPACE];
- if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg)
- || !TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1,
- &errorMsg)) {
- if (addrlist != NULL) {
- freeaddrinfo(addrlist);
- }
- if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't open socket: %s", errorMsg));
- }
- return NULL;
- }
-
- statePtr = NewSocketInfo(INVALID_SOCKET);
- statePtr->addrlist = addrlist;
- statePtr->myaddrlist = myaddrlist;
- if (async) {
- SET_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
+ if (TclpHasSockets(interp) != TCL_OK) {
+ return NULL;
}
/*
* Create a new client socket and wrap it in a channel.
*/
- if (TcpConnect(interp, statePtr) != TCL_OK) {
- TcpCloseProc(statePtr, NULL);
+
+ infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async);
+ if (infoPtr == NULL) {
return NULL;
}
- TclWinGenerateChannelName(channelName, "sock", statePtr);
- statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
- statePtr, (TCL_READABLE | TCL_WRITABLE));
- if (TCL_ERROR == Tcl_SetChannelOption(NULL, statePtr->channel,
- "-translation", "auto crlf")) {
- Tcl_Close(NULL, statePtr->channel);
- return NULL;
- } else if (TCL_ERROR == Tcl_SetChannelOption(NULL, statePtr->channel,
- "-eofchar", "")) {
- Tcl_Close(NULL, statePtr->channel);
- return NULL;
+ sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t)infoPtr->socket);
+
+ infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
+ (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
+ if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation",
+ "auto crlf") == TCL_ERROR) {
+ Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
+ return (Tcl_Channel) NULL;
+ }
+ if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "")
+ == TCL_ERROR) {
+ Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
+ return (Tcl_Channel) NULL;
}
- return statePtr->channel;
+ return infoPtr->channel;
}
/*
@@ -2053,18 +1348,22 @@ Tcl_OpenTcpClient(
* Side effects:
* None.
*
+ * NOTE: Code contributed by Mark Diekhans (markd@grizzly.com)
+ *
*----------------------------------------------------------------------
*/
Tcl_Channel
Tcl_MakeTcpClientChannel(
- void *sock) /* The socket to wrap up into a channel. */
+ ClientData sock) /* The socket to wrap up into a channel. */
{
- TcpState *statePtr;
- char channelName[SOCK_CHAN_LENGTH];
+ SocketInfo *infoPtr;
+ char channelName[16 + TCL_INTEGER_SPACE];
ThreadSpecificData *tsdPtr;
- TclInitSockets();
+ if (TclpHasSockets(NULL) != TCL_OK) {
+ return NULL;
+ }
tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
@@ -2074,32 +1373,33 @@ Tcl_MakeTcpClientChannel(
TclSockMinimumBuffers(sock, TCP_BUFFER_SIZE);
- statePtr = NewSocketInfo((SOCKET) sock);
+ infoPtr = NewSocketInfo((SOCKET) sock);
/*
* Start watching for read/write events on the socket.
*/
- statePtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE;
- SendSelectMessage(tsdPtr, SELECT, statePtr);
+ infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE;
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) SELECT, (LPARAM) infoPtr);
- TclWinGenerateChannelName(channelName, "sock", statePtr);
- statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
- statePtr, (TCL_READABLE | TCL_WRITABLE));
- Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", "auto crlf");
- return statePtr->channel;
+ sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t)infoPtr->socket);
+ infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
+ (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
+ Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf");
+ return infoPtr->channel;
}
/*
*----------------------------------------------------------------------
*
- * Tcl_OpenTcpServerEx --
+ * Tcl_OpenTcpServer --
*
* Opens a TCP server socket and creates a channel around it.
*
* Results:
- * The channel or NULL if failed. If an error occurred, an error message
- * is left in the interp's result if interp is not NULL.
+ * The channel or NULL if failed. An error message is returned in the
+ * interpreter on failure.
*
* Side effects:
* Opens a server socket and creates a new channel.
@@ -2108,217 +1408,118 @@ Tcl_MakeTcpClientChannel(
*/
Tcl_Channel
-Tcl_OpenTcpServerEx(
+Tcl_OpenTcpServer(
Tcl_Interp *interp, /* For error reporting - may be NULL. */
- const char *service, /* Port number to open. */
- const char *myHost, /* Name of local host. */
- unsigned int flags, /* Flags. */
- int backlog, /* Length of OS listen backlog queue, or -1
- * for default. */
+ int port, /* Port number to open. */
+ const char *host, /* Name of local host. */
Tcl_TcpAcceptProc *acceptProc,
/* Callback for accepting connections from new
* clients. */
- void *acceptProcData) /* Data for the callback. */
+ ClientData acceptProcData) /* Data for the callback. */
{
- SOCKET sock = INVALID_SOCKET;
- unsigned short chosenport = 0;
- struct addrinfo *addrlist = NULL;
- struct addrinfo *addrPtr; /* Socket address to listen on. */
- TcpState *statePtr = NULL; /* The returned value. */
- char channelName[SOCK_CHAN_LENGTH];
- u_long flag = 1; /* Indicates nonblocking mode. */
- const char *errorMsg = NULL;
- int optvalue, port;
+ SocketInfo *infoPtr;
+ char channelName[16 + TCL_INTEGER_SPACE];
- TclInitSockets();
+ if (TclpHasSockets(interp) != TCL_OK) {
+ return NULL;
+ }
/*
- * Construct the addresses for each end of the socket.
+ * Create a new client socket and wrap it in a channel.
*/
- if (TclSockGetPort(interp, service, "tcp", &port) != TCL_OK) {
- errorMsg = "invalid port number";
- goto error;
- }
-
- if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1,
- &errorMsg)) {
- goto error;
- }
-
- for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) {
- sock = socket(addrPtr->ai_family, addrPtr->ai_socktype,
- addrPtr->ai_protocol);
- if (sock == INVALID_SOCKET) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
- continue;
- }
-
- /*
- * Win-NT has a misfeature that sockets are inherited in child
- * processes by default. Turn off the inherit bit.
- */
-
- SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
-
- /*
- * Set kernel space buffering
- */
-
- TclSockMinimumBuffers((void *)sock, TCP_BUFFER_SIZE);
-
- /*
- * Make sure we use the same port when opening two server sockets
- * for IPv4 and IPv6.
- *
- * As sockaddr_in6 uses the same offset and size for the port
- * member as sockaddr_in, we can handle both through the IPv4 API.
- */
-
- if (port == 0 && chosenport != 0) {
- ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port =
- htons(chosenport);
- }
-
- /*
- * The SO_REUSEADDR option on Windows behaves like SO_REUSEPORT on
- * unix systems.
- */
-
- if (GOT_BITS(flags, TCL_TCPSERVER_REUSEPORT)) {
- optvalue = 1;
- (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
- (char *) &optvalue, sizeof(optvalue));
- }
-
- /*
- * Bind to the specified port.
- *
- * Bind should not be affected by the socket having already been
- * set into nonblocking mode. If there is trouble, this is one
- * place to look for bugs.
- */
-
- if (bind(sock, addrPtr->ai_addr,
- addrPtr->ai_addrlen) == SOCKET_ERROR) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
- closesocket(sock);
- continue;
- }
- if (port == 0 && chosenport == 0) {
- address sockname;
- socklen_t namelen = sizeof(sockname);
-
- /*
- * Synchronize port numbers when binding to port 0 of multiple
- * addresses.
- */
-
- if (getsockname(sock, &sockname.sa, &namelen) >= 0) {
- chosenport = ntohs(sockname.sa4.sin_port);
- }
- }
-
- /*
- * Set the maximum number of pending connect requests to the max
- * value allowed on each platform (Win32 and Win32s may be
- * different, and there may be differences between TCP/IP stacks).
- */
-
- if (backlog < 0) {
- backlog = SOMAXCONN;
- }
- if (listen(sock, backlog) == SOCKET_ERROR) {
- Tcl_WinConvertError((DWORD) WSAGetLastError());
- closesocket(sock);
- continue;
- }
-
- if (statePtr == NULL) {
- /*
- * Add this socket to the global list of sockets.
- */
-
- statePtr = NewSocketInfo(sock);
- } else {
- AddSocketInfoFd(statePtr, sock);
- }
- }
-
- error:
- if (addrlist != NULL) {
- freeaddrinfo(addrlist);
+ infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0);
+ if (infoPtr == NULL) {
+ return NULL;
}
- if (statePtr != NULL) {
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
-
- statePtr->acceptProc = acceptProc;
- statePtr->acceptProcData = acceptProcData;
- TclWinGenerateChannelName(channelName, "sock", statePtr);
- statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
- statePtr, 0);
- /*
- * Set up the select mask for connection request events.
- */
-
- statePtr->selectEvents = FD_ACCEPT;
-
- /*
- * Register for interest in events in the select mask. Note that this
- * automatically places the socket into non-blocking mode.
- */
+ infoPtr->acceptProc = acceptProc;
+ infoPtr->acceptProcData = acceptProcData;
- ioctlsocket(sock, (long) FIONBIO, &flag);
- SendSelectMessage(tsdPtr, SELECT, statePtr);
- if (Tcl_SetChannelOption(interp, statePtr->channel, "-eofchar", "")
- == TCL_ERROR) {
- Tcl_Close(NULL, statePtr->channel);
- return NULL;
- }
- return statePtr->channel;
- }
+ sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t)infoPtr->socket);
- if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't open socket: %s",
- (errorMsg ? errorMsg : Tcl_PosixError(interp))));
+ infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
+ (ClientData) infoPtr, 0);
+ if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "")
+ == TCL_ERROR) {
+ Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
+ return (Tcl_Channel) NULL;
}
- if (sock != INVALID_SOCKET) {
- closesocket(sock);
- }
- return NULL;
+ return infoPtr->channel;
}
/*
*----------------------------------------------------------------------
*
* TcpAccept --
- * Accept a TCP socket connection. This is called by the event loop.
+ *
+ * Accept a TCP socket connection. This is called by SocketEventProc and
+ * it in turns calls the registered accept function.
*
* Results:
* None.
*
* Side effects:
- * Creates a new connection socket. Calls the registered callback for the
- * connection acceptance mechanism.
+ * Invokes the accept proc which may invoke arbitrary Tcl code.
*
*----------------------------------------------------------------------
*/
static void
TcpAccept(
- TcpFdList *fds, /* Server socket that accepted newSocket. */
- SOCKET newSocket, /* Newly accepted socket. */
- address addr) /* Address of new socket. */
+ SocketInfo *infoPtr) /* Socket to accept. */
{
- TcpState *newInfoPtr;
- TcpState *statePtr = fds->statePtr;
- int len = sizeof(addr);
- char channelName[SOCK_CHAN_LENGTH];
- char host[NI_MAXHOST], port[NI_MAXSERV];
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
+ SOCKET newSocket;
+ SocketInfo *newInfoPtr;
+ SOCKADDR_IN addr;
+ int len;
+ char channelName[16 + TCL_INTEGER_SPACE];
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ TclThreadDataKeyGet(&dataKey);
+
+ /*
+ * Accept the incoming connection request.
+ */
+
+ len = sizeof(SOCKADDR_IN);
+
+ newSocket = accept(infoPtr->socket, (SOCKADDR *)&addr,
+ &len);
+
+ /*
+ * Protect access to sockets (acceptEventCount, readyEvents) in socketList
+ * by the lock. Fix for SF Tcl Bug 3056775.
+ */
+ WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
+
+ /*
+ * Clear the ready mask so we can detect the next connection request. Note
+ * that connection requests are level triggered, so if there is a request
+ * already pending, a new event will be generated.
+ */
+
+ if (newSocket == INVALID_SOCKET) {
+ infoPtr->acceptEventCount = 0;
+ infoPtr->readyEvents &= ~(FD_ACCEPT);
+
+ SetEvent(tsdPtr->socketListLock);
+ return;
+ }
+
+ /*
+ * It is possible that more than one FD_ACCEPT has been sent, so an extra
+ * count must be kept. Decrement the count, and reset the readyEvent bit
+ * if the count is no longer > 0.
+ */
+
+ infoPtr->acceptEventCount--;
+
+ if (infoPtr->acceptEventCount <= 0) {
+ infoPtr->readyEvents &= ~(FD_ACCEPT);
+ }
+
+ SetEvent(tsdPtr->socketListLock);
/*
* Win-NT has a misfeature that sockets are inherited in child processes
@@ -2328,7 +1529,7 @@ TcpAccept(
SetHandleInformation((HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0);
/*
- * Add this socket to the global list of sockets.
+ * Allocate socket info structure
*/
newInfoPtr = NewSocketInfo(newSocket);
@@ -2338,19 +1539,20 @@ TcpAccept(
*/
newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE);
- SendSelectMessage(tsdPtr, SELECT, newInfoPtr);
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) SELECT, (LPARAM) newInfoPtr);
- TclWinGenerateChannelName(channelName, "sock", newInfoPtr);
+ sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t)newInfoPtr->socket);
newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
- newInfoPtr, (TCL_READABLE | TCL_WRITABLE));
+ (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE));
if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation",
"auto crlf") == TCL_ERROR) {
- Tcl_Close(NULL, newInfoPtr->channel);
+ Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
return;
}
if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-eofchar", "")
== TCL_ERROR) {
- Tcl_Close(NULL, newInfoPtr->channel);
+ Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
return;
}
@@ -2358,620 +1560,647 @@ TcpAccept(
* Invoke the accept callback function.
*/
- if (statePtr->acceptProc != NULL) {
- getnameinfo(&(addr.sa), len, host, sizeof(host), port, sizeof(port),
- NI_NUMERICHOST|NI_NUMERICSERV);
- statePtr->acceptProc(statePtr->acceptProcData, newInfoPtr->channel,
- host, atoi(port));
+ if (infoPtr->acceptProc != NULL) {
+ (infoPtr->acceptProc) (infoPtr->acceptProcData, newInfoPtr->channel,
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
}
}
/*
*----------------------------------------------------------------------
*
- * InitSocketWindowClass --
+ * TcpInputProc --
*
- * Registers the event window class for the socket notifier code.
- * Caller must not hold socket mutex lock.
+ * This function is called by the generic IO level to read data from a
+ * socket based channel.
*
* Results:
- * None.
+ * The number of bytes read or -1 on error.
*
* Side effects:
- * Register a new window class.
+ * Consumes input from the socket.
*
*----------------------------------------------------------------------
*/
-static void
-InitSocketWindowClass(void)
+static int
+TcpInputProc(
+ ClientData instanceData, /* The socket state. */
+ char *buf, /* Where to store data. */
+ int toRead, /* Maximum number of bytes to read. */
+ int *errorCodePtr) /* Where to store error codes. */
{
- if (initialized) {
- return;
+ SocketInfo *infoPtr = (SocketInfo *) instanceData;
+ int bytesRead;
+ DWORD error;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ TclThreadDataKeyGet(&dataKey);
+
+ *errorCodePtr = 0;
+
+ /*
+ * Check that WinSock is initialized; do not call it if not, to prevent
+ * system crashes. This can happen at exit time if the exit handler for
+ * WinSock ran before other exit handlers that want to use sockets.
+ */
+
+ if (!SocketsEnabled()) {
+ *errorCodePtr = EFAULT;
+ return -1;
}
- Tcl_MutexLock(&socketMutex);
- if (!initialized) {
- initialized = 1;
- TclCreateLateExitHandler(SocketExitHandler, NULL);
+
+ /*
+ * First check to see if EOF was already detected, to prevent calling the
+ * socket stack after the first time EOF is detected.
+ */
+
+ if (infoPtr->flags & SOCKET_EOF) {
+ return 0;
+ }
+
+ /*
+ * Check to see if the socket is connected before trying to read.
+ */
+
+ if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
+ && !WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) {
+ return -1;
+ }
+
+ /*
+ * No EOF, and it is connected, so try to read more from the socket. Note
+ * that we clear the FD_READ bit because read events are level triggered
+ * so a new event will be generated if there is still data available to be
+ * read. We have to simulate blocking behavior here since we are always
+ * using non-blocking sockets.
+ */
+
+ while (1) {
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) UNSELECT, (LPARAM) infoPtr);
+ bytesRead = recv(infoPtr->socket, buf, toRead, 0);
+ infoPtr->readyEvents &= ~(FD_READ);
/*
- * Create the async notification window with a new class. We must
- * create a new class to avoid a Windows 95 bug that causes us to get
- * the wrong message number for socket events if the message window is
- * a subclass of a static control.
+ * Check for end-of-file condition or successful read.
*/
- windowClass.style = 0;
- windowClass.cbClsExtra = 0;
- windowClass.cbWndExtra = 0;
- windowClass.hInstance = (HINSTANCE)TclWinGetTclInstance();
- windowClass.hbrBackground = NULL;
- windowClass.lpszMenuName = NULL;
- windowClass.lpszClassName = className;
- windowClass.lpfnWndProc = SocketProc;
- windowClass.hIcon = NULL;
- windowClass.hCursor = NULL;
+ if (bytesRead == 0) {
+ infoPtr->flags |= SOCKET_EOF;
+ }
+ if (bytesRead != SOCKET_ERROR) {
+ break;
+ }
- if (!RegisterClassW(&windowClass)) {
- Tcl_WinConvertError(GetLastError());
- goto initFailure;
+ /*
+ * If an error occurs after the FD_CLOSE has arrived, then ignore the
+ * error and report an EOF.
+ */
+
+ if (infoPtr->readyEvents & FD_CLOSE) {
+ infoPtr->flags |= SOCKET_EOF;
+ bytesRead = 0;
+ break;
+ }
+
+ error = WSAGetLastError();
+
+ /*
+ * If an RST comes, then ignore the error and report an EOF just like
+ * on unix.
+ */
+
+ if (error == WSAECONNRESET) {
+ infoPtr->flags |= SOCKET_EOF;
+ bytesRead = 0;
+ break;
+ }
+
+ /*
+ * Check for error condition or underflow in non-blocking case.
+ */
+
+ if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) {
+ TclWinConvertWSAError(error);
+ *errorCodePtr = Tcl_GetErrno();
+ bytesRead = -1;
+ break;
+ }
+
+ /*
+ * In the blocking case, wait until the file becomes readable or
+ * closed and try again.
+ */
+
+ if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) {
+ bytesRead = -1;
+ break;
}
}
- Tcl_MutexUnlock(&socketMutex);
- return;
- initFailure:
- Tcl_MutexUnlock(&socketMutex); /* Probably pointless before panicing */
- Tcl_Panic("InitSockets failed");
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) SELECT, (LPARAM) infoPtr);
+
+ return bytesRead;
}
/*
*----------------------------------------------------------------------
*
- * SocketExitHandler --
+ * TcpOutputProc --
*
- * Callback invoked during exit clean up to delete the socket
- * communication window.
+ * This function is called by the generic IO level to write data to a
+ * socket based channel.
*
* Results:
- * None.
+ * The number of bytes written or -1 on failure.
*
* Side effects:
- * None.
+ * Produces output on the socket.
*
*----------------------------------------------------------------------
*/
-static void
-SocketExitHandler(
- TCL_UNUSED(void *))
+static int
+TcpOutputProc(
+ ClientData instanceData, /* The socket state. */
+ const char *buf, /* Where to get data. */
+ int toWrite, /* Maximum number of bytes to write. */
+ int *errorCodePtr) /* Where to store error codes. */
{
- Tcl_MutexLock(&socketMutex);
+ SocketInfo *infoPtr = (SocketInfo *) instanceData;
+ int bytesWritten;
+ DWORD error;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ TclThreadDataKeyGet(&dataKey);
+
+ *errorCodePtr = 0;
/*
- * Make sure the socket event handling window is cleaned-up for, at
- * most, this thread.
+ * Check that WinSock is initialized; do not call it if not, to prevent
+ * system crashes. This can happen at exit time if the exit handler for
+ * WinSock ran before other exit handlers that want to use sockets.
*/
- TclpFinalizeSockets();
- UnregisterClassW(className, (HINSTANCE)TclWinGetTclInstance());
- initialized = 0;
- Tcl_MutexUnlock(&socketMutex);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * SocketSetupProc --
- *
- * This function is invoked before Tcl_DoOneEvent blocks waiting for an
- * event.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Adjusts the block time if needed.
- *
- *----------------------------------------------------------------------
- */
-
-void
-SocketSetupProc(
- TCL_UNUSED(void *),
- int flags) /* Event flags as passed to Tcl_DoOneEvent. */
-{
- TcpState *statePtr;
- Tcl_Time blockTime = { 0, 0 };
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
- if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
- return;
+ if (!SocketsEnabled()) {
+ *errorCodePtr = EFAULT;
+ return -1;
}
/*
- * Check to see if there is a ready socket. If so, poll.
+ * Check to see if the socket is connected before trying to write.
*/
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- for (statePtr = tsdPtr->socketList; statePtr != NULL;
- statePtr = statePtr->nextPtr) {
- if (GOT_BITS(statePtr->readyEvents,
- statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)) {
- Tcl_SetMaxBlockTime(&blockTime);
+
+ if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
+ && !WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) {
+ return -1;
+ }
+
+ while (1) {
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) UNSELECT, (LPARAM) infoPtr);
+
+ bytesWritten = send(infoPtr->socket, buf, toWrite, 0);
+ if (bytesWritten != SOCKET_ERROR) {
+ /*
+ * Since Windows won't generate a new write event until we hit an
+ * overflow condition, we need to force the event loop to poll
+ * until the condition changes.
+ */
+
+ if (infoPtr->watchEvents & FD_WRITE) {
+ Tcl_Time blockTime = { 0, 0 };
+ Tcl_SetMaxBlockTime(&blockTime);
+ }
+ break;
+ }
+
+ /*
+ * Check for error condition or overflow. In the event of overflow, we
+ * need to clear the FD_WRITE flag so we can detect the next writable
+ * event. Note that Windows only sends a new writable event after a
+ * send fails with WSAEWOULDBLOCK.
+ */
+
+ error = WSAGetLastError();
+ if (error == WSAEWOULDBLOCK) {
+ infoPtr->readyEvents &= ~(FD_WRITE);
+ if (infoPtr->flags & SOCKET_ASYNC) {
+ *errorCodePtr = EWOULDBLOCK;
+ bytesWritten = -1;
+ break;
+ }
+ } else {
+ TclWinConvertWSAError(error);
+ *errorCodePtr = Tcl_GetErrno();
+ bytesWritten = -1;
+ break;
+ }
+
+ /*
+ * In the blocking case, wait until the file becomes writable or
+ * closed and try again.
+ */
+
+ if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) {
+ bytesWritten = -1;
break;
}
}
- SetEvent(tsdPtr->socketListLock);
+
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) SELECT, (LPARAM) infoPtr);
+
+ return bytesWritten;
}
/*
*----------------------------------------------------------------------
*
- * SocketCheckProc --
+ * TcpSetOptionProc --
*
- * This function is called by Tcl_DoOneEvent to check the socket event
- * source for events.
+ * Sets Tcp channel specific options.
*
* Results:
- * None.
+ * None, unless an error happens.
*
* Side effects:
- * May queue an event.
+ * Changes attributes of the socket at the system level.
*
*----------------------------------------------------------------------
*/
-static void
-SocketCheckProc(
- TCL_UNUSED(void *),
- int flags) /* Event flags as passed to Tcl_DoOneEvent. */
+static int
+TcpSetOptionProc(
+ ClientData instanceData, /* Socket state. */
+ Tcl_Interp *interp, /* For error reporting - can be NULL. */
+ const char *optionName, /* Name of the option to set. */
+ const char *value) /* New value for option. */
{
- TcpState *statePtr;
- SocketEvent *evPtr;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
- if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
- return;
- }
+#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
+ SocketInfo *infoPtr;
+ SOCKET sock;
+#endif
/*
- * Queue events for any ready sockets that don't already have events
- * queued (caused by persistent states that won't generate WinSock
- * events).
+ * Check that WinSock is initialized; do not call it if not, to prevent
+ * system crashes. This can happen at exit time if the exit handler for
+ * WinSock ran before other exit handlers that want to use sockets.
*/
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- for (statePtr = tsdPtr->socketList; statePtr != NULL;
- statePtr = statePtr->nextPtr) {
- if (GOT_BITS(statePtr->readyEvents,
- statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)
- && !GOT_BITS(statePtr->flags, SOCKET_PENDING)) {
- SET_BITS(statePtr->flags, SOCKET_PENDING);
- evPtr = (SocketEvent *)ckalloc(sizeof(SocketEvent));
- evPtr->header.proc = SocketEventProc;
- evPtr->socket = statePtr->sockets->fd;
- Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
+ if (!SocketsEnabled()) {
+ if (interp) {
+ Tcl_AppendResult(interp, "winsock is not initialized", NULL);
}
+ return TCL_ERROR;
}
- SetEvent(tsdPtr->socketListLock);
+
+#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
+ infoPtr = (SocketInfo *) instanceData;
+ sock = infoPtr->socket;
+
+ if (!strcasecmp(optionName, "-keepalive")) {
+ BOOL val = FALSE;
+ int boolVar, rtn;
+
+ if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (boolVar) {
+ val = TRUE;
+ }
+ rtn = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
+ (const char *) &val, sizeof(BOOL));
+ if (rtn != 0) {
+ TclWinConvertWSAError(WSAGetLastError());
+ if (interp) {
+ Tcl_AppendResult(interp, "couldn't set socket option: ",
+ Tcl_PosixError(interp), NULL);
+ }
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+ } else if (!strcasecmp(optionName, "-nagle")) {
+ BOOL val = FALSE;
+ int boolVar, rtn;
+
+ if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (!boolVar) {
+ val = TRUE;
+ }
+ rtn = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ (const char *) &val, sizeof(BOOL));
+ if (rtn != 0) {
+ TclWinConvertWSAError(WSAGetLastError());
+ if (interp) {
+ Tcl_AppendResult(interp, "couldn't set socket option: ",
+ Tcl_PosixError(interp), NULL);
+ }
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+ }
+
+ return Tcl_BadChannelOption(interp, optionName, "keepalive nagle");
+#else
+ return Tcl_BadChannelOption(interp, optionName, "");
+#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/
}
/*
*----------------------------------------------------------------------
*
- * SocketEventProc --
+ * TcpGetOptionProc --
*
- * This function is called by Tcl_ServiceEvent when a socket event
- * reaches the front of the event queue. This function is responsible for
- * notifying the generic channel code.
+ * Computes an option value for a TCP socket based channel, or a list of
+ * all options and their values.
+ *
+ * Note: This code is based on code contributed by John Haxby.
*
* Results:
- * Returns 1 if the event was handled, meaning it should be removed from
- * the queue. Returns 0 if the event was not handled, meaning it should
- * stay on the queue. The only time the event isn't handled is if the
- * TCL_FILE_EVENTS flag bit isn't set.
+ * A standard Tcl result. The value of the specified option or a list of
+ * all options and their values is returned in the supplied DString.
*
* Side effects:
- * Whatever the channel callback functions do.
+ * None.
*
*----------------------------------------------------------------------
*/
static int
-SocketEventProc(
- Tcl_Event *evPtr, /* Event to service. */
- int flags) /* Flags that indicate what events to handle,
- * such as TCL_FILE_EVENTS. */
+TcpGetOptionProc(
+ ClientData instanceData, /* Socket state. */
+ Tcl_Interp *interp, /* For error reporting - can be NULL */
+ const char *optionName, /* Name of the option to retrieve the value
+ * for, or NULL to get all options and their
+ * values. */
+ Tcl_DString *dsPtr) /* Where to store the computed value;
+ * initialized by caller. */
{
- TcpState *statePtr;
- SocketEvent *eventPtr = (SocketEvent *) evPtr;
- int mask = 0, events;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- TcpFdList *fds;
- SOCKET newSocket;
- address addr;
- int len;
-
- if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
- return 0;
- }
+ SocketInfo *infoPtr;
+ SOCKADDR_IN sockname;
+ SOCKADDR_IN peername;
+ struct hostent *hostEntPtr;
+ SOCKET sock;
+ int size = sizeof(SOCKADDR_IN);
+ size_t len = 0;
+ char buf[TCL_INTEGER_SPACE];
/*
- * Find the specified socket on the socket list.
+ * Check that WinSock is initialized; do not call it if not, to prevent
+ * system crashes. This can happen at exit time if the exit handler for
+ * WinSock ran before other exit handlers that want to use sockets.
*/
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- for (statePtr = tsdPtr->socketList; statePtr != NULL;
- statePtr = statePtr->nextPtr) {
- if (statePtr->sockets->fd == eventPtr->socket) {
- break;
+ if (!SocketsEnabled()) {
+ if (interp) {
+ Tcl_AppendResult(interp, "winsock is not initialized", NULL);
}
+ return TCL_ERROR;
}
- /*
- * Discard events that have gone stale.
- */
-
- if (!statePtr) {
- SetEvent(tsdPtr->socketListLock);
- return 1;
+ infoPtr = (SocketInfo *) instanceData;
+ sock = (int) infoPtr->socket;
+ if (optionName != NULL) {
+ len = strlen(optionName);
}
- /*
- * Clear flag that (this) event is pending
- */
-
- CLEAR_BITS(statePtr->flags, SOCKET_PENDING);
-
- /*
- * Continue async connect if pending and ready
- */
+ if ((len > 1) && (optionName[1] == 'e') &&
+ (strncmp(optionName, "-error", len) == 0)) {
+ int optlen;
+ DWORD err;
+ int ret;
+
+ optlen = sizeof(int);
+ ret = TclWinGetSockOpt((int)sock, SOL_SOCKET, SO_ERROR,
+ (char *)&err, &optlen);
+ if (ret == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ }
+ if (err) {
+ TclWinConvertWSAError(err);
+ Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1);
+ }
+ return TCL_OK;
+ }
- if (GOT_BITS(statePtr->readyEvents, FD_CONNECT)) {
- if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
- /*
- * Do one step and save eventual connect error
- */
+ if ((len == 0) || ((len > 1) && (optionName[1] == 'p') &&
+ (strncmp(optionName, "-peername", len) == 0))) {
+ if (getpeername(sock, (LPSOCKADDR) &peername, &size) == 0) {
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-peername");
+ Tcl_DStringStartSublist(dsPtr);
+ }
+ Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr));
- SetEvent(tsdPtr->socketListLock);
- WaitForConnect(statePtr,NULL);
+ if (peername.sin_addr.s_addr == 0) {
+ hostEntPtr = NULL;
+ } else {
+ hostEntPtr = gethostbyaddr((char *) &(peername.sin_addr),
+ sizeof(peername.sin_addr), AF_INET);
+ }
+ if (hostEntPtr != NULL) {
+ Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
+ } else {
+ Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr));
+ }
+ TclFormatInt(buf, ntohs(peername.sin_port));
+ Tcl_DStringAppendElement(dsPtr, buf);
+ if (len == 0) {
+ Tcl_DStringEndSublist(dsPtr);
+ } else {
+ return TCL_OK;
+ }
} else {
/*
- * No async connect reenter pending. Just clear event.
+ * getpeername failed - but if we were asked for all the options
+ * (len==0), don't flag an error at that point because it could be
+ * an fconfigure request on a server socket (such sockets have no
+ * peer). {Copied from unix/tclUnixChan.c}
*/
- CLEAR_BITS(statePtr->readyEvents, FD_CONNECT);
- SetEvent(tsdPtr->socketListLock);
+ if (len) {
+ TclWinConvertWSAError((DWORD) WSAGetLastError());
+ if (interp) {
+ Tcl_AppendResult(interp, "can't get peername: ",
+ Tcl_PosixError(interp), NULL);
+ }
+ return TCL_ERROR;
+ }
}
- return 1;
}
- /*
- * Handle connection requests directly.
- */
-
- if (GOT_BITS(statePtr->readyEvents, FD_ACCEPT)) {
- for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
- /*
- * Accept the incoming connection request.
- */
-
- len = sizeof(address);
- newSocket = accept(fds->fd, &(addr.sa), &len);
-
- /*
- * On Tcl server sockets with multiple OS fds we loop over the fds
- * trying an accept() on each, so we expect INVALID_SOCKET. There
- * are also other network stack conditions that can result in
- * FD_ACCEPT but a subsequent failure on accept() by the time we
- * get around to it.
- *
- * Access to sockets (acceptEventCount, readyEvents) in socketList
- * is still protected by the lock (prevents reintroduction of
- * SF Tcl Bug 3056775.
- */
-
- if (newSocket == INVALID_SOCKET) {
- /* int err = WSAGetLastError(); */
- continue;
+ if ((len == 0) || ((len > 1) && (optionName[1] == 's') &&
+ (strncmp(optionName, "-sockname", len) == 0))) {
+ if (getsockname(sock, (LPSOCKADDR) &sockname, &size) == 0) {
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-sockname");
+ Tcl_DStringStartSublist(dsPtr);
}
-
- /*
- * It is possible that more than one FD_ACCEPT has been sent, so
- * an extra count must be kept. Decrement the count, and reset the
- * readyEvent bit if the count is no longer > 0.
- */
-
- statePtr->acceptEventCount--;
-
- if (statePtr->acceptEventCount <= 0) {
- CLEAR_BITS(statePtr->readyEvents, FD_ACCEPT);
+ Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr));
+ if (sockname.sin_addr.s_addr == 0) {
+ hostEntPtr = NULL;
+ } else {
+ hostEntPtr = gethostbyaddr((char *) &(sockname.sin_addr),
+ sizeof(peername.sin_addr), AF_INET);
}
-
- SetEvent(tsdPtr->socketListLock);
-
- /*
- * Caution: TcpAccept() has the side-effect of evaluating the
- * server accept script (via AcceptCallbackProc() in tclIOCmd.c),
- * which can close the server socket and invalidate statePtr and
- * fds. If TcpAccept() accepts a socket we must return immediately
- * and let SocketCheckProc queue additional FD_ACCEPT events.
- */
-
- TcpAccept(fds, newSocket, addr);
- return 1;
+ if (hostEntPtr != NULL) {
+ Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
+ } else {
+ Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr));
+ }
+ TclFormatInt(buf, ntohs(sockname.sin_port));
+ Tcl_DStringAppendElement(dsPtr, buf);
+ if (len == 0) {
+ Tcl_DStringEndSublist(dsPtr);
+ } else {
+ return TCL_OK;
+ }
+ } else {
+ if (interp) {
+ TclWinConvertWSAError((DWORD) WSAGetLastError());
+ Tcl_AppendResult(interp, "can't get sockname: ",
+ Tcl_PosixError(interp), NULL);
+ }
+ return TCL_ERROR;
}
-
- /*
- * Loop terminated with no sockets accepted; clear the ready mask so
- * we can detect the next connection request. Note that connection
- * requests are level triggered, so if there is a request already
- * pending, a new event will be generated.
- */
-
- statePtr->acceptEventCount = 0;
- CLEAR_BITS(statePtr->readyEvents, FD_ACCEPT);
-
- SetEvent(tsdPtr->socketListLock);
- return 1;
}
- SetEvent(tsdPtr->socketListLock);
-
- /*
- * Mask off unwanted events and compute the read/write mask so we can
- * notify the channel.
- */
-
- events = statePtr->readyEvents & statePtr->watchEvents;
-
- if (GOT_BITS(events, FD_CLOSE)) {
- /*
- * If the socket was closed and the channel is still interested in
- * read events, then we need to ensure that we keep polling for this
- * event until someone does something with the channel. Note that we
- * do this before calling Tcl_NotifyChannel so we don't have to watch
- * out for the channel being deleted out from under us. This may cause
- * a redundant trip through the event loop, but it's simpler than
- * trying to do unwind protection.
- */
-
- Tcl_Time blockTime = { 0, 0 };
-
- Tcl_SetMaxBlockTime(&blockTime);
- SET_BITS(mask, TCL_READABLE | TCL_WRITABLE);
- } else if (GOT_BITS(events, FD_READ)) {
- /*
- * Throw the readable event if an async connect failed.
- */
+#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
+ if (len == 0 || !strncmp(optionName, "-keepalive", len)) {
+ int optlen;
+ BOOL opt = FALSE;
- if (GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
- SET_BITS(mask, TCL_READABLE);
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-keepalive");
+ }
+ optlen = sizeof(BOOL);
+ getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, &optlen);
+ if (opt) {
+ Tcl_DStringAppendElement(dsPtr, "1");
} else {
- fd_set readFds;
- struct timeval timeout;
-
- /*
- * We must check to see if data is really available, since someone
- * could have consumed the data in the meantime. Turn off async
- * notification so select will work correctly. If the socket is
- * still readable, notify the channel driver, otherwise reset the
- * async select handler and keep waiting.
- */
-
- SendSelectMessage(tsdPtr, UNSELECT, statePtr);
-
- FD_ZERO(&readFds);
- FD_SET(statePtr->sockets->fd, &readFds);
- timeout.tv_usec = 0;
- timeout.tv_sec = 0;
-
- if (select(0, &readFds, NULL, NULL, &timeout) != 0) {
- SET_BITS(mask, TCL_READABLE);
- } else {
- CLEAR_BITS(statePtr->readyEvents, FD_READ);
- SendSelectMessage(tsdPtr, SELECT, statePtr);
- }
+ Tcl_DStringAppendElement(dsPtr, "0");
+ }
+ if (len > 0) {
+ return TCL_OK;
}
}
- /*
- * writable event
- */
+ if (len == 0 || !strncmp(optionName, "-nagle", len)) {
+ int optlen;
+ BOOL opt = FALSE;
- if (GOT_BITS(events, FD_WRITE)) {
- SET_BITS(mask, TCL_WRITABLE);
+ if (len == 0) {
+ Tcl_DStringAppendElement(dsPtr, "-nagle");
+ }
+ optlen = sizeof(BOOL);
+ getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt,
+ &optlen);
+ if (opt) {
+ Tcl_DStringAppendElement(dsPtr, "0");
+ } else {
+ Tcl_DStringAppendElement(dsPtr, "1");
+ }
+ if (len > 0) {
+ return TCL_OK;
+ }
}
+#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/
- /*
- * Call registered event procedures
- */
-
- if (mask) {
- Tcl_NotifyChannel(statePtr->channel, mask);
+ if (len > 0) {
+#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
+ return Tcl_BadChannelOption(interp, optionName,
+ "peername sockname keepalive nagle");
+#else
+ return Tcl_BadChannelOption(interp, optionName, "peername sockname");
+#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/
}
- return 1;
+
+ return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
- * AddSocketInfoFd --
+ * TcpWatchProc --
*
- * This function adds a SOCKET file descriptor to the 'sockets' linked
- * list of a TcpState structure.
+ * Informs the channel driver of the events that the generic channel code
+ * wishes to receive on this socket.
*
* Results:
* None.
*
* Side effects:
- * None, except for allocation of memory.
+ * May cause the notifier to poll if any of the specified conditions are
+ * already true.
*
*----------------------------------------------------------------------
*/
static void
-AddSocketInfoFd(
- TcpState *statePtr,
- SOCKET socket)
+TcpWatchProc(
+ ClientData instanceData, /* The socket state. */
+ int mask) /* Events of interest; an OR-ed combination of
+ * TCL_READABLE, TCL_WRITABLE and
+ * TCL_EXCEPTION. */
{
- TcpFdList *fds = statePtr->sockets;
+ SocketInfo *infoPtr = (SocketInfo *) instanceData;
- if (fds == NULL) {
- /*
- * Add the first FD.
- */
+ /*
+ * Update the watch events mask. Only if the socket is not a server
+ * socket. Fix for SF Tcl Bug #557878.
+ */
+
+ if (!infoPtr->acceptProc) {
+ infoPtr->watchEvents = 0;
+ if (mask & TCL_READABLE) {
+ infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT);
+ }
+ if (mask & TCL_WRITABLE) {
+ infoPtr->watchEvents |= (FD_WRITE|FD_CLOSE|FD_CONNECT);
+ }
- statePtr->sockets = (TcpFdList *)ckalloc(sizeof(TcpFdList));
- fds = statePtr->sockets;
- } else {
/*
- * Find end of list and append FD.
+ * If there are any conditions already set, then tell the notifier to
+ * poll rather than block.
*/
- while (fds->next != NULL) {
- fds = fds->next;
+ if (infoPtr->readyEvents & infoPtr->watchEvents) {
+ Tcl_Time blockTime = { 0, 0 };
+ Tcl_SetMaxBlockTime(&blockTime);
}
-
- fds->next = (TcpFdList *)ckalloc(sizeof(TcpFdList));
- fds = fds->next;
}
-
- /*
- * Populate new FD.
- */
-
- fds->fd = socket;
- fds->statePtr = statePtr;
- fds->next = NULL;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * NewSocketInfo --
- *
- * This function allocates and initializes a new TcpState structure.
- *
- * Results:
- * Returns a newly allocated TcpState.
- *
- * Side effects:
- * None, except for allocation of memory.
- *
- *----------------------------------------------------------------------
- */
-
-static TcpState *
-NewSocketInfo(SOCKET socket)
-{
- TcpState *statePtr = (TcpState *)ckalloc(sizeof(TcpState));
-
- memset(statePtr, 0, sizeof(TcpState));
-
- /*
- * TIP #218. Removed the code inserting the new structure into the global
- * list. This is now handled in the thread action callbacks, and only
- * there.
- */
-
- AddSocketInfoFd(statePtr, socket);
-
- return statePtr;
}
/*
*----------------------------------------------------------------------
*
- * WaitForSocketEvent --
+ * TcpGetProc --
*
- * Waits until one of the specified events occurs on a socket.
- * For event FD_CONNECT use WaitForConnect.
+ * Called from Tcl_GetChannelHandle to retrieve an OS handle from inside
+ * a TCP socket based channel.
*
* Results:
- * Returns 1 on success or 0 on failure, with an error code in
- * errorCodePtr.
+ * Returns TCL_OK with the socket in handlePtr.
*
* Side effects:
- * Processes socket events off the system queue.
+ * None.
*
*----------------------------------------------------------------------
*/
static int
-WaitForSocketEvent(
- TcpState *statePtr, /* Information about this socket. */
- int events, /* Events to look for. May be one of
- * FD_READ or FD_WRITE.
- */
- int *errorCodePtr) /* Where to store errors? */
+TcpGetHandleProc(
+ ClientData instanceData, /* The socket state. */
+ int direction, /* Not used. */
+ ClientData *handlePtr) /* Where to store the handle. */
{
- int result = 1;
- int oldMode;
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
-
- /*
- * Be sure to disable event servicing so we are truly modal.
- */
-
- oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
-
- /*
- * Reset WSAAsyncSelect so we have a fresh set of events pending.
- */
-
- SendSelectMessage(tsdPtr, UNSELECT, statePtr);
- SendSelectMessage(tsdPtr, SELECT, statePtr);
-
- while (1) {
- int event_found;
-
- /*
- * Get statePtr lock.
- */
-
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
+ SocketInfo *statePtr = (SocketInfo *) instanceData;
- /*
- * Check if event occurred.
- */
-
- event_found = GOT_BITS(statePtr->readyEvents, events);
-
- /*
- * Free list lock.
- */
-
- SetEvent(tsdPtr->socketListLock);
-
- /*
- * Exit loop if event occurred.
- */
-
- if (event_found) {
- break;
- }
-
- /*
- * Exit loop if event did not occur but this is a non-blocking channel
- */
-
- if (statePtr->flags & TCP_NONBLOCKING) {
- *errorCodePtr = EWOULDBLOCK;
- result = 0;
- break;
- }
-
- /*
- * Wait until something happens.
- */
-
- WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
- }
-
- (void) Tcl_SetServiceMode(oldMode);
- return result;
+ *handlePtr = (ClientData) statePtr->socket;
+ return TCL_OK;
}
/*
@@ -2995,14 +2224,14 @@ SocketThread(
LPVOID arg)
{
MSG msg;
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)arg;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg);
/*
* Create a dummy window receiving socket events.
*/
- tsdPtr->hwnd = CreateWindowW(className, className, WS_TILED, 0, 0, 0, 0,
- NULL, NULL, windowClass.hInstance, arg);
+ tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket",
+ WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg);
/*
* Signalize thread creator that we are done creating the window.
@@ -3021,11 +2250,11 @@ SocketThread(
/*
* Process all messages on the socket window until WM_QUIT. This threads
* exits only when instructed to do so by the call to
- * PostMessageW(SOCKET_TERMINATE) in TclpFinalizeSockets().
+ * PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets().
*/
- while (GetMessageW(&msg, NULL, 0, 0) > 0) {
- DispatchMessageW(&msg);
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ DispatchMessage(&msg);
}
/*
@@ -3051,7 +2280,7 @@ SocketThread(
*
* Side effects:
* The flags for the given socket are updated to reflect the event that
- * occurred.
+ * occured.
*
*----------------------------------------------------------------------
*/
@@ -3065,19 +2294,18 @@ SocketProc(
{
int event, error;
SOCKET socket;
- TcpState *statePtr;
+ SocketInfo *infoPtr;
int info_found = 0;
- TcpFdList *fds = NULL;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
#ifdef _WIN64
- GetWindowLongPtrW(hwnd, GWLP_USERDATA);
+ GetWindowLongPtr(hwnd, GWLP_USERDATA);
#else
- GetWindowLongW(hwnd, GWL_USERDATA);
+ GetWindowLong(hwnd, GWL_USERDATA);
#endif
switch (message) {
default:
- return DefWindowProcW(hwnd, message, wParam, lParam);
+ return DefWindowProc(hwnd, message, wParam, lParam);
break;
case WM_CREATE:
@@ -3087,10 +2315,10 @@ SocketProc(
*/
#ifdef _WIN64
- SetWindowLongPtrW(hwnd, GWLP_USERDATA,
+ SetWindowLongPtr(hwnd, GWLP_USERDATA,
(LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams);
#else
- SetWindowLongW(hwnd, GWL_USERDATA,
+ SetWindowLong(hwnd, GWL_USERDATA,
(LONG) ((LPCREATESTRUCT)lParam)->lpCreateParams);
#endif
break;
@@ -3104,63 +2332,73 @@ SocketProc(
error = WSAGETSELECTERROR(lParam);
socket = (SOCKET) wParam;
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
-
/*
* Find the specified socket on the socket list and update its
* eventState flag.
*/
- for (statePtr = tsdPtr->socketList; statePtr != NULL;
- statePtr = statePtr->nextPtr) {
- if (FindFDInList(statePtr, socket)) {
+ WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
+ for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
+ infoPtr = infoPtr->nextPtr) {
+ if (infoPtr->socket == socket) {
info_found = 1;
break;
}
}
-
/*
- * Check if there is a pending info structure not jet in the list.
+ * Check if there is a pending info structure not jet in the
+ * list
*/
-
- if (!info_found
- && tsdPtr->pendingTcpState != NULL
- && FindFDInList(tsdPtr->pendingTcpState, socket)) {
- statePtr = tsdPtr->pendingTcpState;
+ if ( !info_found
+ && tsdPtr->pendingSocketInfo != NULL
+ && tsdPtr->pendingSocketInfo->socket ==socket ) {
+ infoPtr = tsdPtr->pendingSocketInfo;
info_found = 1;
}
if (info_found) {
+
/*
* Update the socket state.
*
* A count of FD_ACCEPTS is stored, so if an FD_CLOSE event
- * happens, then clear the FD_ACCEPT count. Otherwise, increment
- * the count if the current event is an FD_ACCEPT.
+ * happens, then clear the FD_ACCEPT count. Otherwise,
+ * increment the count if the current event is an FD_ACCEPT.
*/
- if (GOT_BITS(event, FD_CLOSE)) {
- statePtr->acceptEventCount = 0;
- CLEAR_BITS(statePtr->readyEvents, FD_WRITE | FD_ACCEPT);
- } else if (GOT_BITS(event, FD_ACCEPT)) {
- statePtr->acceptEventCount++;
+ if (event & FD_CLOSE) {
+ infoPtr->acceptEventCount = 0;
+ infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT);
+ } else if (event & FD_ACCEPT) {
+ infoPtr->acceptEventCount++;
}
- if (GOT_BITS(event, FD_CONNECT)) {
+ if (event & FD_CONNECT) {
+ /*
+ * The socket is now connected, clear the async connect
+ * flag.
+ */
+
+ infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
+
/*
* Remember any error that occurred so we can report
* connection failures.
*/
if (error != ERROR_SUCCESS) {
- statePtr->notifierConnectError = error;
+ /* Async Connect error */
+ TclWinConvertWSAError((DWORD) error);
+ infoPtr->lastError = Tcl_GetErrno();
+ /* Fire also readable event on connect failure */
+ infoPtr->readyEvents |= FD_READ;
}
- }
- /*
- * Inform main thread about signaled events
- */
+ /* fire writable event on connect */
+ infoPtr->readyEvents |= FD_WRITE;
- SET_BITS(statePtr->readyEvents, event);
+ }
+
+ infoPtr->readyEvents |= event;
/*
* Wake up the Main Thread.
@@ -3173,18 +2411,20 @@ SocketProc(
break;
case SOCKET_SELECT:
- statePtr = (TcpState *) lParam;
- for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
- if (wParam == SELECT) {
- WSAAsyncSelect(fds->fd, hwnd,
- SOCKET_MESSAGE, statePtr->selectEvents);
- } else {
- /*
- * Clear the selection mask
- */
+ infoPtr = (SocketInfo *) lParam;
+ if (wParam == SELECT) {
+ /*
+ * Start notification by windows messages on socket events
+ */
- WSAAsyncSelect(fds->fd, hwnd, 0, 0);
- }
+ WSAAsyncSelect(infoPtr->socket, hwnd,
+ SOCKET_MESSAGE, infoPtr->selectEvents);
+ } else {
+ /*
+ * UNSELECT: Clear the selection mask
+ */
+
+ WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0);
}
break;
@@ -3199,31 +2439,83 @@ SocketProc(
/*
*----------------------------------------------------------------------
*
- * FindFDInList --
+ * Tcl_GetHostName --
*
- * Return true, if the given file descriptor is contained in the
- * file descriptor list.
+ * Returns the name of the local host.
*
* Results:
- * true if found.
+ * A string containing the network name for this machine. The caller must
+ * not modify or free this string.
*
* Side effects:
+ * Caches the name to return for future calls.
*
*----------------------------------------------------------------------
*/
-static int
-FindFDInList(
- TcpState *statePtr,
- SOCKET socket)
+const char *
+Tcl_GetHostName(void)
{
- TcpFdList *fds;
- for (fds = statePtr->sockets; fds != NULL; fds = fds->next) {
- if (fds->fd == socket) {
- return 1;
+ return Tcl_GetString(TclGetProcessGlobalValue(&hostName));
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * InitializeHostName --
+ *
+ * This routine sets the process global value of the name of the local
+ * host on which the process is running.
+ *
+ * Results:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+InitializeHostName(
+ char **valuePtr,
+ int *lengthPtr,
+ Tcl_Encoding *encodingPtr)
+{
+ WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD length = sizeof(wbuf) / sizeof(WCHAR);
+ Tcl_DString ds;
+
+ if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) {
+ /*
+ * Convert string from native to UTF then change to lowercase.
+ */
+
+ Tcl_UtfToLower(Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds));
+
+ } else {
+ Tcl_DStringInit(&ds);
+ if (TclpHasSockets(NULL) == TCL_OK) {
+ /*
+ * The buffer size of 256 is recommended by the MSDN page that
+ * documents gethostname() as being always adequate.
+ */
+
+ Tcl_DString inDs;
+
+ Tcl_DStringInit(&inDs);
+ Tcl_DStringSetLength(&inDs, 256);
+ if (gethostname(Tcl_DStringValue(&inDs),
+ Tcl_DStringLength(&inDs)) == 0) {
+ Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&inDs), -1,
+ &ds);
+ }
+ Tcl_DStringFree(&inDs);
}
}
- return 0;
+
+ *encodingPtr = Tcl_GetEncoding(NULL, "utf-8");
+ *lengthPtr = Tcl_DStringLength(&ds);
+ *valuePtr = ckalloc((unsigned int) (*lengthPtr)+1);
+ memcpy(*valuePtr, Tcl_DStringValue(&ds), (size_t)(*lengthPtr)+1);
+ Tcl_DStringFree(&ds);
}
/*
@@ -3231,11 +2523,10 @@ FindFDInList(
*
* TclWinGetSockOpt, et al. --
*
- * Those functions are historically exported by the stubs table and
- * just use the original system calls now.
- *
- * Warning:
- * Those functions are depreciated and will be removed with TCL 9.0.
+ * These functions are wrappers that let us bind the WinSock API
+ * dynamically so we can run on systems that don't have the wsock32.dll.
+ * We need wrappers for these interfaces because they are called from the
+ * generic Tcl code.
*
* Results:
* As defined for each function.
@@ -3246,38 +2537,28 @@ FindFDInList(
*----------------------------------------------------------------------
*/
-#ifndef TCL_NO_DEPRECATED
#undef TclWinGetSockOpt
int
-TclWinGetSockOpt(
- SOCKET s,
- int level,
- int optname,
- char *optval,
- int *optlen)
+TclWinGetSockOpt(SOCKET s, int level, int optname, char *optval,
+ int *optlen)
{
-
return getsockopt(s, level, optname, optval, optlen);
}
+
#undef TclWinSetSockOpt
int
-TclWinSetSockOpt(
- SOCKET s,
- int level,
- int optname,
- const char *optval,
+TclWinSetSockOpt(SOCKET s, int level, int optname, const char *optval,
int optlen)
{
return setsockopt(s, level, optname, optval, optlen);
}
-#undef TclpInetNtoa
char *
-TclpInetNtoa(
- struct in_addr addr)
+TclpInetNtoa(struct in_addr addr)
{
return inet_ntoa(addr);
}
+
#undef TclWinGetServByName
struct servent *
TclWinGetServByName(
@@ -3286,7 +2567,6 @@ TclWinGetServByName(
{
return getservbyname(name, proto);
}
-#endif /* TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
@@ -3306,11 +2586,11 @@ TclWinGetServByName(
static void
TcpThreadActionProc(
- void *instanceData,
+ ClientData instanceData,
int action)
{
ThreadSpecificData *tsdPtr;
- TcpState *statePtr = (TcpState *)instanceData;
+ SocketInfo *infoPtr = (SocketInfo *) instanceData;
int notifyCmd;
if (action == TCL_CHANNEL_THREAD_INSERT) {
@@ -3319,23 +2599,25 @@ TcpThreadActionProc(
* sockets will not work.
*/
- TclInitSockets();
+ Tcl_MutexLock(&socketMutex);
+ InitSockets();
+ Tcl_MutexUnlock(&socketMutex);
tsdPtr = TCL_TSD_INIT(&dataKey);
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
- statePtr->nextPtr = tsdPtr->socketList;
- tsdPtr->socketList = statePtr;
-
- if (statePtr == tsdPtr->pendingTcpState) {
- tsdPtr->pendingTcpState = NULL;
+ infoPtr->nextPtr = tsdPtr->socketList;
+ tsdPtr->socketList = infoPtr;
+
+ if (infoPtr == tsdPtr->pendingSocketInfo) {
+ tsdPtr->pendingSocketInfo = NULL;
}
-
+
SetEvent(tsdPtr->socketListLock);
notifyCmd = SELECT;
} else {
- TcpState **nextPtrPtr;
+ SocketInfo **nextPtrPtr;
int removed = 0;
tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -3348,8 +2630,8 @@ TcpThreadActionProc(
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
- if ((*nextPtrPtr) == statePtr) {
- (*nextPtrPtr) = statePtr->nextPtr;
+ if ((*nextPtrPtr) == infoPtr) {
+ (*nextPtrPtr) = infoPtr->nextPtr;
removed = 1;
break;
}
@@ -3374,7 +2656,8 @@ TcpThreadActionProc(
* thread.
*/
- SendSelectMessage(tsdPtr, notifyCmd, statePtr);
+ SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
+ (WPARAM) notifyCmd, (LPARAM) infoPtr);
}
/*
@@ -3382,7 +2665,5 @@ TcpThreadActionProc(
* mode: c
* c-basic-offset: 4
* fill-column: 78
- * tab-width: 8
- * indent-tabs-mode: nil
* End:
*/
diff --git a/win/tclWinTest.c b/win/tclWinTest.c
index ec12f67..e493fbf 100644
--- a/win/tclWinTest.c
+++ b/win/tclWinTest.c
@@ -3,27 +3,20 @@
*
* Contains commands for platform specific tests on Windows.
*
- * Copyright © 1996 Sun Microsystems, Inc.
+ * Copyright (c) 1996 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#ifndef USE_TCL_STUBS
-# define USE_TCL_STUBS
-#endif
#include "tclInt.h"
-#ifdef TCL_WITH_EXTERNAL_TOMMATH
-# include "tommath.h"
-#else
-# include "tclTomMath.h"
-#endif
/*
* For TestplatformChmod on Windows
*/
+#ifdef __WIN32__
#include <aclapi.h>
-#include <sddl.h>
+#endif
/*
* MinGW 3.4.2 does not define this.
@@ -36,14 +29,20 @@
* Forward declarations of functions defined later in this file:
*/
-static Tcl_ObjCmdProc TesteventloopCmd;
-static Tcl_ObjCmdProc TestvolumetypeCmd;
-static Tcl_ObjCmdProc TestwinclockCmd;
-static Tcl_ObjCmdProc TestwinsleepCmd;
-static Tcl_ObjCmdProc TestSizeCmd;
+int TclplatformtestInit(Tcl_Interp *interp);
+static int TesteventloopCmd(ClientData dummy, Tcl_Interp *interp,
+ int argc, const char **argv);
+static int TestvolumetypeCmd(ClientData dummy,
+ Tcl_Interp *interp, int objc,
+ Tcl_Obj *const objv[]);
+static int TestwinclockCmd(ClientData dummy, Tcl_Interp* interp,
+ int objc, Tcl_Obj *const objv[]);
+static int TestwinsleepCmd(ClientData dummy, Tcl_Interp* interp,
+ int objc, Tcl_Obj *const objv[]);
static Tcl_ObjCmdProc TestExceptionCmd;
static int TestplatformChmod(const char *nativePath, int pmode);
-static Tcl_ObjCmdProc TestchmodCmd;
+static int TestchmodCmd(ClientData dummy,
+ Tcl_Interp *interp, int argc, const char **argv);
/*
*----------------------------------------------------------------------
@@ -70,14 +69,13 @@ TclplatformtestInit(
* Add commands for platform specific tests for Windows here.
*/
- Tcl_CreateObjCommand(interp, "testchmod", TestchmodCmd, NULL, NULL);
- Tcl_CreateObjCommand(interp, "testeventloop", TesteventloopCmd, NULL, NULL);
+ Tcl_CreateCommand(interp, "testchmod", TestchmodCmd, NULL, NULL);
+ Tcl_CreateCommand(interp, "testeventloop", TesteventloopCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testvolumetype", TestvolumetypeCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testwinclock", TestwinclockCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testwinsleep", TestwinsleepCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testexcept", TestExceptionCmd, NULL, NULL);
- Tcl_CreateObjCommand(interp, "testsize", TestSizeCmd, NULL, NULL);
return TCL_OK;
}
@@ -101,22 +99,23 @@ TclplatformtestInit(
static int
TesteventloopCmd(
- TCL_UNUSED(void *),
+ ClientData clientData, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
+ int argc, /* Number of arguments. */
+ const char **argv) /* Argument strings. */
{
static int *framePtr = NULL;/* Pointer to integer on stack frame of
* innermost invocation of the "wait"
* subcommand. */
- if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "option ...");
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
+ " option ... \"", NULL);
return TCL_ERROR;
}
- if (strcmp(Tcl_GetString(objv[1]), "done") == 0) {
+ if (strcmp(argv[1], "done") == 0) {
*framePtr = 1;
- } else if (strcmp(Tcl_GetString(objv[1]), "wait") == 0) {
+ } else if (strcmp(argv[1], "wait") == 0) {
int *oldFramePtr, done;
int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
@@ -136,7 +135,7 @@ TesteventloopCmd(
while (!done) {
MSG msg;
- if (!GetMessageW(&msg, NULL, 0, 0)) {
+ if (!GetMessage(&msg, NULL, 0, 0)) {
/*
* The application is exiting, so repost the quit message and
* start unwinding.
@@ -146,13 +145,13 @@ TesteventloopCmd(
break;
}
TranslateMessage(&msg);
- DispatchMessageW(&msg);
+ DispatchMessage(&msg);
}
(void) Tcl_SetServiceMode(oldMode);
framePtr = oldFramePtr;
} else {
- Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[1]),
- "\": must be done or wait", (char *)NULL);
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": must be done or wait", NULL);
return TCL_ERROR;
}
return TCL_OK;
@@ -177,7 +176,7 @@ TesteventloopCmd(
static int
TestvolumetypeCmd(
- TCL_UNUSED(void *),
+ ClientData clientData, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
@@ -185,7 +184,7 @@ TestvolumetypeCmd(
#define VOL_BUF_SIZE 32
int found;
char volType[VOL_BUF_SIZE];
- const char *path;
+ char *path;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?name?");
@@ -206,11 +205,11 @@ TestvolumetypeCmd(
if (found == 0) {
Tcl_AppendResult(interp, "could not get volume type for \"",
- (path?path:""), "\"", (char *)NULL);
- Tcl_WinConvertError(GetLastError());
+ (path?path:""), "\"", NULL);
+ TclWinConvertError(GetLastError());
return TCL_ERROR;
}
- Tcl_AppendResult(interp, volType, (char *)NULL);
+ Tcl_SetResult(interp, volType, TCL_VOLATILE);
return TCL_OK;
#undef VOL_BUF_SIZE
}
@@ -243,7 +242,7 @@ TestvolumetypeCmd(
static int
TestwinclockCmd(
- TCL_UNUSED(void *),
+ ClientData dummy, /* Unused */
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Argument count */
Tcl_Obj *const objv[]) /* Argument vector */
@@ -276,11 +275,11 @@ TestwinclockCmd(
result = Tcl_NewObj();
Tcl_ListObjAppendElement(interp, result,
- Tcl_NewWideIntObj(t2.QuadPart / 10000000));
+ Tcl_NewIntObj((int) (t2.QuadPart / 10000000)));
Tcl_ListObjAppendElement(interp, result,
- Tcl_NewWideIntObj((t2.QuadPart / 10) % 1000000));
- Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(tclTime.sec));
- Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(tclTime.usec));
+ Tcl_NewIntObj((int) ((t2.QuadPart / 10) % 1000000)));
+ Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(tclTime.sec));
+ Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(tclTime.usec));
Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(p1.QuadPart));
Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(p2.QuadPart));
@@ -292,7 +291,7 @@ TestwinclockCmd(
static int
TestwinsleepCmd(
- TCL_UNUSED(void *),
+ ClientData clientData, /* Unused */
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const * objv) /* Parameter vector */
@@ -310,28 +309,6 @@ TestwinsleepCmd(
return TCL_OK;
}
-static int
-TestSizeCmd(
- TCL_UNUSED(void *),
- Tcl_Interp* interp, /* Tcl interpreter */
- int objc, /* Parameter count */
- Tcl_Obj *const * objv) /* Parameter vector */
-{
-
- if (objc != 2) {
- goto syntax;
- }
- if (strcmp(Tcl_GetString(objv[1]), "st_mtime") == 0) {
- Tcl_StatBuf *statPtr;
- Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sizeof(statPtr->st_mtime)));
- return TCL_OK;
- }
-
-syntax:
- Tcl_WrongNumArgs(interp, 1, objv, "st_mtime");
- return TCL_ERROR;
-}
-
/*
*----------------------------------------------------------------------
*
@@ -357,12 +334,12 @@ syntax:
static int
TestExceptionCmd(
- TCL_UNUSED(void *),
+ ClientData dummy, /* Unused */
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Argument count */
Tcl_Obj *const objv[]) /* Argument vector */
{
- static const char *const cmds[] = {
+ static const char *cmds[] = {
"access_violation", "datatype_misalignment", "array_bounds",
"float_denormal", "float_divbyzero", "float_inexact",
"float_invalidop", "float_overflow", "float_stack", "float_underflow",
@@ -410,225 +387,311 @@ TestExceptionCmd(
/* SMASH! */
RaiseException(exceptions[cmd], EXCEPTION_NONCONTINUABLE, 0, NULL);
+ /* NOTREACHED */
return TCL_OK;
}
-/*
- * This "chmod" works sufficiently for test script purposes. Do not expect
- * it to be exact emulation of Unix chmod (not sure if that's even possible)
- */
static int
TestplatformChmod(
const char *nativePath,
int pmode)
{
+ typedef DWORD (WINAPI *getSidLengthRequiredDef)(UCHAR);
+ typedef BOOL (WINAPI *initializeSidDef)(PSID, PSID_IDENTIFIER_AUTHORITY,
+ BYTE);
+ typedef PDWORD (WINAPI *getSidSubAuthorityDef)(PSID, DWORD);
+ typedef DWORD (WINAPI *setNamedSecurityInfoADef)(IN LPSTR,
+ IN SE_OBJECT_TYPE, IN SECURITY_INFORMATION, IN PSID, IN PSID,
+ IN PACL, IN PACL);
+ typedef BOOL (WINAPI *getAceDef)(PACL, DWORD, LPVOID *);
+ typedef BOOL (WINAPI *addAceDef)(PACL, DWORD, DWORD, LPVOID, DWORD);
+ typedef BOOL (WINAPI *equalSidDef)(PSID, PSID);
+ typedef BOOL (WINAPI *addAccessDeniedAceDef)(PACL, DWORD, DWORD, PSID);
+ typedef BOOL (WINAPI *initializeAclDef)(PACL, DWORD, DWORD);
+ typedef DWORD (WINAPI *getLengthSidDef)(PSID);
+ typedef BOOL (WINAPI *getAclInformationDef)(PACL, LPVOID, DWORD,
+ ACL_INFORMATION_CLASS);
+ typedef BOOL (WINAPI *getSecurityDescriptorDaclDef)(PSECURITY_DESCRIPTOR,
+ LPBOOL, PACL *, LPBOOL);
+ typedef BOOL (WINAPI *lookupAccountNameADef)(LPCSTR, LPCSTR, PSID,
+ PDWORD, LPSTR, LPDWORD, PSID_NAME_USE);
+ typedef BOOL (WINAPI *getFileSecurityADef)(LPCSTR, SECURITY_INFORMATION,
+ PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
+
+ static const SECURITY_INFORMATION infoBits = OWNER_SECURITY_INFORMATION
+ | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
+ static const DWORD readOnlyMask = FILE_DELETE_CHILD | FILE_ADD_FILE
+ | FILE_ADD_SUBDIRECTORY | FILE_WRITE_EA | FILE_APPEND_DATA
+ | FILE_WRITE_DATA | DELETE;
+
/*
- * Note FILE_DELETE_CHILD missing from dirWriteMask because we do
- * not want overriding of child's delete setting when testing
+ * References to security functions (only available on NT and later).
*/
- static const DWORD dirWriteMask =
- FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA |
- FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | STANDARD_RIGHTS_WRITE | DELETE |
- SYNCHRONIZE;
- static const DWORD dirReadMask =
- FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_LIST_DIRECTORY |
- STANDARD_RIGHTS_READ | SYNCHRONIZE;
- /* Note - default user privileges allow ignoring TRAVERSE setting */
- static const DWORD dirExecuteMask =
- FILE_TRAVERSE | STANDARD_RIGHTS_READ | SYNCHRONIZE;
-
- static const DWORD fileWriteMask =
- FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_WRITE_DATA |
- FILE_APPEND_DATA | STANDARD_RIGHTS_WRITE | DELETE | SYNCHRONIZE;
- static const DWORD fileReadMask =
- FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA |
- STANDARD_RIGHTS_READ | SYNCHRONIZE;
- static const DWORD fileExecuteMask =
- FILE_EXECUTE | STANDARD_RIGHTS_READ | SYNCHRONIZE;
-
- DWORD attr, newAclSize;
- PACL newAcl = NULL;
+
+ static getSidLengthRequiredDef getSidLengthRequiredProc;
+ static initializeSidDef initializeSidProc;
+ static getSidSubAuthorityDef getSidSubAuthorityProc;
+ static setNamedSecurityInfoADef setNamedSecurityInfoProc;
+ static getAceDef getAceProc;
+ static addAceDef addAceProc;
+ static equalSidDef equalSidProc;
+ static addAccessDeniedAceDef addAccessDeniedAceProc;
+ static initializeAclDef initializeAclProc;
+ static getLengthSidDef getLengthSidProc;
+ static getAclInformationDef getAclInformationProc;
+ static getSecurityDescriptorDaclDef getSecurityDescriptorDaclProc;
+ static lookupAccountNameADef lookupAccountNameProc;
+ static getFileSecurityADef getFileSecurityProc;
+ static int initialized = 0;
+
+ const BOOL set_readOnly = !(pmode & 0222);
+ BOOL acl_readOnly_found = FALSE, curAclPresent, curAclDefaulted;
+ SID_IDENTIFIER_AUTHORITY userSidAuthority = {
+ SECURITY_WORLD_SID_AUTHORITY
+ };
+ BYTE *secDesc = 0;
+ DWORD secDescLen, attr, newAclSize;
+ ACL_SIZE_INFORMATION ACLSize;
+ PACL curAcl, newAcl = 0;
+ WORD j;
+ SID *userSid = 0;
+ TCHAR *userDomain = 0;
int res = 0;
- HANDLE hToken = NULL;
- int i;
- int nSids = 0;
- struct {
- PSID pSid;
- DWORD mask;
- DWORD sidLen;
- } aceEntry[3];
- DWORD dw;
- int isDir;
- TOKEN_USER *pTokenUser = NULL;
-
- res = -1; /* Assume failure */
-
- attr = GetFileAttributesA(nativePath);
- if (attr == 0xFFFFFFFF) {
- goto done; /* Not found */
+ /*
+ * One time initialization, dynamically load Windows NT features
+ */
+
+ if (!initialized) {
+ TCL_DECLARE_MUTEX(initializeMutex)
+ Tcl_MutexLock(&initializeMutex);
+ if (!initialized) {
+ HINSTANCE hInstance = LoadLibrary("Advapi32");
+
+ if (hInstance != NULL) {
+ setNamedSecurityInfoProc = (setNamedSecurityInfoADef)
+ GetProcAddress(hInstance, "SetNamedSecurityInfoA");
+ getFileSecurityProc = (getFileSecurityADef)
+ GetProcAddress(hInstance, "GetFileSecurityA");
+ getAceProc = (getAceDef)
+ GetProcAddress(hInstance, "GetAce");
+ addAceProc = (addAceDef)
+ GetProcAddress(hInstance, "AddAce");
+ equalSidProc = (equalSidDef)
+ GetProcAddress(hInstance, "EqualSid");
+ addAccessDeniedAceProc = (addAccessDeniedAceDef)
+ GetProcAddress(hInstance, "AddAccessDeniedAce");
+ initializeAclProc = (initializeAclDef)
+ GetProcAddress(hInstance, "InitializeAcl");
+ getLengthSidProc = (getLengthSidDef)
+ GetProcAddress(hInstance, "GetLengthSid");
+ getAclInformationProc = (getAclInformationDef)
+ GetProcAddress(hInstance, "GetAclInformation");
+ getSecurityDescriptorDaclProc = (getSecurityDescriptorDaclDef)
+ GetProcAddress(hInstance, "GetSecurityDescriptorDacl");
+ lookupAccountNameProc = (lookupAccountNameADef)
+ GetProcAddress(hInstance, "LookupAccountNameA");
+ getSidLengthRequiredProc = (getSidLengthRequiredDef)
+ GetProcAddress(hInstance, "GetSidLengthRequired");
+ initializeSidProc = (initializeSidDef)
+ GetProcAddress(hInstance, "InitializeSid");
+ getSidSubAuthorityProc = (getSidSubAuthorityDef)
+ GetProcAddress(hInstance, "GetSidSubAuthority");
+
+ if (setNamedSecurityInfoProc && getAceProc && addAceProc
+ && equalSidProc && addAccessDeniedAceProc
+ && initializeAclProc && getLengthSidProc
+ && getAclInformationProc
+ && getSecurityDescriptorDaclProc
+ && lookupAccountNameProc && getFileSecurityProc
+ && getSidLengthRequiredProc && initializeSidProc
+ && getSidSubAuthorityProc) {
+ initialized = 1;
+ }
+ }
+ if (!initialized) {
+ initialized = -1;
+ }
+ }
+ Tcl_MutexUnlock(&initializeMutex);
}
- isDir = (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ /*
+ * Process the chmod request.
+ */
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
- goto done;
- }
+ attr = GetFileAttributes(nativePath);
- /* Get process SID */
- if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dw)
- && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- goto done;
- }
- pTokenUser = (TOKEN_USER *)ckalloc(dw);
- if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dw, &dw)) {
+ /*
+ * nativePath not found
+ */
+
+ if (attr == 0xffffffff) {
+ res = -1;
goto done;
}
- aceEntry[nSids].sidLen = GetLengthSid(pTokenUser->User.Sid);
- aceEntry[nSids].pSid = ckalloc(aceEntry[nSids].sidLen);
- if (!CopySid(aceEntry[nSids].sidLen, aceEntry[nSids].pSid,
- pTokenUser->User.Sid)) {
- ckfree(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
+
+ /*
+ * If no ACL API is present or nativePath is not a directory, there is no
+ * special handling.
+ */
+
+ if (initialized < 0 || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
goto done;
}
+
/*
- * Always include DACL modify rights so we don't get locked out
+ * Set the result to error, if the ACL change is successful it will be
+ * reset to 0.
*/
- aceEntry[nSids].mask = READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE |
- FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES;
- if (pmode & 0700) {
- /* Owner permissions. Assumes current process is owner */
- if (pmode & 0400) {
- aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
- }
- if (pmode & 0200) {
- aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
- }
- if (pmode & 0100) {
- aceEntry[nSids].mask |= isDir ? dirExecuteMask : fileExecuteMask;
- }
- }
- ++nSids;
- if (pmode & 0070) {
- /* Group permissions. */
+ res = -1;
- TOKEN_PRIMARY_GROUP *pTokenGroup;
+ /*
+ * Read the security descriptor for the directory. Note the first call
+ * obtains the size of the security descriptor.
+ */
- /* Get primary group SID */
- if (!GetTokenInformation(
- hToken, TokenPrimaryGroup, NULL, 0, &dw) &&
- GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- goto done;
- }
- pTokenGroup = (TOKEN_PRIMARY_GROUP *)ckalloc(dw);
- if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dw, &dw)) {
- ckfree(pTokenGroup);
+ if (!getFileSecurityProc(nativePath, infoBits, NULL, 0, &secDescLen)) {
+ DWORD secDescLen2 = 0;
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
goto done;
}
- aceEntry[nSids].sidLen = GetLengthSid(pTokenGroup->PrimaryGroup);
- aceEntry[nSids].pSid = ckalloc(aceEntry[nSids].sidLen);
- if (!CopySid(aceEntry[nSids].sidLen, aceEntry[nSids].pSid, pTokenGroup->PrimaryGroup)) {
- ckfree(pTokenGroup);
- ckfree(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
+
+ secDesc = (BYTE *) ckalloc(secDescLen);
+ if (!getFileSecurityProc(nativePath, infoBits,
+ (PSECURITY_DESCRIPTOR) secDesc, secDescLen, &secDescLen2)
+ || (secDescLen < secDescLen2)) {
goto done;
}
- ckfree(pTokenGroup);
+ }
- /* Generate mask for group ACL */
+ /*
+ * Get the World SID.
+ */
- aceEntry[nSids].mask = 0;
- if (pmode & 0040) {
- aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
- }
- if (pmode & 0020) {
- aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
- }
- if (pmode & 0010) {
- aceEntry[nSids].mask |= isDir ? dirExecuteMask : fileExecuteMask;
- }
- ++nSids;
+ userSid = (SID *) ckalloc(getSidLengthRequiredProc((UCHAR) 1));
+ initializeSidProc(userSid, &userSidAuthority, (BYTE) 1);
+ *(getSidSubAuthorityProc(userSid, 0)) = SECURITY_WORLD_RID;
+
+ /*
+ * If curAclPresent == false then curAcl and curAclDefaulted not valid.
+ */
+
+ if (!getSecurityDescriptorDaclProc((PSECURITY_DESCRIPTOR) secDesc,
+ &curAclPresent, &curAcl, &curAclDefaulted)) {
+ goto done;
+ }
+ if (!curAclPresent || !curAcl) {
+ ACLSize.AclBytesInUse = 0;
+ ACLSize.AceCount = 0;
+ } else if (!getAclInformationProc(curAcl, &ACLSize, sizeof(ACLSize),
+ AclSizeInformation)) {
+ goto done;
}
- if (pmode & 0007) {
- /* World permissions */
- PSID pWorldSid;
- if (!ConvertStringSidToSidA("S-1-1-0", &pWorldSid)) {
- goto done;
- }
- aceEntry[nSids].sidLen = GetLengthSid(pWorldSid);
- aceEntry[nSids].pSid = ckalloc(aceEntry[nSids].sidLen);
- if (!CopySid(aceEntry[nSids].sidLen, aceEntry[nSids].pSid, pWorldSid)) {
- LocalFree(pWorldSid);
- ckfree(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
- goto done;
- }
- LocalFree(pWorldSid);
+ /*
+ * Allocate memory for the new ACL.
+ */
- /* Generate mask for world ACL */
+ newAclSize = ACLSize.AclBytesInUse + sizeof(ACCESS_DENIED_ACE)
+ + getLengthSidProc(userSid) - sizeof(DWORD);
+ newAcl = (ACL *) ckalloc(newAclSize);
- aceEntry[nSids].mask = 0;
- if (pmode & 0004) {
- aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
- }
- if (pmode & 0002) {
- aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
- }
- if (pmode & 0001) {
- aceEntry[nSids].mask |= isDir ? dirExecuteMask : fileExecuteMask;
- }
- ++nSids;
+ /*
+ * Initialize the new ACL.
+ */
+
+ if (!initializeAclProc(newAcl, newAclSize, ACL_REVISION)) {
+ goto done;
}
- /* Allocate memory and initialize the new ACL. */
+ /*
+ * Add denied to make readonly, this will be known as a "read-only tag".
+ */
- newAclSize = sizeof(ACL);
- /* Add in size required for each ACE entry in the ACL */
- for (i = 0; i < nSids; ++i) {
- newAclSize +=
- offsetof(ACCESS_ALLOWED_ACE, SidStart) + aceEntry[i].sidLen;
- }
- newAcl = (PACL)ckalloc(newAclSize);
- if (!InitializeAcl(newAcl, newAclSize, ACL_REVISION)) {
+ if (set_readOnly && !addAccessDeniedAceProc(newAcl, ACL_REVISION,
+ readOnlyMask, userSid)) {
goto done;
}
- for (i = 0; i < nSids; ++i) {
- if (!AddAccessAllowedAce(newAcl, ACL_REVISION, aceEntry[i].mask, aceEntry[i].pSid)) {
+ acl_readOnly_found = FALSE;
+ for (j = 0; j < ACLSize.AceCount; j++) {
+ LPVOID pACE2;
+ ACE_HEADER *phACE2;
+
+ if (!getAceProc(curAcl, j, &pACE2)) {
+ goto done;
+ }
+
+ phACE2 = (ACE_HEADER *) pACE2;
+
+ /*
+ * Do NOT propagate inherited ACEs.
+ */
+
+ if (phACE2->AceFlags & INHERITED_ACE) {
+ continue;
+ }
+
+ /*
+ * Skip the "read-only tag" restriction (either added above, or it is
+ * being removed).
+ */
+
+ if (phACE2->AceType == ACCESS_DENIED_ACE_TYPE) {
+ ACCESS_DENIED_ACE *pACEd = (ACCESS_DENIED_ACE *) phACE2;
+
+ if (pACEd->Mask == readOnlyMask
+ && equalSidProc(userSid, (PSID) &pACEd->SidStart)) {
+ acl_readOnly_found = TRUE;
+ continue;
+ }
+ }
+
+ /*
+ * Copy the current ACE from the old to the new ACL.
+ */
+
+ if (!addAceProc(newAcl, ACL_REVISION, MAXDWORD, (PACL *)pACE2,
+ ((PACE_HEADER) pACE2)->AceSize)) {
goto done;
}
}
/*
- * Apply the new ACL. Note PROTECTED_DACL_SECURITY_INFORMATION can be used
- * to remove inherited ACL (we need to overwrite the default ACL's in this case)
+ * Apply the new ACL.
*/
- if (SetNamedSecurityInfoA((LPSTR)nativePath, SE_FILE_OBJECT,
- DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
+ if (set_readOnly == acl_readOnly_found || setNamedSecurityInfoProc(
+ (LPSTR) nativePath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, newAcl, NULL) == ERROR_SUCCESS) {
res = 0;
}
done:
- if (pTokenUser) {
- ckfree(pTokenUser);
- }
- if (hToken) {
- CloseHandle(hToken);
+ if (secDesc) {
+ ckfree((char *) secDesc);
}
if (newAcl) {
- ckfree(newAcl);
+ ckfree((char *) newAcl);
+ }
+ if (userSid) {
+ ckfree((char *) userSid);
}
- for (i = 0; i < nSids; ++i) {
- ckfree(aceEntry[i].pSid);
+ if (userDomain) {
+ ckfree(userDomain);
}
if (res != 0) {
return res;
}
- /* Run normal chmod command */
+ /*
+ * Run normal chmod command.
+ */
+
return chmod(nativePath, pmode);
}
@@ -653,33 +716,37 @@ TestplatformChmod(
static int
TestchmodCmd(
- TCL_UNUSED(void *),
+ ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Parameter count */
- Tcl_Obj *const * objv) /* Parameter vector */
+ int argc, /* Number of arguments. */
+ const char **argv) /* Argument strings. */
{
int i, mode;
+ char *rest;
- if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "mode file ?file ...?");
+ if (argc < 2) {
+ usage:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " mode file ?file ...?", NULL);
return TCL_ERROR;
}
- if (Tcl_GetIntFromObj(interp, objv[1], &mode) != TCL_OK) {
- return TCL_ERROR;
+ mode = (int) strtol(argv[1], &rest, 8);
+ if ((rest == argv[1]) || (*rest != '\0')) {
+ goto usage;
}
- for (i = 2; i < objc; i++) {
+ for (i = 2; i < argc; i++) {
Tcl_DString buffer;
const char *translated;
- translated = Tcl_TranslateFileName(interp, Tcl_GetString(objv[i]), &buffer);
+ translated = Tcl_TranslateFileName(interp, argv[i], &buffer);
if (translated == NULL) {
return TCL_ERROR;
}
if (TestplatformChmod(translated, mode) != 0) {
Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp),
- (char *)NULL);
+ NULL);
return TCL_ERROR;
}
Tcl_DStringFree(&buffer);
diff --git a/win/tclWinThrd.c b/win/tclWinThrd.c
index e8d4d4d..2413a78 100644
--- a/win/tclWinThrd.c
+++ b/win/tclWinThrd.c
@@ -3,9 +3,8 @@
*
* This file implements the Windows-specific thread operations.
*
- * Copyright © 1998 Sun Microsystems, Inc.
- * Copyright © 1999 Scriptics Corporation
- * Copyright © 2008 George Peter Staplin
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * Copyright (c) 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.
@@ -13,6 +12,8 @@
#include "tclWinInt.h"
+#include <float.h>
+
/* Workaround for mingw versions which don't provide this in float.h */
#ifndef _MCW_EM
# define _MCW_EM 0x0008001F /* Error masks */
@@ -22,15 +23,18 @@ _CRTIMP unsigned int __cdecl _controlfp (unsigned int unNew, unsigned int unMask
#endif
/*
- * This is the global lock used to serialize access to other serialization
+ * This is the master lock used to serialize access to other serialization
* data structures.
*/
-static CRITICAL_SECTION globalLock;
-static int initialized = 0;
+static CRITICAL_SECTION masterLock;
+static int init = 0;
+#define MASTER_LOCK TclpMasterLock()
+#define MASTER_UNLOCK TclpMasterUnlock()
+
/*
- * This is the global lock used to serialize initialization and finalization
+ * This is the master lock used to serialize initialization and finalization
* of Tcl as a whole.
*/
@@ -38,10 +42,10 @@ static CRITICAL_SECTION initLock;
/*
* allocLock is used by Tcl's version of malloc for synchronization. For
- * obvious reasons, cannot use any dynamically allocated storage.
+ * obvious reasons, cannot use any dyamically allocated storage.
*/
-#if TCL_THREADS
+#ifdef TCL_THREADS
static struct Tcl_Mutex_ {
CRITICAL_SECTION crit;
@@ -76,7 +80,7 @@ static CRITICAL_SECTION joinLock;
* The per-thread event and queue pointers.
*/
-#if TCL_THREADS
+#ifdef TCL_THREADS
typedef struct ThreadSpecificData {
HANDLE condEvent; /* Per-thread condition event */
@@ -105,7 +109,7 @@ static Tcl_ThreadDataKey dataKey;
* the queue.
*/
-typedef struct {
+typedef struct WinCondition {
CRITICAL_SECTION condLock; /* Lock to serialize queuing on the
* condition. */
struct ThreadSpecificData *firstPtr; /* Queue pointers */
@@ -117,9 +121,10 @@ typedef struct {
*/
#ifdef USE_THREAD_ALLOC
+static int once;
static DWORD tlsKey;
-typedef struct {
+typedef struct allocMutex {
Tcl_Mutex tlock;
CRITICAL_SECTION wlock;
} allocMutex;
@@ -130,7 +135,7 @@ typedef struct {
* to TclWinThreadStart.
*/
-typedef struct {
+typedef struct WinThread {
LPTHREAD_START_ROUTINE lpStartAddress; /* Original startup routine */
LPVOID lpParameter; /* Original startup data */
unsigned int fpControl; /* Floating point control word from the
@@ -162,6 +167,7 @@ TclWinThreadStart(
* from TclpThreadCreate */
{
WinThread *winThreadPtr = (WinThread *) lpParameter;
+ unsigned int fpmask;
LPTHREAD_START_ROUTINE lpOrigStartAddress;
LPVOID lpOrigParameter;
@@ -169,16 +175,18 @@ TclWinThreadStart(
return TCL_ERROR;
}
- _controlfp(winThreadPtr->fpControl, _MCW_EM | _MCW_RC | 0x03000000 /* _MCW_DN */
-#if !defined(_WIN64)
- | _MCW_PC
+ fpmask = _MCW_EM | _MCW_RC | _MCW_PC;
+
+#if defined(_MSC_VER) && _MSC_VER >= 1200
+ fpmask |= _MCW_DN;
#endif
- );
+
+ _controlfp(winThreadPtr->fpControl, fpmask);
lpOrigStartAddress = winThreadPtr->lpStartAddress;
lpOrigParameter = winThreadPtr->lpParameter;
- ckfree(winThreadPtr);
+ ckfree((char *)winThreadPtr);
return lpOrigStartAddress(lpOrigParameter);
}
@@ -202,13 +210,13 @@ TclWinThreadStart(
int
TclpThreadCreate(
Tcl_ThreadId *idPtr, /* Return, the ID of the thread. */
- Tcl_ThreadCreateProc *proc, /* Main() function of the thread. */
- void *clientData, /* The one argument to Main(). */
- TCL_HASH_TYPE stackSize, /* Size of stack for the new thread. */
+ Tcl_ThreadCreateProc proc, /* Main() function of the thread. */
+ ClientData clientData, /* The one argument to Main(). */
+ int stackSize, /* Size of stack for the new thread. */
int flags) /* Flags controlling behaviour of the new
* thread. */
{
- WinThread *winThreadPtr; /* Per-thread startup info */
+ WinThread *winThreadPtr; /* Per-thread startup info */
HANDLE tHandle;
winThreadPtr = (WinThread *)ckalloc(sizeof(WinThread));
@@ -219,14 +227,15 @@ TclpThreadCreate(
EnterCriticalSection(&joinLock);
*idPtr = 0; /* must initialize as Tcl_Thread is a pointer and
- * on WIN64 sizeof void* != sizeof unsigned */
+ * on WIN64 sizeof void* != sizeof unsigned
+ */
-#if defined(_MSC_VER) || defined(__MSVCRT__)
- tHandle = (HANDLE) _beginthreadex(NULL, (unsigned)stackSize,
+#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
+ tHandle = (HANDLE) _beginthreadex(NULL, (unsigned) stackSize,
(Tcl_ThreadCreateProc*) TclWinThreadStart, winThreadPtr,
0, (unsigned *)idPtr);
#else
- tHandle = CreateThread(NULL, (DWORD)stackSize,
+ tHandle = CreateThread(NULL, (DWORD) stackSize,
TclWinThreadStart, winThreadPtr, 0, (LPDWORD)idPtr);
#endif
@@ -240,7 +249,7 @@ TclpThreadCreate(
/*
* The only purpose of this is to decrement the reference count so the
- * OS resources will be reacquired when the thread closes.
+ * OS resources will be reaquired when the thread closes.
*/
CloseHandle(tHandle);
@@ -299,7 +308,7 @@ TclpThreadExit(
TclSignalExitThread(Tcl_GetCurrentThread(), status);
LeaveCriticalSection(&joinLock);
-#if defined(_MSC_VER) || defined(__MSVCRT__)
+#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
_endthreadex((unsigned) status);
#else
ExitThread((DWORD) status);
@@ -325,7 +334,7 @@ TclpThreadExit(
Tcl_ThreadId
Tcl_GetCurrentThread(void)
{
- return (Tcl_ThreadId)INT2PTR(GetCurrentThreadId());
+ return (Tcl_ThreadId) INT2PTR(GetCurrentThreadId());
}
/*
@@ -350,7 +359,7 @@ Tcl_GetCurrentThread(void)
void
TclpInitLock(void)
{
- if (!initialized) {
+ if (!init) {
/*
* There is a fundamental race here that is solved by creating the
* first Tcl interpreter in a single threaded environment. Once the
@@ -358,10 +367,10 @@ TclpInitLock(void)
* that create interpreters in parallel.
*/
- initialized = 1;
+ init = 1;
InitializeCriticalSection(&joinLock);
InitializeCriticalSection(&initLock);
- InitializeCriticalSection(&globalLock);
+ InitializeCriticalSection(&masterLock);
}
EnterCriticalSection(&initLock);
}
@@ -392,27 +401,27 @@ TclpInitUnlock(void)
/*
*----------------------------------------------------------------------
*
- * TclpGlobalLock
+ * TclpMasterLock
*
* This procedure is used to grab a lock that serializes creation of
* mutexes, condition variables, and thread local storage keys.
*
* This lock must be different than the initLock because the initLock is
- * held during creation of synchronization objects.
+ * held during creation of syncronization objects.
*
* Results:
* None.
*
* Side effects:
- * Acquire the global mutex.
+ * Acquire the master mutex.
*
*----------------------------------------------------------------------
*/
void
-TclpGlobalLock(void)
+TclpMasterLock(void)
{
- if (!initialized) {
+ if (!init) {
/*
* There is a fundamental race here that is solved by creating the
* first Tcl interpreter in a single threaded environment. Once the
@@ -420,18 +429,18 @@ TclpGlobalLock(void)
* that create interpreters in parallel.
*/
- initialized = 1;
+ init = 1;
InitializeCriticalSection(&joinLock);
InitializeCriticalSection(&initLock);
- InitializeCriticalSection(&globalLock);
+ InitializeCriticalSection(&masterLock);
}
- EnterCriticalSection(&globalLock);
+ EnterCriticalSection(&masterLock);
}
/*
*----------------------------------------------------------------------
*
- * TclpGlobalUnlock
+ * TclpMasterUnlock
*
* This procedure is used to release a lock that serializes creation and
* deletion of synchronization objects.
@@ -440,15 +449,15 @@ TclpGlobalLock(void)
* None.
*
* Side effects:
- * Release the global mutex.
+ * Release the master mutex.
*
*----------------------------------------------------------------------
*/
void
-TclpGlobalUnlock(void)
+TclpMasterUnlock(void)
{
- LeaveCriticalSection(&globalLock);
+ LeaveCriticalSection(&masterLock);
}
/*
@@ -457,7 +466,7 @@ TclpGlobalUnlock(void)
* Tcl_GetAllocMutex
*
* This procedure returns a pointer to a statically initialized mutex for
- * use by the memory allocator. The allocator must use this lock, because
+ * use by the memory allocator. The alloctor must use this lock, because
* all other locks are allocated...
*
* Results:
@@ -473,7 +482,7 @@ TclpGlobalUnlock(void)
Tcl_Mutex *
Tcl_GetAllocMutex(void)
{
-#if TCL_THREADS
+#ifdef TCL_THREADS
if (!allocOnce) {
InitializeCriticalSection(&allocLock.crit);
allocOnce = 1;
@@ -487,7 +496,7 @@ Tcl_GetAllocMutex(void)
/*
*----------------------------------------------------------------------
*
- * TclFinalizeLock
+ * TclpFinalizeLock
*
* This procedure is used to destroy all private resources used in this
* file.
@@ -505,17 +514,17 @@ Tcl_GetAllocMutex(void)
void
TclFinalizeLock(void)
{
- TclpGlobalLock();
+ MASTER_LOCK;
DeleteCriticalSection(&joinLock);
/*
* Destroy the critical section that we are holding!
*/
- DeleteCriticalSection(&globalLock);
- initialized = 0;
+ DeleteCriticalSection(&masterLock);
+ init = 0;
-#if TCL_THREADS
+#ifdef TCL_THREADS
if (allocOnce) {
DeleteCriticalSection(&allocLock.crit);
allocOnce = 0;
@@ -531,10 +540,10 @@ TclFinalizeLock(void)
DeleteCriticalSection(&initLock);
}
-#if TCL_THREADS
+#ifdef TCL_THREADS
/* locally used prototype */
-static void FinalizeConditionEvent(void *data);
+static void FinalizeConditionEvent(ClientData data);
/*
*----------------------------------------------------------------------
@@ -548,7 +557,7 @@ static void FinalizeConditionEvent(void *data);
* None.
*
* Side effects:
- * May block the current thread. The mutex is acquired when this returns.
+ * May block the current thread. The mutex is aquired when this returns.
*
*----------------------------------------------------------------------
*/
@@ -560,19 +569,19 @@ Tcl_MutexLock(
CRITICAL_SECTION *csPtr;
if (*mutexPtr == NULL) {
- TclpGlobalLock();
+ MASTER_LOCK;
/*
- * Double inside global lock check to avoid a race.
+ * Double inside master lock check to avoid a race.
*/
if (*mutexPtr == NULL) {
- csPtr = (CRITICAL_SECTION *)ckalloc(sizeof(CRITICAL_SECTION));
+ csPtr = (CRITICAL_SECTION *) ckalloc(sizeof(CRITICAL_SECTION));
InitializeCriticalSection(csPtr);
*mutexPtr = (Tcl_Mutex)csPtr;
TclRememberMutex(mutexPtr);
}
- TclpGlobalUnlock();
+ MASTER_UNLOCK;
}
csPtr = *((CRITICAL_SECTION **)mutexPtr);
EnterCriticalSection(csPtr);
@@ -628,7 +637,7 @@ TclpFinalizeMutex(
if (csPtr != NULL) {
DeleteCriticalSection(csPtr);
- ckfree(csPtr);
+ ckfree((char *) csPtr);
*mutexPtr = NULL;
}
}
@@ -648,7 +657,7 @@ TclpFinalizeMutex(
* None.
*
* Side effects:
- * May block the current thread. The mutex is acquired when this returns.
+ * May block the current thread. The mutex is aquired when this returns.
* Will allocate memory for a HANDLE and initialize this the first time
* this Tcl_Condition is used.
*
@@ -659,7 +668,7 @@ void
Tcl_ConditionWait(
Tcl_Condition *condPtr, /* Really (WinCondition **) */
Tcl_Mutex *mutexPtr, /* Really (CRITICAL_SECTION **) */
- const Tcl_Time *timePtr) /* Timeout on waiting period */
+ Tcl_Time *timePtr) /* Timeout on waiting period */
{
WinCondition *winCondPtr; /* Per-condition queue head */
CRITICAL_SECTION *csPtr; /* Caller's Mutex, after casting */
@@ -674,57 +683,58 @@ Tcl_ConditionWait(
*/
if (tsdPtr->flags == WIN_THREAD_UNINIT) {
- TclpGlobalLock();
+ MASTER_LOCK;
/*
* Create the per-thread event and queue pointers.
*/
if (tsdPtr->flags == WIN_THREAD_UNINIT) {
- tsdPtr->condEvent = CreateEventW(NULL, TRUE /* manual reset */,
+ tsdPtr->condEvent = CreateEvent(NULL, TRUE /* manual reset */,
FALSE /* non signaled */, NULL);
tsdPtr->nextPtr = NULL;
tsdPtr->prevPtr = NULL;
tsdPtr->flags = WIN_THREAD_RUNNING;
doExit = 1;
}
- TclpGlobalUnlock();
+ MASTER_UNLOCK;
if (doExit) {
/*
* Create a per-thread exit handler to clean up the condEvent. We
- * must be careful to do this outside the Global Lock because
+ * must be careful to do this outside the Master Lock because
* Tcl_CreateThreadExitHandler uses its own ThreadSpecificData,
- * and initializing that may drop back into the Global Lock.
+ * and initializing that may drop back into the Master Lock.
*/
- Tcl_CreateThreadExitHandler(FinalizeConditionEvent, tsdPtr);
+ Tcl_CreateThreadExitHandler(FinalizeConditionEvent,
+ (ClientData) tsdPtr);
}
}
if (*condPtr == NULL) {
- TclpGlobalLock();
+ MASTER_LOCK;
/*
* Initialize the per-condition queue pointers and Mutex.
*/
if (*condPtr == NULL) {
- winCondPtr = (WinCondition *)ckalloc(sizeof(WinCondition));
+ winCondPtr = (WinCondition *) ckalloc(sizeof(WinCondition));
InitializeCriticalSection(&winCondPtr->condLock);
winCondPtr->firstPtr = NULL;
winCondPtr->lastPtr = NULL;
*condPtr = (Tcl_Condition) winCondPtr;
TclRememberCondition(condPtr);
}
- TclpGlobalUnlock();
+ MASTER_UNLOCK;
}
csPtr = *((CRITICAL_SECTION **)mutexPtr);
winCondPtr = *((WinCondition **)condPtr);
if (timePtr == NULL) {
wtime = INFINITE;
} else {
- wtime = (DWORD)timePtr->sec * 1000 + (DWORD)timePtr->usec / 1000;
+ wtime = timePtr->sec * 1000 + timePtr->usec / 1000;
}
/*
@@ -759,8 +769,7 @@ Tcl_ConditionWait(
while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) {
ResetEvent(tsdPtr->condEvent);
LeaveCriticalSection(&winCondPtr->condLock);
- if (WaitForSingleObjectEx(tsdPtr->condEvent, wtime,
- TRUE) == WAIT_TIMEOUT) {
+ if (WaitForSingleObject(tsdPtr->condEvent, wtime) == WAIT_TIMEOUT) {
timeout = 1;
}
EnterCriticalSection(&winCondPtr->condLock);
@@ -776,9 +785,9 @@ Tcl_ConditionWait(
timeout = 0;
} else {
/*
- * When dequeueing, we can leave the tsdPtr->nextPtr and
+ * When dequeuing, we can leave the tsdPtr->nextPtr and
* tsdPtr->prevPtr with dangling pointers because they are
- * reinitialized w/out reading them when the thread is enqueued
+ * reinitialilzed w/out reading them when the thread is enqueued
* later.
*/
@@ -879,7 +888,7 @@ Tcl_ConditionNotify(
static void
FinalizeConditionEvent(
- void *data)
+ ClientData data)
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) data;
@@ -895,7 +904,7 @@ FinalizeConditionEvent(
* This procedure is invoked to clean up a condition variable. This is
* only safe to call at the end of time.
*
- * This assumes the Global Lock is held.
+ * This assumes the Master Lock is held.
*
* Results:
* None.
@@ -921,7 +930,7 @@ TclpFinalizeCondition(
if (winCondPtr != NULL) {
DeleteCriticalSection(&winCondPtr->condLock);
- ckfree(winCondPtr);
+ ckfree((char *) winCondPtr);
*condPtr = NULL;
}
}
@@ -937,9 +946,9 @@ TclpFinalizeCondition(
Tcl_Mutex *
TclpNewAllocMutex(void)
{
- allocMutex *lockPtr;
+ struct allocMutex *lockPtr;
- lockPtr = (allocMutex *)malloc(sizeof(allocMutex));
+ lockPtr = malloc(sizeof(struct allocMutex));
if (lockPtr == NULL) {
Tcl_Panic("could not allocate lock");
}
@@ -961,24 +970,24 @@ TclpFreeAllocMutex(
free(lockPtr);
}
-void
-TclpInitAllocCache(void)
+void *
+TclpGetAllocCache(void)
{
- /*
- * We need to make sure that TclpFreeAllocCache is called on each
- * thread that calls this, but only on threads that call this.
- */
+ VOID *result;
+
+ if (!once) {
+ /*
+ * We need to make sure that TclpFreeAllocCache is called on each
+ * thread that calls this, but only on threads that call this.
+ */
- tlsKey = TlsAlloc();
- if (tlsKey == TLS_OUT_OF_INDEXES) {
- Tcl_Panic("could not allocate thread local storage");
+ tlsKey = TlsAlloc();
+ once = 1;
+ if (tlsKey == TLS_OUT_OF_INDEXES) {
+ Tcl_Panic("could not allocate thread local storage");
+ }
}
-}
-void *
-TclpGetAllocCache(void)
-{
- void *result;
result = TlsGetValue(tlsKey);
if ((result == NULL) && (GetLastError() != NO_ERROR)) {
Tcl_Panic("TlsGetValue failed from TclpGetAllocCache");
@@ -1005,10 +1014,8 @@ TclpFreeAllocCache(
if (ptr != NULL) {
/*
- * Called by TclFinalizeThreadAlloc() and
- * TclFinalizeThreadAllocThread() during Tcl_Finalize() or
- * Tcl_FinalizeThread(). This function destroys the tsd key which
- * stores allocator caches in thread local storage.
+ * Called by us in TclpFinalizeThreadData when a thread exits and
+ * destroys the tsd key which stores allocator caches.
*/
TclFreeAllocCache(ptr);
@@ -1016,7 +1023,7 @@ TclpFreeAllocCache(
if (!success) {
Tcl_Panic("TlsSetValue failed from TclpFreeAllocCache");
}
- } else {
+ } else if (once) {
/*
* Called by us in TclFinalizeThreadAlloc() during the library
* finalization initiated from Tcl_Finalize()
@@ -1026,64 +1033,11 @@ TclpFreeAllocCache(
if (!success) {
Tcl_Panic("TlsFree failed from TclpFreeAllocCache");
}
- }
-}
-#endif /* USE_THREAD_ALLOC */
-
-
-void *
-TclpThreadCreateKey(void)
-{
- DWORD *key;
-
- key = (DWORD *)TclpSysAlloc(sizeof *key, 0);
- if (key == NULL) {
- Tcl_Panic("unable to allocate thread key!");
- }
-
- *key = TlsAlloc();
-
- if (*key == TLS_OUT_OF_INDEXES) {
- Tcl_Panic("unable to allocate thread-local storage");
+ once = 0; /* reset for next time. */
}
- return key;
}
-
-void
-TclpThreadDeleteKey(
- void *keyPtr)
-{
- DWORD *key = (DWORD *)keyPtr;
-
- if (!TlsFree(*key)) {
- Tcl_Panic("unable to delete key");
- }
-
- TclpSysFree(keyPtr);
-}
-
-void
-TclpThreadSetGlobalTSD(
- void *tsdKeyPtr,
- void *ptr)
-{
- DWORD *key = (DWORD *)tsdKeyPtr;
-
- if (!TlsSetValue(*key, ptr)) {
- Tcl_Panic("unable to set global TSD value");
- }
-}
-
-void *
-TclpThreadGetGlobalTSD(
- void *tsdKeyPtr)
-{
- DWORD *key = (DWORD *)tsdKeyPtr;
-
- return TlsGetValue(*key);
-}
-
+#endif /* USE_THREAD_ALLOC */
#endif /* TCL_THREADS */
/*
diff --git a/win/tclWinThrd.h b/win/tclWinThrd.h
new file mode 100644
index 0000000..41bc7aa
--- /dev/null
+++ b/win/tclWinThrd.h
@@ -0,0 +1,19 @@
+/*
+ * tclWinThrd.h --
+ *
+ * This header file defines things for thread support.
+ *
+ * Copyright (c) 1998 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#ifndef _TCLWINTHRD
+#define _TCLWINTHRD
+
+#ifdef TCL_THREADS
+
+#endif /* TCL_THREADS */
+
+#endif /* _TCLWINTHRD */
diff --git a/win/tclWinTime.c b/win/tclWinTime.c
index 438a8ec..0163723 100644
--- a/win/tclWinTime.c
+++ b/win/tclWinTime.c
@@ -4,7 +4,7 @@
* Contains Windows specific versions of Tcl functions that obtain time
* values from the operating system.
*
- * Copyright © 1995-1998 Sun Microsystems, Inc.
+ * Copyright 1995-1998 by Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -27,7 +27,6 @@
* month, where index 1 is January.
*/
-#ifndef TCL_NO_DEPRECATED
static const int normalDays[] = {
-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
};
@@ -36,25 +35,22 @@ static const int leapDays[] = {
-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
};
-typedef struct {
+typedef struct ThreadSpecificData {
char tzName[64]; /* Time zone name */
struct tm tm; /* time information */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
-#endif /* TCL_NO_DEPRECATED */
/*
* Data for managing high-resolution timers.
*/
-typedef struct {
+typedef struct TimeInfo {
CRITICAL_SECTION cs; /* Mutex guarding this structure. */
int initialized; /* Flag == 1 if this structure is
* initialized. */
int perfCounterAvailable; /* Flag == 1 if the hardware has a performance
* counter. */
- DWORD calibrationInterv; /* Calibration interval in seconds (start 1
- * sec) */
HANDLE calibrationThread; /* Handle to the thread that keeps the virtual
* clock calibrated. */
HANDLE readyEvent; /* System event used to trigger the requesting
@@ -65,6 +61,7 @@ typedef struct {
LARGE_INTEGER nominalFreq; /* Nominal frequency of the system performance
* counter, that is, the value returned from
* QueryPerformanceFrequency. */
+
/*
* The following values are used for calculating virtual time. Virtual
* time is always equal to:
@@ -77,40 +74,35 @@ typedef struct {
ULARGE_INTEGER fileTimeLastCall;
LARGE_INTEGER perfCounterLastCall;
LARGE_INTEGER curCounterFreq;
- LARGE_INTEGER posixEpoch; /* Posix epoch expressed as 100-ns ticks since
- * the windows epoch. */
/*
* Data used in developing the estimate of performance counter frequency
*/
- unsigned long long fileTimeSample[SAMPLES];
+ Tcl_WideUInt fileTimeSample[SAMPLES];
/* Last 64 samples of system time. */
- long long perfCounterSample[SAMPLES];
+ Tcl_WideInt perfCounterSample[SAMPLES];
/* Last 64 samples of performance counter. */
int sampleNo; /* Current sample number. */
} TimeInfo;
static TimeInfo timeInfo = {
- { NULL, 0, 0, NULL, NULL, 0 },
+ { NULL },
0,
0,
- 1,
(HANDLE) NULL,
(HANDLE) NULL,
(HANDLE) NULL,
-#if defined(HAVE_CAST_TO_UNION) && !defined(__cplusplus)
- (LARGE_INTEGER) (long long) 0,
+#ifdef HAVE_CAST_TO_UNION
+ (LARGE_INTEGER) (Tcl_WideInt) 0,
(ULARGE_INTEGER) (DWORDLONG) 0,
- (LARGE_INTEGER) (long long) 0,
- (LARGE_INTEGER) (long long) 0,
- (LARGE_INTEGER) (long long) 0,
+ (LARGE_INTEGER) (Tcl_WideInt) 0,
+ (LARGE_INTEGER) (Tcl_WideInt) 0,
#else
- {0, 0},
- {0, 0},
- {0, 0},
- {0, 0},
- {0, 0},
+ 0,
+ 0,
+ 0,
+ 0,
#endif
{ 0 },
{ 0 },
@@ -118,36 +110,21 @@ static TimeInfo timeInfo = {
};
/*
- * Scale to convert wide click values from the TclpGetWideClicks native
- * resolution to microsecond resolution and back.
- */
-static struct {
- int initialized; /* 1 if initialized, 0 otherwise */
- int perfCounter; /* 1 if performance counter usable for wide
- * clicks */
- double microsecsScale; /* Denominator scale between clock / microsecs */
-} wideClick = {0, 0, 0.0};
-
-
-/*
* Declarations for functions defined later in this file.
*/
-#ifndef TCL_NO_DEPRECATED
static struct tm * ComputeGMT(const time_t *tp);
-#endif /* TCL_NO_DEPRECATED */
-static void StopCalibration(void *clientData);
+static void StopCalibration(ClientData clientData);
static DWORD WINAPI CalibrationThread(LPVOID arg);
static void UpdateTimeEachSecond(void);
-static void ResetCounterSamples(unsigned long long fileTime,
- long long perfCounter, long long perfFreq);
-static long long AccumulateSample(long long perfCounter,
- unsigned long long fileTime);
+static void ResetCounterSamples(Tcl_WideUInt fileTime,
+ Tcl_WideInt perfCounter, Tcl_WideInt perfFreq);
+static Tcl_WideInt AccumulateSample(Tcl_WideInt perfCounter,
+ Tcl_WideUInt fileTime);
static void NativeScaleTime(Tcl_Time* timebuf,
- void *clientData);
-static long long NativeGetMicroseconds(void);
+ ClientData clientData);
static void NativeGetTime(Tcl_Time* timebuf,
- void *clientData);
+ ClientData clientData);
/*
* TIP #233 (Virtualized Time): Data for the time hooks, if any.
@@ -155,24 +132,7 @@ static void NativeGetTime(Tcl_Time* timebuf,
Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime;
Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime;
-void *tclTimeClientData = NULL;
-
-/*
- * Inlined version of Tcl_GetTime.
- */
-
-static inline void
-GetTime(
- Tcl_Time *timePtr)
-{
- tclGetTimeProcPtr(timePtr, tclTimeClientData);
-}
-
-static inline int
-IsTimeNative(void)
-{
- return tclGetTimeProcPtr == NativeGetTime;
-}
+ClientData tclTimeClientData = NULL;
/*
*----------------------------------------------------------------------
@@ -194,20 +154,10 @@ IsTimeNative(void)
unsigned long
TclpGetSeconds(void)
{
- long long usecSincePosixEpoch;
+ Tcl_Time t;
- /*
- * Try to use high resolution timer
- */
-
- if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
- return usecSincePosixEpoch / 1000000;
- } else {
- Tcl_Time t;
-
- GetTime(&t);
- return t.sec;
- }
+ (*tclGetTimeProcPtr) (&t, tclTimeClientData); /* Tcl_GetTime inlined. */
+ return t.sec;
}
/*
@@ -218,7 +168,7 @@ TclpGetSeconds(void)
* This procedure returns a value that represents the highest resolution
* clock available on the system. There are no guarantees on what the
* resolution will be. In Tcl we will call this value a "click". The
- * start time is also system dependent.
+ * start time is also system dependant.
*
* Results:
* Number of clicks from some start time.
@@ -232,121 +182,31 @@ TclpGetSeconds(void)
unsigned long
TclpGetClicks(void)
{
- long long usecSincePosixEpoch;
-
/*
- * Try to use high resolution timer.
+ * Use the Tcl_GetTime abstraction to get the time in microseconds, as
+ * nearly as we can, and return it.
*/
- if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
- return (unsigned long) usecSincePosixEpoch;
- } else {
- /*
- * Use the Tcl_GetTime abstraction to get the time in microseconds, as
- * nearly as we can, and return it.
- */
+ Tcl_Time now; /* Current Tcl time */
+ unsigned long retval; /* Value to return */
- Tcl_Time now; /* Current Tcl time */
+ (*tclGetTimeProcPtr) (&now, tclTimeClientData); /* Tcl_GetTime inlined */
- GetTime(&now);
- return ((unsigned long)(now.sec)*1000000UL) + (unsigned long)(now.usec);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpGetWideClicks --
- *
- * This procedure returns a WideInt value that represents the highest
- * resolution clock in microseconds available on the system.
- *
- * Results:
- * Number of microseconds (from some start time).
- *
- * Side effects:
- * This should be used for time-delta resp. for measurement purposes
- * only, because on some platforms can return microseconds from some
- * start time (not from the epoch).
- *
- *----------------------------------------------------------------------
- */
-
-long long
-TclpGetWideClicks(void)
-{
- LARGE_INTEGER curCounter;
-
- if (!wideClick.initialized) {
- LARGE_INTEGER perfCounterFreq;
-
- /*
- * The frequency of the performance counter is fixed at system boot and
- * is consistent across all processors. Therefore, the frequency need
- * only be queried upon application initialization.
- */
-
- if (QueryPerformanceFrequency(&perfCounterFreq)) {
- wideClick.perfCounter = 1;
- wideClick.microsecsScale = 1000000.0 / perfCounterFreq.QuadPart;
- } else {
- /* fallback using microseconds */
- wideClick.perfCounter = 0;
- wideClick.microsecsScale = 1;
- }
-
- wideClick.initialized = 1;
- }
- if (wideClick.perfCounter) {
- if (QueryPerformanceCounter(&curCounter)) {
- return (long long)curCounter.QuadPart;
- }
- /* fallback using microseconds */
- wideClick.perfCounter = 0;
- wideClick.microsecsScale = 1;
- return TclpGetMicroseconds();
- } else {
- return TclpGetMicroseconds();
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclpWideClickInMicrosec --
- *
- * This procedure return scale to convert wide click values from the
- * TclpGetWideClicks native resolution to microsecond resolution
- * and back.
- *
- * Results:
- * 1 click in microseconds as double.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
+ retval = (now.sec * 1000000) + now.usec;
+ return retval;
-double
-TclpWideClickInMicrosec(void)
-{
- if (!wideClick.initialized) {
- (void) TclpGetWideClicks(); /* initialize */
- }
- return wideClick.microsecsScale;
}
/*
*----------------------------------------------------------------------
*
- * TclpGetMicroseconds --
+ * TclpGetTimeZone --
*
- * This procedure returns a WideInt value that represents the highest
- * resolution clock in microseconds available on the system.
+ * Determines the current timezone. The method varies wildly between
+ * different Platform implementations, so its hidden in this function.
*
* Results:
- * Number of microseconds (from the epoch).
+ * Minutes west of GMT.
*
* Side effects:
* None.
@@ -354,28 +214,16 @@ TclpWideClickInMicrosec(void)
*----------------------------------------------------------------------
*/
-long long
-TclpGetMicroseconds(void)
+int
+TclpGetTimeZone(
+ unsigned long currentTime)
{
- long long usecSincePosixEpoch;
+ int timeZone;
- /*
- * Try to use high resolution timer.
- */
+ tzset();
+ timeZone = timezone / 60;
- if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
- return usecSincePosixEpoch;
- } else {
- /*
- * Use the Tcl_GetTime abstraction to get the time in microseconds, as
- * nearly as we can, and return it.
- */
-
- Tcl_Time now;
-
- GetTime(&now);
- return (((long long) now.sec) * 1000000) + now.usec;
- }
+ return timeZone;
}
/*
@@ -404,18 +252,7 @@ void
Tcl_GetTime(
Tcl_Time *timePtr) /* Location to store time information. */
{
- long long usecSincePosixEpoch;
-
- /*
- * Try to use high resolution timer.
- */
-
- if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
- timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
- timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
- } else {
- GetTime(timePtr);
- }
+ (*tclGetTimeProcPtr) (timePtr, tclTimeClientData);
}
/*
@@ -437,8 +274,8 @@ Tcl_GetTime(
static void
NativeScaleTime(
- TCL_UNUSED(Tcl_Time *),
- TCL_UNUSED(void *))
+ Tcl_Time *timePtr,
+ ClientData clientData)
{
/*
* Native scale is 1:1. Nothing is done.
@@ -448,104 +285,13 @@ NativeScaleTime(
/*
*----------------------------------------------------------------------
*
- * IsPerfCounterAvailable --
- *
- * Tests whether the performance counter is available, which is a gnarly
- * problem on 32-bit systems. Also retrieves the nominal frequency of the
- * performance counter.
- *
- * Results:
- * 1 if the counter is available, 0 if not.
- *
- * Side effects:
- * Updates fields of the timeInfo global. Make sure you hold the lock
- * before calling this.
- *
- *----------------------------------------------------------------------
- */
-
-static inline int
-IsPerfCounterAvailable(void)
-{
- timeInfo.perfCounterAvailable =
- QueryPerformanceFrequency(&timeInfo.nominalFreq);
-
- /*
- * Some hardware abstraction layers use the CPU clock in place of the
- * real-time clock as a performance counter reference. This results in:
- * - inconsistent results among the processors on multi-processor
- * systems.
- * - unpredictable changes in performance counter frequency on
- * "gearshift" processors such as Transmeta and SpeedStep.
- *
- * There seems to be no way to test whether the performance counter is
- * reliable, but a useful heuristic is that if its frequency is 1.193182
- * MHz or 3.579545 MHz, it's derived from a colorburst crystal and is
- * therefore the RTC rather than the TSC.
- *
- * A sloppier but serviceable heuristic is that the RTC crystal is
- * normally less than 15 MHz while the TSC crystal is virtually assured to
- * be greater than 100 MHz. Since Win98SE appears to fiddle with the
- * definition of the perf counter frequency (perhaps in an attempt to
- * calibrate the clock?), we use the latter rule rather than an exact
- * match.
- *
- * We also assume (perhaps questionably) that the vendors have gotten
- * their act together on Win64, so bypass all this rubbish on that
- * platform.
- */
-
-#if !defined(_WIN64)
- if (timeInfo.perfCounterAvailable &&
- /*
- * The following lines would do an exact match on crystal
- * frequency:
- *
- * timeInfo.nominalFreq.QuadPart != (long long) 1193182 &&
- * timeInfo.nominalFreq.QuadPart != (long long) 3579545 &&
- */
- timeInfo.nominalFreq.QuadPart > (long long) 15000000) {
- /*
- * As an exception, if every logical processor on the system is on the
- * same chip, we use the performance counter anyway, presuming that
- * everyone's TSC is locked to the same oscillator.
- */
-
- SYSTEM_INFO systemInfo;
- int regs[4];
-
- GetSystemInfo(&systemInfo);
- if (TclWinCPUID(0, regs) == TCL_OK
- && regs[1] == 0x756E6547 /* "Genu" */
- && regs[3] == 0x49656E69 /* "ineI" */
- && regs[2] == 0x6C65746E /* "ntel" */
- && TclWinCPUID(1, regs) == TCL_OK
- && ((regs[0]&0x00000F00) == 0x00000F00 /* Pentium 4 */
- || ((regs[0] & 0x00F00000) /* Extended family */
- && (regs[3] & 0x10000000))) /* Hyperthread */
- && (((regs[1]&0x00FF0000) >> 16)/* CPU count */
- == (int)systemInfo.dwNumberOfProcessors)) {
- timeInfo.perfCounterAvailable = TRUE;
- } else {
- timeInfo.perfCounterAvailable = FALSE;
- }
- }
-#endif /* above code is Win32 only */
-
- return timeInfo.perfCounterAvailable;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NativeGetMicroseconds --
+ * NativeGetTime --
*
- * Gets the current system time in microseconds since the beginning
- * of the epoch: 00:00 UCT, January 1, 1970.
+ * TIP #233: Gets the current system time in seconds and microseconds
+ * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
*
* Results:
- * Returns the wide integer with number of microseconds from the epoch, or
- * 0 if high resolution timer is not available.
+ * Returns the current time in timePtr.
*
* Side effects:
* On the first call, initializes a set of static variables to keep track
@@ -558,20 +304,15 @@ IsPerfCounterAvailable(void)
*----------------------------------------------------------------------
*/
-static inline long long
-NativeCalc100NsTicks(
- ULONGLONG fileTimeLastCall,
- LONGLONG perfCounterLastCall,
- LONGLONG curCounterFreq,
- LONGLONG curCounter)
+static void
+NativeGetTime(
+ Tcl_Time *timePtr,
+ ClientData clientData)
{
- return fileTimeLastCall +
- ((curCounter - perfCounterLastCall) * 10000000 / curCounterFreq);
-}
+ struct _timeb t;
+ int useFtime = 1; /* Flag == TRUE if we need to fall back on
+ * ftime rather than using the perf counter. */
-static long long
-NativeGetMicroseconds(void)
-{
/*
* Initialize static storage on the first trip through.
*
@@ -582,20 +323,84 @@ NativeGetMicroseconds(void)
if (!timeInfo.initialized) {
TclpInitLock();
if (!timeInfo.initialized) {
- timeInfo.posixEpoch.LowPart = 0xD53E8000;
- timeInfo.posixEpoch.HighPart = 0x019DB1DE;
+ timeInfo.perfCounterAvailable =
+ QueryPerformanceFrequency(&timeInfo.nominalFreq);
+
+ /*
+ * Some hardware abstraction layers use the CPU clock in place of
+ * the real-time clock as a performance counter reference. This
+ * results in:
+ * - inconsistent results among the processors on
+ * multi-processor systems.
+ * - unpredictable changes in performance counter frequency on
+ * "gearshift" processors such as Transmeta and SpeedStep.
+ *
+ * There seems to be no way to test whether the performance
+ * counter is reliable, but a useful heuristic is that if its
+ * frequency is 1.193182 MHz or 3.579545 MHz, it's derived from a
+ * colorburst crystal and is therefore the RTC rather than the
+ * TSC.
+ *
+ * A sloppier but serviceable heuristic is that the RTC crystal is
+ * normally less than 15 MHz while the TSC crystal is virtually
+ * assured to be greater than 100 MHz. Since Win98SE appears to
+ * fiddle with the definition of the perf counter frequency
+ * (perhaps in an attempt to calibrate the clock?), we use the
+ * latter rule rather than an exact match.
+ *
+ * We also assume (perhaps questionably) that the vendors have
+ * gotten their act together on Win64, so bypass all this rubbish
+ * on that platform.
+ */
+
+#if !defined(_WIN64)
+ if (timeInfo.perfCounterAvailable
+ /*
+ * The following lines would do an exact match on crystal
+ * frequency:
+ * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt)1193182
+ * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt)3579545
+ */
+ && timeInfo.nominalFreq.QuadPart > (Tcl_WideInt) 15000000){
+ /*
+ * As an exception, if every logical processor on the system
+ * is on the same chip, we use the performance counter anyway,
+ * presuming that everyone's TSC is locked to the same
+ * oscillator.
+ */
+
+ SYSTEM_INFO systemInfo;
+ unsigned int regs[4];
+
+ GetSystemInfo(&systemInfo);
+ if (TclWinCPUID(0, regs) == TCL_OK
+ && regs[1] == 0x756e6547 /* "Genu" */
+ && regs[3] == 0x49656e69 /* "ineI" */
+ && regs[2] == 0x6c65746e /* "ntel" */
+ && TclWinCPUID(1, regs) == TCL_OK
+ && ((regs[0]&0x00000F00) == 0x00000F00 /* Pentium 4 */
+ || ((regs[0] & 0x00F00000) /* Extended family */
+ && (regs[3] & 0x10000000))) /* Hyperthread */
+ && (((regs[1]&0x00FF0000) >> 16)/* CPU count */
+ == systemInfo.dwNumberOfProcessors)) {
+ timeInfo.perfCounterAvailable = TRUE;
+ } else {
+ timeInfo.perfCounterAvailable = FALSE;
+ }
+ }
+#endif /* above code is Win32 only */
/*
* If the performance counter is available, start a thread to
* calibrate it.
*/
- if (IsPerfCounterAvailable()) {
+ if (timeInfo.perfCounterAvailable) {
DWORD id;
InitializeCriticalSection(&timeInfo.cs);
- timeInfo.readyEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
- timeInfo.exitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+ timeInfo.readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ timeInfo.exitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
timeInfo.calibrationThread = CreateThread(NULL, 256,
CalibrationThread, (LPVOID) NULL, 0, &id);
SetThreadPriority(timeInfo.calibrationThread,
@@ -609,7 +414,7 @@ NativeGetMicroseconds(void)
WaitForSingleObject(timeInfo.readyEvent, INFINITE);
CloseHandle(timeInfo.readyEvent);
- Tcl_CreateExitHandler(StopCalibration, NULL);
+ Tcl_CreateExitHandler(StopCalibration, (ClientData) NULL);
}
timeInfo.initialized = TRUE;
}
@@ -622,39 +427,22 @@ NativeGetMicroseconds(void)
* time.
*/
- ULONGLONG fileTimeLastCall;
- LONGLONG perfCounterLastCall, curCounterFreq;
- /* Copy with current data of calibration
- * cycle. */
-
LARGE_INTEGER curCounter;
/* Current performance counter. */
+ Tcl_WideInt curFileTime;/* Current estimated time, expressed as 100-ns
+ * ticks since the Windows epoch. */
+ static LARGE_INTEGER posixEpoch;
+ /* Posix epoch expressed as 100-ns ticks since
+ * the windows epoch. */
+ Tcl_WideInt usecSincePosixEpoch;
+ /* Current microseconds since Posix epoch. */
- QueryPerformanceCounter(&curCounter);
-
- /*
- * Hold time section locked as short as possible
- */
+ posixEpoch.LowPart = 0xD53E8000;
+ posixEpoch.HighPart = 0x019DB1DE;
EnterCriticalSection(&timeInfo.cs);
- fileTimeLastCall = timeInfo.fileTimeLastCall.QuadPart;
- perfCounterLastCall = timeInfo.perfCounterLastCall.QuadPart;
- curCounterFreq = timeInfo.curCounterFreq.QuadPart;
-
- LeaveCriticalSection(&timeInfo.cs);
-
- /*
- * If calibration cycle occurred after we get curCounter
- */
-
- if (curCounter.QuadPart <= perfCounterLastCall) {
- /*
- * Calibrated file-time is saved from Posix in 100-ns ticks
- */
-
- return fileTimeLastCall / 10;
- }
+ QueryPerformanceCounter(&curCounter);
/*
* If it appears to be more than 1.1 seconds since the last trip
@@ -666,65 +454,29 @@ NativeGetMicroseconds(void)
* loop should recover.
*/
- if (curCounter.QuadPart - perfCounterLastCall <
- 11 * curCounterFreq * timeInfo.calibrationInterv / 10) {
- /*
- * Calibrated file-time is saved from Posix in 100-ns ticks.
- */
-
- return NativeCalc100NsTicks(fileTimeLastCall,
- perfCounterLastCall, curCounterFreq,
- curCounter.QuadPart) / 10;
+ if (curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart <
+ 11 * timeInfo.curCounterFreq.QuadPart / 10) {
+ curFileTime = timeInfo.fileTimeLastCall.QuadPart +
+ ((curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart)
+ * 10000000 / timeInfo.curCounterFreq.QuadPart);
+ timeInfo.fileTimeLastCall.QuadPart = curFileTime;
+ timeInfo.perfCounterLastCall.QuadPart = curCounter.QuadPart;
+ usecSincePosixEpoch = (curFileTime - posixEpoch.QuadPart) / 10;
+ timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
+ timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
+ useFtime = 0;
}
- }
- /*
- * High resolution timer is not available.
- */
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NativeGetTime --
- *
- * TIP #233: Gets the current system time in seconds and microseconds
- * since the beginning of the epoch: 00:00 UCT, January 1, 1970.
- *
- * Results:
- * Returns the current time in timePtr.
- *
- * Side effects:
- * See NativeGetMicroseconds for more information.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-NativeGetTime(
- Tcl_Time *timePtr,
- TCL_UNUSED(void *))
-{
- long long usecSincePosixEpoch;
-
- /*
- * Try to use high resolution timer.
- */
+ LeaveCriticalSection(&timeInfo.cs);
+ }
- usecSincePosixEpoch = NativeGetMicroseconds();
- if (usecSincePosixEpoch) {
- timePtr->sec = (long) (usecSincePosixEpoch / 1000000);
- timePtr->usec = (unsigned long) (usecSincePosixEpoch % 1000000);
- } else {
+ if (useFtime) {
/*
* High resolution timer is not available. Just use ftime.
*/
- struct _timeb t;
-
_ftime(&t);
- timePtr->sec = (long) t.time;
+ timePtr->sec = (long)t.time;
timePtr->usec = t.millitm * 1000;
}
}
@@ -747,11 +499,9 @@ NativeGetTime(
*----------------------------------------------------------------------
*/
-void TclWinResetTimerResolution(void);
-
static void
StopCalibration(
- TCL_UNUSED(void *))
+ ClientData unused) /* Client data is unused */
{
SetEvent(timeInfo.exitEvent);
@@ -768,6 +518,93 @@ StopCalibration(
/*
*----------------------------------------------------------------------
*
+ * TclpGetTZName --
+ *
+ * Gets the current timezone string.
+ *
+ * Results:
+ * Returns a pointer to a static string, or NULL on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+TclpGetTZName(
+ int dst)
+{
+ int len;
+ char *zone, *p;
+ TIME_ZONE_INFORMATION tz;
+ Tcl_Encoding encoding;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ char *name = tsdPtr->tzName;
+
+ /*
+ * tzset() under Borland doesn't seem to set up tzname[] at all.
+ * tzset() under MSVC has the following weird observed behavior:
+ * First time we call "clock format [clock seconds] -format %Z -gmt 1"
+ * we get "GMT", but on all subsequent calls we get the current time
+ * ezone string, even though env(TZ) is GMT and the variable _timezone
+ * is 0.
+ */
+
+ name[0] = '\0';
+
+ zone = getenv("TZ");
+ if (zone != NULL) {
+ /*
+ * TZ is of form "NST-4:30NDT", where "NST" would be the name of the
+ * standard time zone for this area, "-4:30" is the offset from GMT in
+ * hours, and "NDT is the name of the daylight savings time zone in
+ * this area. The offset and DST strings are optional.
+ */
+
+ len = strlen(zone);
+ if (len > 3) {
+ len = 3;
+ }
+ if (dst != 0) {
+ /*
+ * Skip the offset string and get the DST string.
+ */
+
+ p = zone + len;
+ p += strspn(p, "+-:0123456789");
+ if (*p != '\0') {
+ zone = p;
+ len = strlen(zone);
+ if (len > 3) {
+ len = 3;
+ }
+ }
+ }
+ Tcl_ExternalToUtf(NULL, NULL, zone, len, 0, NULL, name,
+ sizeof(tsdPtr->tzName), NULL, NULL, NULL);
+ }
+ if (name[0] == '\0') {
+ if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_UNKNOWN) {
+ /*
+ * MSDN: On NT this is returned if DST is not used in the current
+ * TZ
+ */
+
+ dst = 0;
+ }
+ encoding = Tcl_GetEncoding(NULL, "unicode");
+ Tcl_ExternalToUtf(NULL, encoding,
+ (char *) ((dst) ? tz.DaylightName : tz.StandardName), -1,
+ 0, NULL, name, sizeof(tsdPtr->tzName), NULL, NULL, NULL);
+ Tcl_FreeEncoding(encoding);
+ }
+ return name;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclpGetDate --
*
* This function converts between seconds and struct tm. If useGMT is
@@ -783,26 +620,15 @@ StopCalibration(
*----------------------------------------------------------------------
*/
-#ifndef TCL_NO_DEPRECATED
struct tm *
TclpGetDate(
- const time_t *t,
+ CONST time_t *t,
int useGMT)
{
struct tm *tmPtr;
time_t time;
-#if defined(_WIN64) || defined(_USE_64BIT_TIME_T)
-# define t2 *t /* no need to cripple time to 32-bit */
-#else
- time_t t2 = *(__time32_t *) t;
-#endif
if (!useGMT) {
-#if defined(_MSC_VER)
-# undef timezone /* prevent conflict with timezone() function */
- long timezone = 0;
-#endif
-
tzset();
/*
@@ -811,15 +637,28 @@ TclpGetDate(
* daylight savings time before the epoch.
*/
- if (t2 >= 0) {
- return TclpLocaltime(&t2);
- }
+ /*
+ * Hm, Borland's localtime manages to return NULL under certain
+ * circumstances (e.g. wintime.test, test 1.2). Nobody tests for this,
+ * since 'localtime' isn't supposed to do this, possibly leading to
+ * crashes.
+ *
+ * Patch: We only call this function if we are at least one day into
+ * the epoch, else we handle it ourselves (like we do for times < 0).
+ * H. Giese, June 2003
+ */
-#if defined(_MSC_VER)
- _get_timezone(&timezone);
+#ifdef __BORLANDC__
+#define LOCALTIME_VALIDITY_BOUNDARY SECSPERDAY
+#else
+#define LOCALTIME_VALIDITY_BOUNDARY 0
#endif
- time = t2 - timezone;
+ if (*t >= LOCALTIME_VALIDITY_BOUNDARY) {
+ return TclpLocaltime(t);
+ }
+
+ time = *t - timezone;
/*
* If we aren't near to overflowing the long, just add the bias and
@@ -827,10 +666,10 @@ TclpGetDate(
* result at the end.
*/
- if (t2 < (LONG_MAX - 2*SECSPERDAY) && t2 > (LONG_MIN + 2*SECSPERDAY)) {
+ if (*t < (LONG_MAX - 2*SECSPERDAY) && *t > (LONG_MIN + 2*SECSPERDAY)) {
tmPtr = ComputeGMT(&time);
} else {
- tmPtr = ComputeGMT(&t2);
+ tmPtr = ComputeGMT(t);
tzset();
@@ -846,14 +685,14 @@ TclpGetDate(
time -= 60;
}
- time = tmPtr->tm_min + time / 60;
+ time = tmPtr->tm_min + time/60;
tmPtr->tm_min = (int)(time % 60);
if (tmPtr->tm_min < 0) {
tmPtr->tm_min += 60;
time -= 60;
}
- time = tmPtr->tm_hour + time / 60;
+ time = tmPtr->tm_hour + time/60;
tmPtr->tm_hour = (int)(time % 24);
if (tmPtr->tm_hour < 0) {
tmPtr->tm_hour += 24;
@@ -861,12 +700,12 @@ TclpGetDate(
}
time /= 24;
- tmPtr->tm_mday += (int) time;
- tmPtr->tm_yday += (int) time;
- tmPtr->tm_wday = (tmPtr->tm_wday + (int) time) % 7;
+ tmPtr->tm_mday += (int)time;
+ tmPtr->tm_yday += (int)time;
+ tmPtr->tm_wday = (tmPtr->tm_wday + (int)time) % 7;
}
} else {
- tmPtr = ComputeGMT(&t2);
+ tmPtr = ComputeGMT(t);
}
return tmPtr;
}
@@ -904,8 +743,8 @@ ComputeGMT(
* Compute the 4 year span containing the specified time.
*/
- tmp = (long) (*tp / SECSPER4YEAR);
- rem = (long) (*tp % SECSPER4YEAR);
+ tmp = (long)(*tp / SECSPER4YEAR);
+ rem = (long)(*tp % SECSPER4YEAR);
/*
* Correct for weird mod semantics so the remainder is always positive.
@@ -972,7 +811,7 @@ ComputeGMT(
* Compute day of week. Epoch started on a Thursday.
*/
- tmPtr->tm_wday = (long) (*tp / SECSPERDAY) + 4;
+ tmPtr->tm_wday = (long)(*tp / SECSPERDAY) + 4;
if ((*tp % SECSPERDAY) < 0) {
tmPtr->tm_wday--;
}
@@ -983,7 +822,6 @@ ComputeGMT(
return tmPtr;
}
-#endif /* TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
@@ -1013,7 +851,7 @@ ComputeGMT(
static DWORD WINAPI
CalibrationThread(
- TCL_UNUSED(LPVOID))
+ LPVOID arg)
{
FILETIME curFileTime;
DWORD waitResult;
@@ -1028,12 +866,6 @@ CalibrationThread(
timeInfo.fileTimeLastCall.LowPart = curFileTime.dwLowDateTime;
timeInfo.fileTimeLastCall.HighPart = curFileTime.dwHighDateTime;
- /*
- * Calibrated file-time will be saved from Posix in 100-ns ticks.
- */
-
- timeInfo.fileTimeLastCall.QuadPart -= timeInfo.posixEpoch.QuadPart;
-
ResetCounterSamples(timeInfo.fileTimeLastCall.QuadPart,
timeInfo.perfCounterLastCall.QuadPart,
timeInfo.curCounterFreq.QuadPart);
@@ -1061,6 +893,7 @@ CalibrationThread(
UpdateTimeEachSecond();
}
+ /* lint */
return (DWORD) 0;
}
@@ -1091,45 +924,29 @@ UpdateTimeEachSecond(void)
/* Current value returned from
* QueryPerformanceCounter. */
FILETIME curSysTime; /* Current system time. */
- static LARGE_INTEGER lastFileTime;
- /* File time of the previous calibration */
LARGE_INTEGER curFileTime; /* File time at the time this callback was
* scheduled. */
- long long estFreq; /* Estimated perf counter frequency. */
- long long vt0; /* Tcl time right now. */
- long long vt1; /* Tcl time one second from now. */
- long long tdiff; /* Difference between system clock and Tcl
+ Tcl_WideInt estFreq; /* Estimated perf counter frequency. */
+ Tcl_WideInt vt0; /* Tcl time right now. */
+ Tcl_WideInt vt1; /* Tcl time one second from now. */
+ Tcl_WideInt tdiff; /* Difference between system clock and Tcl
* time. */
- long long driftFreq; /* Frequency needed to drift virtual time into
+ Tcl_WideInt driftFreq; /* Frequency needed to drift virtual time into
* step over 1 second. */
/*
- * Sample performance counter and system time (from Posix epoch).
+ * Sample performance counter and system time.
*/
+ QueryPerformanceCounter(&curPerfCounter);
GetSystemTimeAsFileTime(&curSysTime);
curFileTime.LowPart = curSysTime.dwLowDateTime;
curFileTime.HighPart = curSysTime.dwHighDateTime;
- curFileTime.QuadPart -= timeInfo.posixEpoch.QuadPart;
-
- /*
- * If calibration still not needed (check for possible time switch)
- */
-
- if (curFileTime.QuadPart > lastFileTime.QuadPart && curFileTime.QuadPart <
- lastFileTime.QuadPart + (timeInfo.calibrationInterv * 10000000)) {
- /*
- * Look again in next one second.
- */
-
- return;
- }
- QueryPerformanceCounter(&curPerfCounter);
- lastFileTime.QuadPart = curFileTime.QuadPart;
+ EnterCriticalSection(&timeInfo.cs);
/*
- * We divide by timeInfo.curCounterFreq.QuadPart in several places. That
+ * We devide by timeInfo.curCounterFreq.QuadPart in several places. That
* value should always be positive on a correctly functioning system. But
* it is good to be defensive about such matters. So if something goes
* wrong and the value does goes to zero, we clear the
@@ -1138,6 +955,7 @@ UpdateTimeEachSecond(void)
*/
if (timeInfo.curCounterFreq.QuadPart == 0){
+ LeaveCriticalSection(&timeInfo.cs);
timeInfo.perfCounterAvailable = 0;
return;
}
@@ -1157,7 +975,7 @@ UpdateTimeEachSecond(void)
*/
estFreq = AccumulateSample(curPerfCounter.QuadPart,
- (unsigned long long) curFileTime.QuadPart);
+ (Tcl_WideUInt) curFileTime.QuadPart);
/*
* We want to adjust things so that time appears to be continuous.
@@ -1176,9 +994,11 @@ UpdateTimeEachSecond(void)
* is estFreq * 20000000 / (vt1 - vt0)
*/
- vt0 = NativeCalc100NsTicks(timeInfo.fileTimeLastCall.QuadPart,
- timeInfo.perfCounterLastCall.QuadPart,
- timeInfo.curCounterFreq.QuadPart, curPerfCounter.QuadPart);
+ vt0 = 10000000 * (curPerfCounter.QuadPart
+ - timeInfo.perfCounterLastCall.QuadPart)
+ / timeInfo.curCounterFreq.QuadPart
+ + timeInfo.fileTimeLastCall.QuadPart;
+ vt1 = 20000000 + curFileTime.QuadPart;
/*
* If we've gotten more than a second away from system time, then drifting
@@ -1188,111 +1008,21 @@ UpdateTimeEachSecond(void)
tdiff = vt0 - curFileTime.QuadPart;
if (tdiff > 10000000 || tdiff < -10000000) {
- /*
- * Jump to current system time, use curent estimated frequency.
- */
-
- vt0 = curFileTime.QuadPart;
+ timeInfo.fileTimeLastCall.QuadPart = curFileTime.QuadPart;
+ timeInfo.curCounterFreq.QuadPart = estFreq;
} else {
- /*
- * Calculate new frequency and estimate drift to the next second.
- */
-
- vt1 = 20000000 + curFileTime.QuadPart;
- driftFreq = (estFreq * 20000000 / (vt1 - vt0));
-
- /*
- * Avoid too large drifts (only half of the current difference), that
- * allows also be more accurate (aspire to the smallest tdiff), so
- * then we can prolong calibration interval by tdiff < 100000
- */
-
- driftFreq = timeInfo.curCounterFreq.QuadPart +
- (driftFreq - timeInfo.curCounterFreq.QuadPart) / 2;
+ driftFreq = estFreq * 20000000 / (vt1 - vt0);
- /*
- * Average between estimated, 2 current and 5 drifted frequencies,
- * (do the soft drifting as possible)
- */
-
- estFreq = (estFreq + 2 * timeInfo.curCounterFreq.QuadPart +
- 5 * driftFreq) / 8;
- }
-
- /*
- * Avoid too large discrepancy from nominal frequency.
- */
-
- if (estFreq > 1003 * timeInfo.nominalFreq.QuadPart / 1000) {
- estFreq = 1003 * timeInfo.nominalFreq.QuadPart / 1000;
- vt0 = curFileTime.QuadPart;
- } else if (estFreq < 997 * timeInfo.nominalFreq.QuadPart / 1000) {
- estFreq = 997 * timeInfo.nominalFreq.QuadPart / 1000;
- vt0 = curFileTime.QuadPart;
- } else if (vt0 != curFileTime.QuadPart) {
- /*
- * Be sure the clock ticks never backwards (avoid it by negative
- * drifting). Just compare native time (in 100-ns) before and
- * hereafter using new calibrated values) and do a small adjustment
- * (short time freeze).
- */
-
- LARGE_INTEGER newPerfCounter;
- long long nt0, nt1;
-
- QueryPerformanceCounter(&newPerfCounter);
- nt0 = NativeCalc100NsTicks(timeInfo.fileTimeLastCall.QuadPart,
- timeInfo.perfCounterLastCall.QuadPart,
- timeInfo.curCounterFreq.QuadPart, newPerfCounter.QuadPart);
- nt1 = NativeCalc100NsTicks(vt0,
- curPerfCounter.QuadPart, estFreq, newPerfCounter.QuadPart);
- if (nt0 > nt1) {
- /*
- * Drifted backwards, try to compensate with new base.
- *
- * First adjust with a micro jump (short frozen time is
- * acceptable).
- */
- vt0 += nt0 - nt1;
-
- /*
- * If drift unavoidable (e. g. we had a time switch), then reset
- * it.
- */
-
- vt1 = vt0 - curFileTime.QuadPart;
- if (vt1 > 10000000 || vt1 < -10000000) {
- /*
- * Larger jump resp. shift relative new file-time.
- */
-
- vt0 = curFileTime.QuadPart;
- }
+ if (driftFreq > 1003*estFreq/1000) {
+ driftFreq = 1003*estFreq/1000;
+ } else if (driftFreq < 997*estFreq/1000) {
+ driftFreq = 997*estFreq/1000;
}
- }
-
- /*
- * In lock commit new values to timeInfo (hold lock as short as possible)
- */
- EnterCriticalSection(&timeInfo.cs);
-
- /*
- * Grow calibration interval up to 10 seconds (if still precise enough)
- */
-
- if (tdiff < -100000 || tdiff > 100000) {
- /*
- * Too long drift. Reset calibration interval to 1000 second.
- */
-
- timeInfo.calibrationInterv = 1;
- } else if (timeInfo.calibrationInterv < 10) {
- timeInfo.calibrationInterv++;
+ timeInfo.fileTimeLastCall.QuadPart = vt0;
+ timeInfo.curCounterFreq.QuadPart = driftFreq;
}
- timeInfo.fileTimeLastCall.QuadPart = vt0;
- timeInfo.curCounterFreq.QuadPart = estFreq;
timeInfo.perfCounterLastCall.QuadPart = curPerfCounter.QuadPart;
LeaveCriticalSection(&timeInfo.cs);
@@ -1319,13 +1049,12 @@ UpdateTimeEachSecond(void)
static void
ResetCounterSamples(
- unsigned long long fileTime,/* Current file time */
- long long perfCounter, /* Current performance counter */
- long long perfFreq) /* Target performance frequency */
+ Tcl_WideUInt fileTime, /* Current file time */
+ Tcl_WideInt perfCounter, /* Current performance counter */
+ Tcl_WideInt perfFreq) /* Target performance frequency */
{
int i;
-
- for (i = SAMPLES - 1 ; i >= 0 ; --i) {
+ for (i=SAMPLES-1 ; i>=0 ; --i) {
timeInfo.perfCounterSample[i] = perfCounter;
timeInfo.fileTimeSample[i] = fileTime;
perfCounter -= perfFreq;
@@ -1360,22 +1089,20 @@ ResetCounterSamples(
* case).
*/
-static long long
+static Tcl_WideInt
AccumulateSample(
- long long perfCounter,
- unsigned long long fileTime)
+ Tcl_WideInt perfCounter,
+ Tcl_WideUInt fileTime)
{
- unsigned long long workFTSample;
- /* File time sample being removed from or
+ Tcl_WideUInt workFTSample; /* File time sample being removed from or
* added to the circular buffer. */
- long long workPCSample; /* Performance counter sample being removed
+ Tcl_WideInt workPCSample; /* Performance counter sample being removed
* from or added to the circular buffer. */
- unsigned long long lastFTSample;
- /* Last file time sample recorded */
- long long lastPCSample; /* Last performance counter sample recorded */
- long long FTdiff; /* Difference between last FT and current */
- long long PCdiff; /* Difference between last PC and current */
- long long estFreq; /* Estimated performance counter frequency */
+ Tcl_WideUInt lastFTSample; /* Last file time sample recorded */
+ Tcl_WideInt lastPCSample; /* Last performance counter sample recorded */
+ Tcl_WideInt FTdiff; /* Difference between last FT and current */
+ Tcl_WideInt PCdiff; /* Difference between last PC and current */
+ Tcl_WideInt estFreq; /* Estimated performance counter frequency */
/*
* Test for jumps and reset the samples if we have one.
@@ -1409,7 +1136,7 @@ AccumulateSample(
estFreq = 10000000 * (perfCounter - workPCSample)
/ (fileTime - workFTSample);
timeInfo.perfCounterSample[timeInfo.sampleNo] = perfCounter;
- timeInfo.fileTimeSample[timeInfo.sampleNo] = (long long) fileTime;
+ timeInfo.fileTimeSample[timeInfo.sampleNo] = (Tcl_WideInt) fileTime;
/*
* Advance the sample number.
@@ -1439,10 +1166,9 @@ AccumulateSample(
*----------------------------------------------------------------------
*/
-#ifndef TCL_NO_DEPRECATED
struct tm *
TclpGmtime(
- const time_t *timePtr) /* Pointer to the number of seconds since the
+ CONST time_t *timePtr) /* Pointer to the number of seconds since the
* local system's epoch */
{
/*
@@ -1451,11 +1177,7 @@ TclpGmtime(
* Posix gmtime_r function.
*/
-#if defined(_WIN64) || defined(_USE_64BIT_TIME_T)
return gmtime(timePtr);
-#else
- return _gmtime32((const __time32_t *) timePtr);
-#endif /* _WIN64 || _USE_64BIT_TIME_T */
}
/*
@@ -1477,8 +1199,9 @@ TclpGmtime(
struct tm *
TclpLocaltime(
- const time_t *timePtr) /* Pointer to the number of seconds since the
+ CONST time_t *timePtr) /* Pointer to the number of seconds since the
* local system's epoch */
+
{
/*
* The MS implementation of localtime is thread safe because it returns
@@ -1486,13 +1209,8 @@ TclpLocaltime(
* provide a Posix localtime_r function.
*/
-#if defined(_WIN64) || defined(_USE_64BIT_TIME_T)
return localtime(timePtr);
-#else
- return _localtime32((const __time32_t *) timePtr);
-#endif /* _WIN64 || _USE_64BIT_TIME_T */
}
-#endif /* TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
@@ -1515,7 +1233,7 @@ void
Tcl_SetTimeProc(
Tcl_GetTimeProc *getProc,
Tcl_ScaleTimeProc *scaleProc,
- void *clientData)
+ ClientData clientData)
{
tclGetTimeProcPtr = getProc;
tclScaleTimeProcPtr = scaleProc;
@@ -1542,7 +1260,7 @@ void
Tcl_QueryTimeProc(
Tcl_GetTimeProc **getProc,
Tcl_ScaleTimeProc **scaleProc,
- void **clientData)
+ ClientData *clientData)
{
if (getProc) {
*getProc = tclGetTimeProcPtr;
diff --git a/win/tclooConfig.sh b/win/tclooConfig.sh
deleted file mode 100644
index a400b5b..0000000
--- a/win/tclooConfig.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-# tclooConfig.sh --
-#
-# This shell script (for sh) is generated automatically by TclOO's configure
-# script, or would be except it has no values that we substitute. It will
-# create shell variables for most of the configuration options discovered by
-# the configure script. This script is intended to be included by TEA-based
-# configure scripts for TclOO extensions so that they don't have to figure
-# this all out for themselves.
-#
-# The information in this file is specific to a single platform.
-
-# These are mostly empty because no special steps are ever needed from Tcl 8.6
-# onwards; all libraries and include files are just part of Tcl.
-TCLOO_LIB_SPEC=""
-TCLOO_STUB_LIB_SPEC=""
-TCLOO_INCLUDE_SPEC=""
-TCLOO_PRIVATE_INCLUDE_SPEC=""
-TCLOO_CFLAGS=""
-TCLOO_VERSION=1.3
diff --git a/win/tclsh.exe.manifest.in b/win/tclsh.exe.manifest.in
index dc652e6..8b06fce 100644
--- a/win/tclsh.exe.manifest.in
+++ b/win/tclsh.exe.manifest.in
@@ -28,6 +28,8 @@
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!-- Windows Vista -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
<asmv3:application>
@@ -35,10 +37,6 @@
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
- <asmv3:windowsSettings
- xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
- <activeCodePage>UTF-8</activeCodePage>
- </asmv3:windowsSettings>
</asmv3:application>
<dependency>
<dependentAssembly>
diff --git a/win/tclsh.ico b/win/tclsh.ico
index e254318..8bcaf48 100644
--- a/win/tclsh.ico
+++ b/win/tclsh.ico
Binary files differ
diff --git a/win/tclsh.rc b/win/tclsh.rc
index f439d08..161da50 100644
--- a/win/tclsh.rc
+++ b/win/tclsh.rc
@@ -8,6 +8,12 @@
//
// build-up the name suffix that defines the type of build this is.
//
+#if TCL_THREADS
+#define SUFFIX_THREADS "t"
+#else
+#define SUFFIX_THREADS ""
+#endif
+
#if STATIC_BUILD
#define SUFFIX_STATIC "s"
#else
@@ -20,7 +26,7 @@
#define SUFFIX_DEBUG ""
#endif
-#define SUFFIX SUFFIX_STATIC SUFFIX_DEBUG
+#define SUFFIX SUFFIX_THREADS SUFFIX_STATIC SUFFIX_DEBUG
LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */
@@ -44,8 +50,9 @@ BEGIN
BEGIN
VALUE "FileDescription", "Tclsh Application\0"
VALUE "OriginalFilename", "tclsh" STRINGIFY(TCL_MAJOR_VERSION) STRINGIFY(TCL_MINOR_VERSION) SUFFIX ".exe\0"
+ VALUE "CompanyName", "ActiveState Corporation\0"
VALUE "FileVersion", TCL_PATCH_LEVEL
- VALUE "LegalCopyright", "Copyright \251 1987-2022 Regents of the University of California and other parties\0"
+ VALUE "LegalCopyright", "Copyright \251 2000 by ActiveState Corporation, et al\0"
VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0"
VALUE "ProductVersion", TCL_PATCH_LEVEL
END
diff --git a/win/tcltest.rc b/win/tcltest.rc
deleted file mode 100644
index 847a250..0000000
--- a/win/tcltest.rc
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// Version Resource Script
-//
-
-#include <winver.h>
-#include <tcl.h>
-
-//
-// build-up the name suffix that defines the type of build this is.
-//
-#if STATIC_BUILD
-#define SUFFIX_STATIC "s"
-#else
-#define SUFFIX_STATIC ""
-#endif
-
-#if DEBUG && !UNCHECKED
-#define SUFFIX_DEBUG "g"
-#else
-#define SUFFIX_DEBUG ""
-#endif
-
-#define SUFFIX SUFFIX_STATIC SUFFIX_DEBUG
-
-
-LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL
- PRODUCTVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL
- FILEFLAGSMASK 0x3fL
-#ifdef DEBUG
- FILEFLAGS VS_FF_DEBUG
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS VOS__WINDOWS32
- FILETYPE VFT_APP
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "FileDescription", "Tcltest Application\0"
- VALUE "OriginalFilename", "tcltest" STRINGIFY(TCL_MAJOR_VERSION) STRINGIFY(TCL_MINOR_VERSION) SUFFIX ".exe\0"
- VALUE "FileVersion", TCL_PATCH_LEVEL
- VALUE "LegalCopyright", "Copyright \251 1987-2022 Regents of the University of California and other parties\0"
- VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0"
- VALUE "ProductVersion", TCL_PATCH_LEVEL
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-//
-// Icon
-//
-
-tclsh ICON DISCARDABLE "tclsh.ico"
-
-//
-// This is needed for Windows 8.1 onwards.
-//
-
-#ifndef RT_MANIFEST
-#define RT_MANIFEST 24
-#endif
-#ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID
-#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
-#endif
-CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "tclsh.exe.manifest"
diff --git a/win/x86_64-w64-mingw32-nmakehlp.exe b/win/x86_64-w64-mingw32-nmakehlp.exe
deleted file mode 100755
index f821add..0000000
--- a/win/x86_64-w64-mingw32-nmakehlp.exe
+++ /dev/null
Binary files differ