./0000700000175000017500000000000012703651743010527 5ustar sergeisergei./tclvfs/0000755000175000017500000000000012703651745012044 5ustar sergeisergei./tclvfs/win/0000755000175000017500000000000012703651745012641 5ustar sergeisergei./tclvfs/win/tclvfs.rc0000644000175000017500000000227411006106740014456 0ustar sergeisergei// tclvfs.rc - Copyright (C) 2008 Pat Thoyts // // Note: the version numbers in here are all provided from the makefile. // No editing required. // // $Id: tclvfs.rc,v 1.1 2008/04/30 15:18:56 patthoyts Exp $ #include VS_VERSION_INFO VERSIONINFO FILEVERSION COMMAVERSION PRODUCTVERSION COMMAVERSION FILEFLAGSMASK 0x3fL #ifdef DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ BEGIN VALUE "FileDescription", "Tcl virtual filesystem support\0" VALUE "OriginalFilename", "vfs" VERSION ".dll\0" VALUE "FileVersion", DOTVERSION "\0" VALUE "LegalCopyright", "Copyright \251 2001 Vince Darley et al.\0" VALUE "ProductName", "TclVfs " DOTVERSION " for Windows\0" VALUE "ProductVersion", DOTVERSION "\0" VALUE "Comments", "http://sourceforge.net/projects/tclvfs\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END ./tclvfs/win/rules.vc0000644000175000017500000004372711136102212014315 0ustar sergeisergei#------------------------------------------------------------- -*- Makefile -*- # rules.vc -- # # Microsoft Visual C++ makefile include for decoding the commandline # macros. This file does not need editing to build Tcl. # # This version is modified from the Tcl source version to support # building extensions using nmake. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 2001-2002 David Gravereaux. # Copyright (c) 2003-2008 Patrick Thoyts # #------------------------------------------------------------------------------ # RCS: @(#) $Id: rules.vc,v 1.2 2009/01/22 14:36:58 patthoyts Exp $ #------------------------------------------------------------------------------ !ifndef _RULES_VC _RULES_VC = 1 cc32 = $(CC) # built-in default. link32 = link lib32 = lib rc32 = $(RC) # built-in default. !ifndef INSTALLDIR ### Assume the normal default. _INSTALLDIR = C:\Program Files\Tcl !else ### Fix the path separators. _INSTALLDIR = $(INSTALLDIR:/=\) !endif !ifndef MACHINE !if "$(CPU)" == "" || "$(CPU)" == "i386" MACHINE = IX86 !else MACHINE = $(CPU) !endif !endif !ifndef CFG_ENCODING CFG_ENCODING = \"cp1252\" !endif #---------------------------------------------------------- # 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 COPY = copy /y >NUL !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 MKDIR = mkdir !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 !endif #---------------------------------------------------------- # Test for compiler features #---------------------------------------------------------- ### test for optimizations !if [nmakehlp -c -Ot] !message *** Compiler has 'Optimizations' OPTIMIZING = 1 !else !message *** Compiler does not have 'Optimizations' OPTIMIZING = 0 !endif OPTIMIZATIONS = !if [nmakehlp -c -Ot] OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot !endif !if [nmakehlp -c -Oi] OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi !endif !if [nmakehlp -c -Op] OPTIMIZATIONS = $(OPTIMIZATIONS) -Op !endif !if [nmakehlp -c -fp:strict] OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:strict !endif !if [nmakehlp -c -Gs] OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs !endif !if [nmakehlp -c -GS] OPTIMIZATIONS = $(OPTIMIZATIONS) -GS !endif !if [nmakehlp -c -GL] OPTIMIZATIONS = $(OPTIMIZATIONS) -GL !endif DEBUGFLAGS = !if [nmakehlp -c -RTC1] DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 !elseif [nmakehlp -c -GZ] DEBUGFLAGS = $(DEBUGFLAGS) -GZ !endif COMPILERFLAGS =-W3 # In v13 -GL and -YX are incompatible. !if [nmakehlp -c -YX] !if ![nmakehlp -c -GL] OPTIMIZATIONS = $(OPTIMIZATIONS) -YX !endif !endif !if "$(MACHINE)" == "IX86" ### test for pentium errata !if [nmakehlp -c -QI0f] !message *** Compiler has 'Pentium 0x0f fix' COMPILERFLAGS = $(COMPILERFLAGSS) -QI0f !else !message *** Compiler does not have 'Pentium 0x0f fix' !endif !endif !if "$(MACHINE)" == "IA64" ### test for Itanium errata !if [nmakehlp -c -QIA64_Bx] !message *** Compiler has 'B-stepping errata workarounds' COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx !else !message *** Compiler does not have 'B-stepping errata workarounds' !endif !endif !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 !message *** Linker does not have 'Win98 alignment problem' ALIGN98_HACK = 0 !endif !else ALIGN98_HACK = 0 !endif LINKERFLAGS = !if [nmakehlp -l -ltcg] LINKERFLAGS =-ltcg !endif #---------------------------------------------------------- # MSVC8 (ships with Visual Studio 2005) generates a manifest # file that we should link into the binaries. This is how. #---------------------------------------------------------- _VC_MANIFEST_EMBED_EXE= _VC_MANIFEST_EMBED_DLL= VCVER=0 !if ![echo VCVERSION=_MSC_VER > vercl.x] \ && ![cl -nologo -TC -P vercl.x $(ERRNULL)] !include vercl.i !if ![del /q vercl.x vercl.i $(ERRNULL)] !endif !if $(VCVERSION) >= 1500 VCVER=9 !elseif $(VCVERSION) >= 1400 VCVER=8 !elseif $(VCVERSION) >= 1300 VCVER=7 !elseif $(VCVERSION) >= 1200 VCVER=6 !endif !endif # Since MSVC8 we must deal with manifest resources. !if $(VCVERSION) >= 1400 _VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 _VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 !endif #---------------------------------------------------------- # Decode the options requested. #---------------------------------------------------------- !if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"] STATIC_BUILD = 0 TCL_THREADS = 1 DEBUG = 0 PROFILE = 0 MSVCRT = 0 LOIMPACT = 0 TCL_USE_STATIC_PACKAGES = 0 USE_THREAD_ALLOC = 1 USE_THREAD_STORAGE = 1 UNCHECKED = 0 !else !if [nmakehlp -f $(OPTS) "static"] !message *** Doing static STATIC_BUILD = 1 !else STATIC_BUILD = 0 !endif !if [nmakehlp -f $(OPTS) "msvcrt"] !message *** Doing msvcrt MSVCRT = 1 !else MSVCRT = 0 !endif !if [nmakehlp -f $(OPTS) "staticpkg"] !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 !else TCL_THREADS = 1 !endif !if [nmakehlp -f $(OPTS) "symbols"] !message *** Doing symbols DEBUG = 1 !else DEBUG = 0 !endif !if [nmakehlp -f $(OPTS) "profile"] !message *** Doing profile PROFILE = 1 !else PROFILE = 0 !endif !if [nmakehlp -f $(OPTS) "loimpact"] !message *** Doing loimpact LOIMPACT = 1 !else LOIMPACT = 0 !endif !if [nmakehlp -f $(OPTS) "thrdalloc"] !message *** Doing thrdalloc USE_THREAD_ALLOC = 1 !else USE_THREAD_ALLOC = 0 !endif !if [nmakehlp -f $(OPTS) "thrdstorage"] !message *** Doing thrdstorage USE_THREAD_STORAGE = 1 !else USE_THREAD_STORAGE = 0 !endif !if [nmakehlp -f $(OPTS) "unchecked"] !message *** Doing unchecked UNCHECKED = 1 !else UNCHECKED = 0 !endif !endif !if !$(STATIC_BUILD) # Make sure we don't build overly fat DLLs. MSVCRT = 1 # We shouldn't statically put the extensions inside the shell when dynamic. TCL_USE_STATIC_PACKAGES = 0 !endif #---------------------------------------------------------- # Figure-out how to name our intermediate and output directories. # 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 = sgx !if $(DEBUG) BUILDDIRTOP = Debug !else BUILDDIRTOP = Release !endif !if "$(MACHINE)" != "IX86" BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE) !endif !if $(VCVER) > 6 BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) !endif !if !$(DEBUG) || $(DEBUG) && $(UNCHECKED) SUFX = $(SUFX:g=) !endif TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX !if !$(STATIC_BUILD) TMP_DIRFULL = $(TMP_DIRFULL:Static=) SUFX = $(SUFX:s=) EXT = dll !if $(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) !endif !else TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) EXT = lib !if !$(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) !endif !endif !if !$(TCL_THREADS) TMP_DIRFULL = $(TMP_DIRFULL:Threaded=) SUFX = $(SUFX:t=) !endif !ifndef TMP_DIR TMP_DIR = $(TMP_DIRFULL) !ifndef OUT_DIR OUT_DIR = .\$(BUILDDIRTOP) !endif !else !ifndef OUT_DIR OUT_DIR = $(TMP_DIR) !endif !endif #---------------------------------------------------------- # Decode the statistics requested. #---------------------------------------------------------- !if "$(STATS)" == "" || [nmakehlp -f "$(STATS)" "none"] TCL_MEM_DEBUG = 0 TCL_COMPILE_DEBUG = 0 !else !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 #---------------------------------------------------------- # Decode the checks requested. #---------------------------------------------------------- !if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"] TCL_NO_DEPRECATED = 0 WARNINGS = -W3 !else !if [nmakehlp -f $(CHECKS) "nodep"] !message *** Doing nodep check TCL_NO_DEPRECATED = 1 !else TCL_NO_DEPRECATED = 0 !endif !if [nmakehlp -f $(CHECKS) "fullwarn"] !message *** Doing full warnings check WARNINGS = -W4 !if [nmakehlp -l -warn:3] LINKERFLAGS = $(LINKERFLAGS) -warn:3 !endif !else WARNINGS = -W3 !endif !if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64] !message *** Doing 64bit portability warnings WARNINGS = $(WARNINGS) -Wp64 !endif !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 !endif !if $(TCL_COMPILE_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS !endif !if $(TCL_THREADS) OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1 !if $(USE_THREAD_ALLOC) OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1 !endif !if $(USE_THREAD_STORAGE) OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_STORAGE=1 !endif !endif !if $(STATIC_BUILD) OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD !endif !if $(TCL_NO_DEPRECATED) OPTDEFINES = $(OPTDEFINES) -DTCL_NO_DEPRECATED !endif !if $(DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DEBUG !elseif $(OPTIMIZING) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED !endif !if $(PROFILE) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED !endif !if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT !endif #---------------------------------------------------------- # Locate the Tcl headers to build against #---------------------------------------------------------- !if "$(PROJECT)" == "tcl" _TCL_H = ..\generic\tcl.h !else # If INSTALLDIR set to tcl root dir then reset to the lib dir. !if exist("$(_INSTALLDIR)\include\tcl.h") _INSTALLDIR=$(_INSTALLDIR)\lib !endif !if !defined(TCLDIR) !if exist("$(_INSTALLDIR)\..\include\tcl.h") TCLINSTALL = 1 _TCLDIR = $(_INSTALLDIR)\.. _TCL_H = $(_INSTALLDIR)\..\include\tcl.h TCLDIR = $(_INSTALLDIR)\.. !else MSG=^ Failed to find tcl.h. Set the TCLDIR macro. !error $(MSG) !endif !else _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 MSG =^ Failed to find tcl.h. The TCLDIR macro does not appear correct. !error $(MSG) !endif !endif !endif #-------------------------------------------------------------- # Extract various version numbers from tcl headers # The generated file is then included in the makefile. #-------------------------------------------------------------- !if [echo REM = This file is generated from rules.vc > versions.vc] !endif !if [echo TCL_MAJOR_VERSION = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_MAJOR_VERSION >> versions.vc] !endif !if [echo TCL_MINOR_VERSION = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc] !endif !if [echo TCL_PATCH_LEVEL = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc] !endif # 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 !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 !endif !include versions.vc #-------------------------------------------------------------- # Setup tcl version dependent stuff headers #-------------------------------------------------------------- !if "$(PROJECT)" != "tcl" TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION) !if $(TCL_VERSION) < 81 TCL_DOES_STUBS = 0 !else TCL_DOES_STUBS = 1 !endif !if $(TCLINSTALL) _TCLBINDIR = "$(_TCLDIR)\bin" TCLSH = "$(_TCLBINDIR)\tclsh$(TCL_VERSION)$(SUFX).exe" !if !exist($(TCLSH)) && $(TCL_THREADS) TCLSH = "$(_TCLBINDIR)\tclsh$(TCL_VERSION)t$(SUFX).exe" !endif TCLSTUBLIB = "$(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib" TCLIMPLIB = "$(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib" TCL_LIBRARY = $(_TCLDIR)\lib TCLREGLIB = "$(_TCLDIR)\lib\tclreg11$(SUFX:t=).lib" TCLDDELIB = "$(_TCLDIR)\lib\tcldde12$(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 _TCLBINDIR = $(_TCLDIR)\win\$(BUILDDIRTOP) TCLSH = "$(_TCLBINDIR)\tclsh$(TCL_VERSION)$(SUFX).exe" !if !exist($(TCLSH)) && $(TCL_THREADS) TCLSH = "$(_TCLBINDIR)\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)\tclreg11$(SUFX:t=).lib" TCLDDELIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde12$(SUFX:t=).lib" COFFBASE = "$(_TCLDIR)\win\coffbase.txt" TCLTOOLSDIR = $(_TCLDIR)\tools TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win" !endif !endif #------------------------------------------------------------------------- # Locate the Tk headers to build against #------------------------------------------------------------------------- !if "$(PROJECT)" == "tk" _TK_H = ..\generic\tk.h !endif !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 _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 MSG =^ Failed to find tk.h. The TKDIR macro does not appear correct. !error $(MSG) !endif !endif !endif #------------------------------------------------------------------------- # Extract Tk version numbers #------------------------------------------------------------------------- !if defined(PROJECT_REQUIRES_TK) || "$(PROJECT)" == "tk" !if [echo TK_MAJOR_VERSION = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) 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_PATCH_LEVEL = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc] !endif !include versions.vc TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION) !if "$(PROJECT)" != "tk" !if $(TKINSTALL) _TKBINDIR = $(_TKDIR)\bin WISH = "$(_TKBINDIR)\wish$(TK_VERSION)$(SUFX).exe" !if !exist($(WISH)) && $(TCL_THREADS) WISH = "$(_TKBINDIR)\wish$(TK_VERSION)t$(SUFX).exe" !endif TKSTUBLIB = "$(_TKDIR)\lib\tkstub$(TK_VERSION).lib" TK_LIBRARY = $(_TKDIR)\lib TKIMPLIB = "$(_TKDIR)\lib\tk$(TK_VERSION)$(SUFX).lib" TK_INCLUDES = -I"$(_TKDIR)\include" !else _TKBINDIR = $(_TKDIR)\win\$(BUILDDIRTOP) WISH = "$(_TKBINDIR)\wish$(TCL_VERSION)$(SUFX).exe" !if !exist($(WISH)) && $(TCL_THREADS) WISH = "$(_TKBINDIR)\wish$(TCL_VERSION)t$(SUFX).exe" !endif TKSTUBLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tkstub$(TCL_VERSION).lib" TKIMPLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tk$(TCL_VERSION)$(SUFX).lib" TK_LIBRARY = $(_TKDIR)\library TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" !endif !endif !endif #---------------------------------------------------------- # Setup the fully qualified OUT_DIR path as OUT_DIR_PATH #---------------------------------------------------------- !if [echo OUT_DIR_PATH = \>> versions.vc] \ && [nmakehlp -Q "$(OUT_DIR)" >> versions.vc] !endif !include versions.vc #---------------------------------------------------------- # Display stats being used. #---------------------------------------------------------- !message *** Intermediate directory will be '$(TMP_DIR)' !message *** Output directory will be '$(OUT_DIR)' !message *** Suffix for binaries will be '$(SUFX)' !message *** Optional defines are '$(OPTDEFINES)' !message *** Compiler version $(VCVER). Target machine is $(MACHINE) !message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)' !message *** Link options '$(LINKERFLAGS)' !endif ./tclvfs/win/nmakehlp.c0000644000175000017500000004440411136102212014565 0ustar sergeisergei/* * ---------------------------------------------------------------------------- * nmakehlp.c -- * * This is used to fix limitations within nmake and the environment. * * 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. * * ---------------------------------------------------------------------------- * RCS: @(#) $Id: nmakehlp.c,v 1.2 2009/01/22 14:36:58 patthoyts Exp $ * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE #include #define NO_SHLWAPI_GDI #define NO_SHLWAPI_STREAM #define NO_SHLWAPI_REG #include #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") #pragma comment (lib, "shlwapi.lib") #include #include /* * This library is required for x64 builds with _some_ versions of MSVC */ #if defined(_M_IA64) || defined(_M_AMD64) #if _MSC_VER >= 1400 && _MSC_VER < 1500 #pragma comment(lib, "bufferoverflowU") #endif #endif /* ISO hack for dumb VC++ */ #ifdef _MSC_VER #define snprintf _snprintf #endif /* protos */ int CheckForCompilerFeature(const char *option); int CheckForLinkerFeature(const char *option); int IsIn(const char *string, const char *substring); int GrepForDefine(const char *file, const char *string); int SubstituteFile(const char *substs, const char *filename); int QualifyPath(const char *path); const char * GetVersionFromFile(const char *filename, const char *match); DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ #define CHUNK 25 #define STATICBUFFERSIZE 1000 typedef struct { HANDLE pipe; char buffer[STATICBUFFERSIZE]; } pipeinfo; pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; /* * exitcodes: 0 == no, 1 == yes, 2 == error */ int main( int argc, char *argv[]) { char msg[300]; DWORD dwWritten; int chars; /* * Make sure children (cl.exe and link.exe) are kept quiet. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); /* * Make sure the compiler and linker aren't effected by the outside world. */ SetEnvironmentVariable("CL", ""); SetEnvironmentVariable("LINK", ""); if (argc > 1 && *argv[1] == '-') { switch (*(argv[1]+1)) { case 'c': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c \n" "Tests for whether cl.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 CheckForCompilerFeature(argv[2]); case 'l': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -l \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]); case 'f': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -f \n" "Find a substring within another\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } else if (argc == 3) { /* * If the string is blank, there is no match. */ return 0; } else { return IsIn(argv[2], argv[3]); } case 'g': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -g \n" "grep for a #define\n" "exitcodes: integer of the found string (no decimals)\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return GrepForDefine(argv[2], argv[3]); case 's': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -s \n" "Perform a set of string map type substutitions on a file\n" "exitcodes: 0\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return SubstituteFile(argv[2], argv[3]); case 'V': if (argc != 4) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -V filename matchstring\n" "Extract a version from a file:\n" "eg: pkgIndex.tcl \"package ifneeded http\"", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 0; } printf("%s\n", GetVersionFromFile(argv[2], argv[3])); return 0; case 'Q': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -q path\n" "Emit the fully qualified path\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return QualifyPath(argv[2]); } } chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c|-l|-f|-g|-V|-s|-Q ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" "Win9x and get nmake.exe to accomplish its job.\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } int CheckForCompilerFeature( const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; char cmdline[100]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = INVALID_HANDLE_VALUE; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; /* * Create a non-inheritible pipe. */ CreatePipe(&Out.pipe, &h, &sa, 0); /* * Dupe the write side, make it inheritible, and close the original. */ DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Same as above, but for the error side. */ CreatePipe(&Err.pipe, &h, &sa, 0); DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Base command line. */ lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch "); /* * Append our option for testing */ lstrcat(cmdline, option); /* * Filename to compile, which exists, but is nothing and empty. */ lstrcat(cmdline, " .\\nul"); ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ NULL, /* Thread handle not inheritable. */ TRUE, /* yes, inherit handles. */ DETACHED_PROCESS, /* No console for you. */ NULL, /* Use parent's environment block. */ NULL, /* Use parent's starting directory. */ &si, /* Pointer to STARTUPINFO structure. */ &pi); /* Pointer to PROCESS_INFORMATION structure. */ if (!ok) { DWORD err = GetLastError(); int chars = snprintf(msg, sizeof(msg) - 1, "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, (LPVOID)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg,lstrlen(msg), &err,NULL); return 2; } /* * Close our references to the write handles that have now been inherited. */ CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); /* * Start the pipe reader threads. */ pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); /* * Block waiting for the process to end. */ WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); /* * Wait for our pipe to get done reading, should it be a little slow. */ WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); /* * Look for the commandline warning code in both streams. * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002. */ return !(strstr(Out.buffer, "D4002") != NULL || strstr(Err.buffer, "D4002") != NULL || strstr(Out.buffer, "D9002") != NULL || strstr(Err.buffer, "D9002") != NULL || strstr(Out.buffer, "D2021") != NULL || strstr(Err.buffer, "D2021") != NULL); } int CheckForLinkerFeature( const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; char cmdline[100]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = INVALID_HANDLE_VALUE; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; /* * Create a non-inheritible pipe. */ CreatePipe(&Out.pipe, &h, &sa, 0); /* * Dupe the write side, make it inheritible, and close the original. */ DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Same as above, but for the error side. */ CreatePipe(&Err.pipe, &h, &sa, 0); DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Base command line. */ lstrcpy(cmdline, "link.exe -nologo "); /* * Append our option for testing. */ lstrcat(cmdline, option); ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ NULL, /* Thread handle not inheritable. */ TRUE, /* yes, inherit handles. */ DETACHED_PROCESS, /* No console for you. */ NULL, /* Use parent's environment block. */ NULL, /* Use parent's starting directory. */ &si, /* Pointer to STARTUPINFO structure. */ &pi); /* Pointer to PROCESS_INFORMATION structure. */ if (!ok) { DWORD err = GetLastError(); int chars = snprintf(msg, sizeof(msg) - 1, "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, (LPVOID)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg,lstrlen(msg), &err,NULL); return 2; } /* * Close our references to the write handles that have now been inherited. */ CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); /* * Start the pipe reader threads. */ pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); /* * Block waiting for the process to end. */ WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); /* * Wait for our pipe to get done reading, should it be a little slow. */ WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); /* * Look for the commandline warning code in the stderr stream. */ return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL || strstr(Out.buffer, "LNK4044") != NULL || strstr(Err.buffer, "LNK4044") != NULL); } DWORD WINAPI ReadFromPipe( LPVOID args) { pipeinfo *pi = (pipeinfo *) args; char *lastBuf = pi->buffer; DWORD dwRead; BOOL ok; again: if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { CloseHandle(pi->pipe); return (DWORD)-1; } ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); if (!ok || dwRead == 0) { CloseHandle(pi->pipe); return 0; } lastBuf += dwRead; goto again; return 0; /* makes the compiler happy */ } int IsIn( const char *string, const char *substring) { return (strstr(string, substring) != NULL); } /* * Find a specified #define by name. * * If the line is '#define TCL_VERSION "8.5"', it returns 85 as the result. */ int GrepForDefine( const char *file, const char *string) { char s1[51], s2[51], s3[51]; FILE *f = fopen(file, "rt"); if (f == NULL) { return 0; } do { int r = fscanf(f, "%50s", s1); if (r == 1 && !strcmp(s1, "#define")) { /* * Get next two words. */ r = fscanf(f, "%50s %50s", s2, s3); if (r != 2) { continue; } /* * Is the first word what we're looking for? */ if (!strcmp(s2, string)) { double d1; fclose(f); /* * Add 1 past first double quote char. "8.5" */ d1 = atof(s3 + 1); /* 8.5 */ while (floor(d1) != d1) { d1 *= 10.0; } return ((int) d1); /* 85 */ } } } while (!feof(f)); fclose(f); return 0; } /* * GetVersionFromFile -- * Looks for a match string in a file and then returns the version * following the match where a version is anything acceptable to * package provide or package ifneeded. */ const char * GetVersionFromFile( const char *filename, const char *match) { size_t cbBuffer = 100; static char szBuffer[100]; char *szResult = NULL; FILE *fp = fopen(filename, "rt"); if (fp != NULL) { /* * Read data until we see our match string. */ while (fgets(szBuffer, cbBuffer, fp) != NULL) { LPSTR p, q; p = strstr(szBuffer, match); if (p != NULL) { /* * Skip to first digit. */ while (*p && !isdigit(*p)) { ++p; } /* * Find ending whitespace. */ q = p; while (*q && (isalnum(*q) || *q == '.')) { ++q; } memcpy(szBuffer, p, q - p); szBuffer[q-p] = 0; szResult = szBuffer; break; } } fclose(fp); } return szResult; } /* * List helpers for the SubstituteFile function */ typedef struct list_item_t { struct list_item_t *nextPtr; char * key; char * value; } list_item_t; /* insert a list item into the list (list may be null) */ static list_item_t * list_insert(list_item_t **listPtrPtr, const char *key, const char *value) { list_item_t *itemPtr = malloc(sizeof(list_item_t)); if (itemPtr) { itemPtr->key = strdup(key); itemPtr->value = strdup(value); itemPtr->nextPtr = NULL; while(*listPtrPtr) { listPtrPtr = &(*listPtrPtr)->nextPtr; } *listPtrPtr = itemPtr; } return itemPtr; } static void list_free(list_item_t **listPtrPtr) { list_item_t *tmpPtr, *listPtr = *listPtrPtr; while (listPtr) { tmpPtr = listPtr; listPtr = listPtr->nextPtr; free(tmpPtr->key); free(tmpPtr->value); free(tmpPtr); } } /* * 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 - * 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: * \s*\S+\s+\S*$ * * Usage is something like: * nmakehlp -S << $** > $@ * @PACKAGE_NAME@ $(PACKAGE_NAME) * @PACKAGE_VERSION@ $(PACKAGE_VERSION) * << */ int 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; fp = fopen(filename, "rt"); if (fp != NULL) { /* * Build a list of substutitions from the first filename */ sp = fopen(substitutions, "rt"); if (sp != NULL) { while (fgets(szBuffer, cbBuffer, sp) != NULL) { char *ks, *ke, *vs, *ve; ks = szBuffer; while (ks && *ks && isspace(*ks)) ++ks; ke = ks; while (ke && *ke && !isspace(*ke)) ++ke; vs = ke; while (vs && *vs && isspace(*vs)) ++vs; ve = vs; while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; *ke = 0, *ve = 0; list_insert(&substPtr, ks, vs); } fclose(sp); } /* debug: dump the list */ #ifdef _DEBUG { int n = 0; list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); } } #endif /* * Run the substitutions over each line of the input */ 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); if (m) { char *cp, *op, *sp; cp = szCopy; op = szBuffer; while (op != m) *cp++ = *op++; sp = p->value; while (sp && *sp) *cp++ = *sp++; op += strlen(p->key); while (*op) *cp++ = *op++; *cp = 0; memcpy(szBuffer, szCopy, sizeof(szCopy)); } } printf(szBuffer); } list_free(&substPtr); } fclose(fp); return 0; } /* * QualifyPath -- * * This composes the current working directory with a provided path * and returns the fully qualified and normalized path. * Mostly needed to setup paths for testing. */ int QualifyPath( const char *szPath) { char szCwd[MAX_PATH + 1]; 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; } /* * Local variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * indent-tabs-mode: t * tab-width: 8 * End: */ ./tclvfs/win/makefile.vc0000644000175000017500000004022011210263104014722 0ustar sergeisergei# makefile.vc -- -*- Makefile -*- # # Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+) # # This makefile is based upon the Tcl 8.4 Makefile.vc and modified to # make it suitable as a general package makefile. Look for the word EDIT # which marks sections that may need modification. As a minumum you will # need to change the PROJECT, DOTVERSION and DLLOBJS variables to values # relevant to your package. # # 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-2000 Ajuba Solutions. # Copyright (c) 2001 ActiveState Corporation. # Copyright (c) 2001-2002 David Gravereaux. # Copyright (c) 2003-2008 Pat Thoyts # #------------------------------------------------------------------------- # RCS: @(#)$Id: makefile.vc,v 1.32 2009/05/30 17:00:52 patthoyts Exp $ #------------------------------------------------------------------------- # Check to see we are configured to build with MSVC (MSDEVDIR or MSVCDIR) # or with the MS Platform SDK (MSSDK). Visual Studio .NET 2003 and 2005 define # VCINSTALLDIR instead. The MSVC Toolkit release defines yet another. !if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(MSSDK) && !defined(VCINSTALLDIR) && !defined(VCToolkitInstallDir) 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% 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. # # 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. # # 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: # all -- Builds everything. # -- Builds the project (eg: nmake sample) # test -- Builds and runs the test suite. # install -- Installs the built binaries and libraries to $(INSTALLDIR) # in an appropriate subdirectory. # clean/realclean/distclean -- varying levels of cleaning. # # 4) Macros usable on the commandline: # INSTALLDIR= # Sets where to install Tcl from the built binaries. # C:\Progra~1\Tcl is assumed when not specified. # # OPTS=static,msvcrt,staticpkg,threads,symbols,profile,loimpact,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. # # static = Builds a static library of the core instead of a # dll. The shell will be static (and large), as well. # msvcrt = Effects 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. # staticpkg = Effects the static option only to switch # tclshXX.exe to have the dde and reg extension linked # inside it. # nothreads = Turns off multithreading support (not recommended) # thrdalloc = Use the thread allocator (shared global free pool). # symbols = Adds symbols for step debugging. # profile = Adds profiling hooks. Map file is assumed. # loimpact = Adds a flag for how NT treats the heap to keep memory # in use, low. This is said to impact alloc performance. # # STATS=memdbg,compdbg,none # Sets optional memory and bytecode compiler debugging code added # to the core. The default is for none. Any combination of the # above may be used (comma separated). 'none' will over-ride # everything to nothing. # # memdbg = Enables the debugging memory allocator. # compdbg = Enables byte compilation logging. # # MACHINE=(IX86|IA64|ALPHA|AMD64) # 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 # when not specified. If the CPU environment variable has been # set (ie: recent Platform SDK) then MACHINE is set from CPU. # # TMP_DIR= # OUT_DIR= # 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 de $(OUT_DIR)\ by default. # # TESTPAT= # Reads the tests requested to be run from this file. # # 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 all # c:\tcl_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl # # 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 # #------------------------------------------------------------------------------ #============================================================================== ############################################################################### #------------------------------------------------------------------------------ !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 #------------------------------------------------------------------------- # Project specific information (EDIT) # # You should edit this with the name and version of your project. This # information is used to generate the name of the package library and # it's install location. # # For example, the sample extension is going to build sample04.dll and # would install it into $(INSTALLDIR)\lib\sample04 # # You need to specify the object files that need to be linked into your # binary here. # #------------------------------------------------------------------------- PROJECT = vfs # Uncomment the following line if this is a Tk extension. #PROJECT_REQUIRES_TK=1 !include "rules.vc" DOTVERSION = 1.4 VERSION = $(DOTVERSION:.=) STUBPREFIX = $(PROJECT)stub DLLOBJS = \ $(TMP_DIR)\vfs.obj \ $(TMP_DIR)\tclvfs.res TCL_FILES = \ ftpvfs.tcl \ httpvfs.tcl \ mk4vfs.tcl \ starkit.tcl \ tarvfs.tcl \ tclprocvfs.tcl \ testvfs.tcl \ vfsUrl.tcl \ vfsUtils.cl \ vfslib.tcl \ webdavvfs.tcl \ zipvfs.tcl \ tkvfs.tcl TEMPLATEVFS = \ collatevfs.tcl \ deltavfs.tcl \ fishvfs.tcl \ globfind.tcl \ quotavfs.tcl \ tdelta.tcl \ templatevfs.tcl \ versionvfs.tcl \ chrootvfs.tcl #------------------------------------------------------------------------- # Target names and paths ( shouldn't need changing ) #------------------------------------------------------------------------- BINROOT = . ROOT = .. PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) ### Make sure we use backslash only. PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) INCLUDE_INSTALL_DIR = $(_TCLDIR)\include ### The following paths CANNOT have spaces in them. GENERICDIR = $(ROOT)\generic WINDIR = $(ROOT)\win LIBDIR = $(ROOT)\library DOCDIR = $(ROOT)\doc TOOLSDIR = $(ROOT)\tools COMPATDIR = $(ROOT)\compat #--------------------------------------------------------------------- # Compile flags #--------------------------------------------------------------------- !if !$(DEBUG) !if $(OPTIMIZING) ### This cranks the optimization level to maximize speed cdebug = $(OPTIMIZATIONS) !else cdebug = !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 !if !$(STATIC_BUILD) cflags = $(cflags) -DUSE_TCL_STUBS !if defined(TKSTUBLIB) cflags = $(cflags) -DUSE_TK_STUBS !endif !endif INCLUDES = $(TCL_INCLUDES) -I"$(WINDIR)" -I"$(GENERICDIR)" BASE_CFLAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE TCL_CFLAGS = -DPACKAGE_NAME="\"$(PROJECT)\"" \ -DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ -DBUILD_$(PROJECT) $(BASE_CFLAGS) $(OPTDEFINES) ### Stubs files should not be compiled with -GL STUB_CFLAGS = $(cflags) $(cdebug:-GL=) #$(TK_DEFINES) #--------------------------------------------------------------------- # Link flags #--------------------------------------------------------------------- !if $(DEBUG) ldebug = -debug !if $(MSVCRT) ldebug = $(ldebug) -nodefaultlib:msvcrt !endif !else ldebug = -release -opt:ref -opt:icf,3 !endif ### Declarations common to all linker options lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) !if $(PROFILE) lflags = $(lflags) -profile !endif !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 !if $(LOIMPACT) lflags = $(lflags) -ws:aggressive !endif dlllflags = $(lflags) -dll conlflags = $(lflags) -subsystem:console guilflags = $(lflags) -subsystem:windows !if !$(STATIC_BUILD) baselibs = $(TCLSTUBLIB) !if defined(TKSTUBLIB) baselibs = $(baselibs) $(TKSTUBLIB) !endif !endif # Avoid 'unresolved external symbol __security_cookie' errors. # c.f. http://support.microsoft.com/?id=894573 !if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" !if $(VCVERSION) >= 1400 && $(VCVERSION) < 1500 baselibs = $(baselibs) bufferoverflowU.lib !endif !endif !if exist("$(TCLDIR)\win\coffbase.txt") #dllbase = -base:@$(TCLDIR)\win\coffbase.txt,tclvfs dllbase = -base:0x10A70000 !else dllbase = -base:0x10A70000 !endif #--------------------------------------------------------------------- # TclTest flags #--------------------------------------------------------------------- !if "$(TESTPAT)" != "" TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) !endif #--------------------------------------------------------------------- # Project specific targets (EDIT) #--------------------------------------------------------------------- all: setup $(PROJECT) $(PROJECT): setup $(PRJLIB) pkgIndex install: install-binaries install-libraries install-docs pkgIndex: setup $(OUT_DIR)\pkgIndex.tcl $(OUT_DIR)\vfs.tcl test: setup $(PROJECT) @set TCL_LIBRARY=$(TCL_LIBRARY:\=/) @set TCLLIBPATH=$(OUT_DIR_PATH:\=/) $(CPY) $(LIBDIR)\*.tcl $(OUT_DIR) !if $(TCLINSTALL) @set PATH=$(_TCLDIR)\bin;$(PATH) !else @set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH) !endif !if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE" $(DEBUGGER) $(TCLSH) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) !else @echo Please wait while the tests are collected... $(TCLSH) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) > tests.log type tests.log | more !endif shell: setup $(PROJECT) @set TCL_LIBRARY=$(TCL_LIBRARY:\=/) @set TCLLIBPATH=$(OUT_DIR_PATH:\=/) @set VFS_LIBRARY=$(LIBDIR:\=/) !if $(TCLINSTALL) @set PATH=$(_TCLDIR)\bin;$(PATH) !else @set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH) !endif !if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE" $(DEBUGGER) $(TCLSH) !else @echo Please wait while the tests are collected... $(TCLSH) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) > tests.log type tests.log | more !endif setup: @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) $(PRJLIB): $(DLLOBJS) !if $(STATIC_BUILD) $(lib32) -nologo -out:$@ @<< $** << !else $(link32) $(dlllflags) $(dllbase) -out:$@ $(baselibs) @<< $** << $(_VC_MANIFEST_EMBED_DLL) -@del $*.exp !endif $(PRJSTUBLIB): $(PRJSTUBOBJS) $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) #--------------------------------------------------------------------- # Implicit rules #--------------------------------------------------------------------- {$(WINDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(WINDIR)}.rc{$(TMP_DIR)}.res: $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \ -DCOMMAVERSION=$(DOTVERSION:.=,),0,0 \ -DDOTVERSION=\"$(DOTVERSION)\" \ -DVERSION=\"$(VERSION)$(SUFX)\" \ !if $(DEBUG) -d DEBUG \ !endif !if $(TCL_THREADS) -d TCL_THREADS \ !endif !if $(STATIC_BUILD) -d STATIC_BUILD \ !endif $< .SUFFIXES: .SUFFIXES:.c .rc #------------------------------------------------------------------------- # Explicit dependency rules # #------------------------------------------------------------------------- .PHONY: $(OUT_DIR)\pkgIndex.tcl $(OUT_DIR)\vfs.tcl $(OUT_DIR)\pkgIndex.tcl: $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $** > $@ @PACKAGE_NAME@ $(PROJECT) @PACKAGE_VERSION@ $(DOTVERSION) @PKG_LIB_FILE@ $(PRJLIBNAME) << $(OUT_DIR)\vfs.tcl: $(ROOT)\library\vfs.tcl.in nmakehlp -s << $** > $@ @PACKAGE_NAME@ $(PROJECT) @PACKAGE_VERSION@ $(DOTVERSION) @PKG_LIB_FILE@ $(PRJLIBNAME) << #--------------------------------------------------------------------- # Installation. (EDIT) # # You may need to modify this section to reflect the final distribution # of your files and possibly to generate documentation. # #--------------------------------------------------------------------- install-binaries: @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL install-libraries: pkgIndex @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" @echo Installing package entrypoint in '$(SCRIPT_INSTALL_DIR)' @$(CPY) $(OUT_DIR)\vfs.tcl "$(SCRIPT_INSTALL_DIR)" @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' @$(CPY) $(OUT_DIR)\pkgIndex.tcl "$(SCRIPT_INSTALL_DIR)" install-docs: @echo Installing documentation files to '$(DOC_INSTALL_DIR)' @if exist $(DOCDIR) $(CPY) $(DOCDIR)\*.n "$(DOC_INSTALL_DIR)" #--------------------------------------------------------------------- # Clean up #--------------------------------------------------------------------- clean: @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) @if exist $(WINDIR)\versions.vc del $(WINDIR)\versions.vc @if exist $(WINDIR)\vercl.i del $(WINDIR)\vercl.i @if exist $(WINDIR)\vercl.x del $(WINDIR)\vercl.x @if exist $(WINDIR)\_junk.pch del $(WINDIR)\_junk.pch realclean: clean @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) distclean: realclean @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj ./tclvfs/tests/0000755000175000017500000000000012703651745013206 5ustar sergeisergei./tclvfs/tests/vfsZip.test0000644000175000017500000002575411203065310015362 0ustar sergeisergei# vfsZip.test -*- tcl -*- # # Commands covered: the 'zip' vfs. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2001-2002 by Vince Darley. # Copyright (c) 2009 by Pat Thoyts # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } testConstraint zipfs [expr {![catch {package require vfs::zip}]}] # To test this properly we require a zip file. If a zip # executable can be found then we will create one. # testConstraint zipexe [expr {[auto_execok zip] ne ""}] if {[testConstraint zipfs] && [testConstraint zipexe]} { file mkdir zipfs.test makeFile {File one} zipfs.test/One.txt makeFile {File two} zipfs.test/Two.txt file mkdir zipfs.test/Aleph makeFile {File aleph one} zipfs.test/Aleph/One.txt makeFile {File aleph two} zipfs.test/Aleph/Two.txt eval exec [auto_execok zip] [list -r zipfs.zip zipfs.test] eval exec [auto_execok zip] [list zipnest.zip zipfs.zip] file mkdir zipglob.test makeFile {Glob one} "zipglob.test/one\[1\].txt" makeFile {Glob two} "zipglob.test/two \[2\].txt" file mkdir zipglob.test/a\[0\] makeFile {Glob three} "zipglob.test/a\[0\]/three.txt" eval exec [auto_execok zip] [list -r zipglob.zip zipglob.test] testConstraint zipcat [expr {![catch { makeFile {} zipcat.zip set f [open zipcat.zip w] ; fconfigure $f -translation binary set fin [open zipfs.zip r] ; fconfigure $fin -translation binary puts -nonewline $f "[string repeat # 4095]\xff" fcopy $fin $f close $fin ; close $f eval exec [auto_execok zip] [list -A zipcat.zip] }]}] } test vfsZip-1.1 "mount non-existent zip file" -constraints {zipfs} -setup { set file [makeFile {} vfszip.zip] } -body { set mnt [vfs::zip::Mount $file localmount] } -cleanup { removeFile $file } -returnCodes {error} -result {no header found} test vfsZip-1.2 "mount invalid zip file" -constraints {zipfs} -setup { set file [makeFile {random text} vfszip.zip] } -body { set mnt [vfs::zip::Mount $file localmount] } -cleanup { removeFile $file } -returnCodes {error} -result {no header found} test vfsZip-1.3 "mount zipfile" -constraints {zipfs zipexe} -body { vfs::zip::Mount zipfs.zip local vfs::unmount local } -result {} test vfsZip-1.4 "glob" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipfs.zip local } -body { glob -directory local * } -cleanup { vfs::unmount local } -result {local/zipfs.test} test vfsZip-1.5 "glob files" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipfs.zip local } -body { lsort [glob -directory local/zipfs.test -tails *] } -cleanup { vfs::unmount local } -result {Aleph One.txt Two.txt} test vfsZip-1.6 "glob non-present files" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipfs.zip local } -body { lsort [glob -directory local/zipfs.test -tails ridikulus.txt] } -cleanup { vfs::unmount local } -returnCodes {error} -result {no files matched glob pattern "ridikulus.txt"} test vfsZip-1.7 "glob non-present directory" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipfs.zip local } -body { lsort [glob -directory local/zipfs.test/ridikulus -tails *] } -cleanup { vfs::unmount local } -returnCodes {error} -result {no files matched glob pattern "*"} test vfsZip-1.8 "read file" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipfs.zip local } -body { set f [open local/zipfs.test/One.txt r] set data [string trim [read $f]] close $f set data } -cleanup { vfs::unmount local } -result {File one} test vfsZip-1.9 "stat file" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipfs.zip local unset -nocomplain stat set result "" } -body { file stat local/zipfs.test/One.txt stat lappend result type $stat(type) size [expr {$stat(size) > 8}] } -cleanup { unset -nocomplain stat vfs::unmount local } -result {type file size 1} test vfsZip-1.10 "stat directory" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipfs.zip local unset -nocomplain stat set result "" } -body { file stat local/zipfs.test/Aleph stat lappend result type $stat(type) size $stat(size) } -cleanup { unset -nocomplain stat vfs::unmount local } -result {type directory size 0} test vfsZip-1.11 "cd directory" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipfs.zip local set cwd [pwd] } -body { cd local/zipfs.test/Aleph lsort [glob *] } -cleanup { cd $cwd vfs::unmount local } -result {One.txt Two.txt} test vfsZip-1.12 "globby filenames" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipglob.zip local } -body { glob -type f -tail -directory local/zipglob.test * } -cleanup { vfs::unmount local } -result [list "one\[1\].txt" "two \[2\].txt"] test vfsZip-1.13 "globby filenames" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipglob.zip local } -body { set result {} foreach file [glob -type f -directory local/zipglob.test *] { set f [open $file r] lappend result [string trim [read $f]] } set result } -cleanup { vfs::unmount local } -result [list "Glob one" "Glob two"] test vfsZip-1.14 "globby subdir" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipglob.zip local } -body { glob -type d -tail -directory local/zipglob.test * } -cleanup { vfs::unmount local } -result [list "a\[0\]"] test vfsZip-1.15 "globby subdir" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipglob.zip local } -body { set result {} foreach dir [glob -type d -directory local/zipglob.test *] { lappend result [glob -nocomplain -tail -directory $dir *] } set result } -cleanup { vfs::unmount local } -returnCodes {ok error} -result {three.txt} test vfsZip-2.0 "nested stat file" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipnest.zip local unset -nocomplain stat set result "" } -body { file stat local/zipfs.zip stat lappend result type $stat(type) size [expr {$stat(size) != 0}] } -cleanup { unset -nocomplain stat vfs::unmount local } -result {type file size 1} test vfsZip-2.1 "nested mount" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipnest.zip local } -body { vfs::zip::Mount local/zipfs.zip nested vfs::unmount nested } -cleanup { vfs::unmount local } -result {} test vfsZip-2.2 "stat mountpoint" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipnest.zip local vfs::zip::Mount local/zipfs.zip nested unset -nocomplain stat set result "" } -body { file stat nested stat lappend result type $stat(type) size $stat(size) } -cleanup { unset -nocomplain stat vfs::unmount nested vfs::unmount local } -result {type directory size 0} test vfsZip-2.3 "stat nested file" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipnest.zip local vfs::zip::Mount local/zipfs.zip nested unset -nocomplain stat set result "" } -body { file stat nested/zipfs.test/One.txt stat lappend result type $stat(type) size [expr {$stat(size) > 0}] } -cleanup { unset -nocomplain stat vfs::unmount nested vfs::unmount local } -result {type file size 1} test vfsZip-2.4 "nested self-mount" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipnest.zip local } -body { vfs::zip::Mount local/zipfs.zip local/zipfs.zip set r [file isdirectory local/zipfs.zip] vfs::unmount local/zipfs.zip set r } -cleanup { vfs::unmount local } -result {1} test vfsZip-2.5 "nested cwd" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipnest.zip vfszip25 vfs::zip::Mount vfszip25/zipfs.zip vfszip25/zipfs.zip set cwd [pwd] } -body { cd vfszip25/zipfs.zip/zipfs.test/Aleph lsort [glob *] } -cleanup { cd $cwd vfs::unmount vfszip25/zipfs.zip vfs::unmount vfszip25 } -result {One.txt Two.txt} # NOTE: this test issues an error, it should probably be a nicer error though if # someone unmounts while using the vfs. At the moment the message is garbage. # test vfsZip-2.6 "nested cwd, umount in use" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipnest.zip vfszip26 set cwd [pwd] } -body { vfs::zip::Mount vfszip26/zipfs.zip vfszip26/zipfs.zip cd vfszip26/zipfs.zip/zipfs.test/Aleph vfs::unmount vfszip26/zipfs.zip pwd } -cleanup { cd $cwd vfs::unmount vfszip26/zipfs.zip vfs::unmount vfszip26 } -returnCodes {error} -match glob -result {*} test vfsZip-2.7 "nested mount mis-ordered unmounts" -constraints {zipfs zipexe} -setup { } -body { vfs::zip::Mount zipnest.zip vfszip27 vfs::zip::Mount vfszip27/zipfs.zip vfszip27/zipfs.zip set r [file isdirectory vfszip27/zipfs.zip] vfs::unmount vfszip27 vfs::unmount vfszip27/zipfs.zip set r } -cleanup { } -result {1} testConstraint bug1533748 [file exists [file join [testsDirectory] bug1533748.zip]] test vfsZip-3.0 "bug #: ./ prefixed filenames" -constraints {zipfs zipexe bug1533748} -setup { vfs::zip::Mount [file join [testsDirectory] bug1533748.zip] vfszip30 } -body { list [glob -nocomplain -directory vfszip30 -tails *] \ [glob -nocomplain -directory vfszip30/articles -tails *] \ } -cleanup { vfs::unmount vfszip30 } -result {articles c_5498.xml} test vfsZip-3.1 "bug #: ./ prefixed filenames" -constraints {zipfs zipexe bug1533748} -setup { vfs::zip::Mount [file join [testsDirectory] bug1533748.zip] vfszip31 } -body { set f [open vfszip31/articles/c_5498.xml r] fconfigure $f -translation binary set data [read $f] close $f expr {[string length $data] == [file size vfszip31/articles/c_5498.xml]} } -cleanup { vfs::unmount vfszip31 } -result {1} test vfsZip-4.0 "zip with preface code" -constraints {zipfs zipcat} -body { vfs::zip::Mount zipcat.zip local set r [glob -nocomplain -directory local -tails *] vfs::unmount local set r } -result {zipfs.test} test vfsZip-4.1 "zip with preface code" -constraints {zipfs zipcat} -setup { vfs::zip::Mount zipcat.zip local } -body { set f [open local/zipfs.test/Aleph/One.txt r] set r [string trim [read $f]] close $f set r } -cleanup { vfs::unmount local } -result {File aleph one} test vfsZip-9.0 "attempt to delete mounted file" -constraints {zipfs zipexe} -setup { vfs::zip::Mount zipfs.zip local } -body { file delete zipfs.zip } -cleanup { vfs::unmount local } -returnCodes {error} -result {error deleting "zipfs.zip": permission denied} # cleanup if {[testConstraint zipfs] && [testConstraint zipexe]} { file delete -force zipfs.test file delete -force zipglob.test file delete zipfs.zip file delete zipnest.zip file delete zipglob.zip } tcltest::cleanupTests return ./tclvfs/tests/vfsUrl.test0000644000175000017500000000514511136102212015350 0ustar sergeisergei# vfsZip.test -*- tcl -*- # # Commands covered: vfs::urltype::Mount and friends. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2001 by Vince Darley. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import ::tcltest::* } package require vfs::urltype puts stdout "These tests require an internet connection, and might" puts stdout "take a long time to complete." set vfsTestDir [pwd] if {![file writable $vfsTestDir]} { if {[info exists env(TEMP)] && [file writable $env(TEMP)]} { set vfsTestDir $env(TEMP) tcltest::testConstraint vfsWritable 1 puts stdout "Using temporary directory for some files\ (since [pwd] is not writable)" } else { tcltest::testConstraint vfsWritable 0 } } else { tcltest::testConstraint vfsWritable 1 } test vfsUrl-1.1 {mount} { vfs::urltype::Mount ftp } {Mounted at "ftp://"} test vfsUrl-1.2 {mount} { file exists ftp://ftp.tcl.tk } {1} test vfsUrl-1.3 {mounted volumes} { set idx [lsearch -exact [file volumes] ftp://] if {$idx < 0} { set res "No ftp:// volume!" } else { set res "New volume 'ftp://' mounted" } set res } {New volume 'ftp://' mounted} test vfsUrl-2.1 {auto-mount ftp and copy file} {vfsWritable} { file delete -force README.tclversions file copy ftp://ftp.tcl.tk/pub/tcl/README.tclversions $vfsTestDir set to [file join $vfsTestDir README.tclversions] if {[file exists $to]} { if {[file size $to] < 800} { set res "file too short" } else { set res "ok" } } else { set res "file doesn't exist" } file delete $to set res } {ok} test vfsUrl-2.2 {auto-mount bad ftp} { catch {file copy ftp://invalid.name.dom/pub/tcl/README.tclversions $vfsTestDir} set to [file join $vfsTestDir README.tclversions] if {[file exists $to]} { set res "file shouldn't exist!" file delete -force $to } else { set res "file doesn't exist" } set res } {file doesn't exist} test vfsUrl-3.1 {mount http} { vfs::urltype::Mount http } {Mounted at "http://"} # cleanup catch { # Unmount all successfully mounted volumes. foreach vol [file volumes] { if {[regexp {^([a-zA-Z]+):/?//$} $vol "" type]} { catch {vfs::urltype::Unmount $type} } } } ::tcltest::cleanupTests return ./tclvfs/tests/vfsTar.test0000644000175000017500000000457111136102212015336 0ustar sergeisergei# vfsTar.test -- -*- tcl -*- # # Commands covered: the 'tar' vfs. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2001-2003 by Vince Darley. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import ::tcltest::* } testConstraint tar [expr {![catch {package require vfs::tar}]}] test vfsTar-1.1 "mount empty tar archive" -constraints {tar} -setup { makeFile {} vfstar.tar } -body { vfs::tar::Mount vfstar.tar local vfs::unmount local } -cleanup { removeFile vfstar.tar } -result {} test vfsTar-1.2 "attempt to delete mounted file" -constraints {tar} -setup { makeFile {} vfstar.tar vfs::tar::Mount vfstar.tar local } -body { file delete vfstar.tar } -cleanup { vfs::unmount local removeFile vfstar.tar } -returnCodes error -result {error deleting "vfstar.tar": permission denied} test vfsTar-1.3 {mount with error} -constraints {tar knownBug} -setup { makeFile {} vfstar.tar set f [open vfstar.tar w] fconfigure $f -translation binary # Place a corrupt header in a fake tar archive puts $f {vfsTar.test01z0064400c0076400010x400000000a2355077d0503600101a4161 0ustar VinceDAdministrators# Commands covered: the 'tar' vfs. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. } close $f } -body { vfs::tar::Mount vfstar.tar local vfs::unmount local } -cleanup { removeFile vfstar.tar } -returnCodes {error} -result {} # cleanup ::tcltest::cleanupTests return ./tclvfs/tests/vfsFtp.test0000644000175000017500000000327011136102212015334 0ustar sergeisergei# vfsFtp.test -*- tcl -*- # # Commands covered: vfs::ftp::Mount and friends. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2001 by Vince Darley. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } testConstraint ftp [expr {![catch {package require vfs::ftp}]}] if {[testConstraint ftp]} { puts stdout "These tests require an internet connection, and might" puts stdout "take a long time to complete." } test vfsFtp-1.1 {mount and cd} -constraints {ftp} -setup { set cwd [pwd] } -body { vfs::ftp::Mount ftp://ftp.ucsd.edu/pub/alpha/ local cd local cd tcl set result [file tail [pwd]] vfs::unmount local set result } -cleanup { cd $pwd } -result {tcl} test vfsFtp-1.2 {mount and glob} -constraints {ftp} -setup { vfs::ftp::Mount ftp://ftp.ucsd.edu/pub/alpha/ local } -body { glob -nocomplain -directory local/tcl vfsTest.tcl } -cleanup { vfs::unmount local } -result {vfsTest.tcl} test vfsFtp-1.3 {mount and source} -constraints {ftp} -setup { vfs::ftp::Mount ftp://ftp.ucsd.edu/pub/alpha/ local } -body { set f [open local/tcl/vfsTest.tcl r] set data [read $f] close $f set data } -cleanup { vfs::unmount local } -result {This was returned from a remote file} # cleanup ::tcltest::cleanupTests return ./tclvfs/tests/vfsArchive.test0000644000175000017500000000755211136102212016173 0ustar sergeisergei# vfsArchive.test -*- tcl -*- # # Commands covered: running our tests from inside a 'zip' vfs. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2001-2002 by Vince Darley. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import ::tcltest::* } # ------------------------------------------------------------------------- # This file really buggers up the normal test suite run. # Comment this return if you really want to run this. # return # # ------------------------------------------------------------------------- tcltest::testConstraint nativefs \ [string equal [lindex [file system [info script]] 0] "native"] proc makeAndMountZipArchive {} { puts stdout "Zipping tests" ; update cd [file dirname [file dirname [file normalize [info script]]]] set filelist [concat [glob -dir [pwd] -join -tails tests *.test] \ [glob -dir [pwd] -join -tails tests *.tcl]] catch {file delete [file join tests tests.zip]} eval [list exec zip -q -9 [file join tests tests.zip]] $filelist puts stdout "Done zipping" cd [file dirname [info script]] package require vfs::zip set mount [vfs::zip::Mount tests.zip tests.zip] #puts "[pwd] ; $::auto_path, [glob *]" pwd cd tests.zip return [list vfs::zip::Unmount $mount tests.zip] } proc makeAndMountMk4Archive {} { puts stdout "Making mk4 archive of tests" ; update cd [file dirname [file dirname [file normalize [info script]]]] catch {file delete [file join tests tests.bin]} exec sdx fs2sd tests puts stdout "Done making mk4 archive" cd [file dirname [info script]] package require vfs::mk4 set mount [vfs::mk4::Mount tests.bin tests.bin] cd tests.bin return [list vfs::mk4::Unmount $mount tests.bin] } # This actually calls the test suite recursively, which probably # causes some problems, although it shouldn't really! test vfsArchive-1.0 {package require vfs} { if {![catch {package require vfs} res]} { set res "ok" } set res } {ok} # This actually calls the test suite recursively, which probably # causes some problems, although it shouldn't really! test vfsArchive-1.1 {run tests in zip archive} {nativefs} { # If this test fails, you probably don't have 'zip' installed. set testdir [pwd] package require vfs if {[catch {makeAndMountZipArchive} unmount]} { set res "Couldn't make and mount zip archive to test with: $unmount" puts $::errorInfo puts stderr $::auto_path } else { puts stdout "=== Running tests in zip archive ===" if {![catch { cd tests source all.tcl cd .. cd .. puts [pwd] eval $unmount } res]} { set res "ok" } puts stdout "=== End of embedded zip tests ===" } cd $testdir set res } {ok} # This actually calls the test suite recursively, which probably # causes some problems, although it shouldn't really! test vfsArchive-1.2 {run tests in mk4 archive} {nativefs} { # If this test fails, you probably don't have tclkit and 'sdx' # installed. That's not a big deal. set testdir [pwd] puts stderr $testdir package require vfs if {[catch {makeAndMountMk4Archive} unmount]} { set res "Couldn't make and mount mk4 archive to test with: $unmount" puts stderr $::auto_path } else { puts stdout "=== Running tests in mk4 archive ===" cd tests source all.tcl cd .. cd .. puts [pwd] eval $unmount set res "ok" puts stdout "=== End of embedded mk4 tests ===" } cd $testdir set res } {ok} # cleanup ::tcltest::cleanupTests return ./tclvfs/tests/vfs.test0000644000175000017500000001517411136114356014704 0ustar sergeisergei# Commands covered: vfs::filesystem # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2001-2002 by Vince Darley. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import ::tcltest::* } package require vfs proc filelistrelative {filelist {remove ""}} { if {[llength $remove]} { set newlist {} foreach f $filelist { if {[lsearch -exact $remove $f] == -1} { lappend newlist $f } } set filelist $newlist } set dir [file normalize [pwd]] set len [string length $dir] incr len set res {} foreach d $filelist { if {[string first $dir $d] == 0} { lappend res [string range $d $len end] } else { lappend res $d } } set res } test vfs-1.1 {mount unmount} { catch {unset res} vfs::filesystem mount foo bar set res [list [catch {vfs::filesystem unmount foo bar} err]] lappend res $err vfs::filesystem unmount foo unset err set res } {1 {wrong # args: should be "vfs::filesystem unmount path"}} # Test 2.x sub-interps test vfs-2.1 {mount unmount in sub interp} { catch {interp delete a} catch {unset res} set remove [vfs::filesystem info] vfs::filesystem mount foo bar vfsCreateInterp a a eval {package require vfs} a eval {vfs::filesystem mount foo2 bar2} set res {} eval lappend res [vfs::filesystem info] a eval {vfs::filesystem unmount foo2} interp delete a eval lappend res [vfs::filesystem info] vfs::filesystem unmount foo filelistrelative $res $remove } {foo2 foo foo} test vfs-2.2 {mount, delete sub interp} { catch {interp delete a} catch {unset res} set remove [vfs::filesystem info] vfs::filesystem mount foo bar vfsCreateInterp a a eval {package require vfs} a eval {vfs::filesystem mount foo2 bar2} set res {} eval lappend res [vfs::filesystem info] interp delete a eval lappend res [vfs::filesystem info] vfs::filesystem unmount foo filelistrelative $res $remove } {foo2 foo foo} test vfs-2.3 {mount where command doesn't exist} { # This is failing in 8.4.0-19, ok in 8.5, but changed message in 8.5.6 # and causes the 'error reading package index' in other tests for 8.4 vfs::filesystem mount foo bar set code [catch {glob foo/pkgIndex.tcl} msg] vfs::filesystem unmount foo list $code $msg } {1 {invalid command name "bar"}} test vfs-2.4 {mount where command doesn't exist} { # Building on vfs-2.3, but -nocomplain changed in 8.5 to still complain # on real underlying issues (just not on empty result) vfs::filesystem mount foo bar set code [catch {glob -nocomplain foo/pkgIndex.tcl} msg] vfs::filesystem unmount foo if {![package vsatisfies [package require Tcl] 8.5]} { if {$code == 0} { set code 1 ; set msg {invalid command name "bar"} } } list $code $msg } {1 {invalid command name "bar"}} test vfs-3.1 {vfs helpers: in memory channels} { close [::vfs::memchan] # If we get here, it's ok. If this test fails, # probably many other tests will fail too. In particular # any use of 'open', 'source', 'load', and usually also # 'file copy', 'file rename' in a vfs will fail. # # What this means is that tclvfs can't find some other # extension/code it requires -- you may need to install # the Memchan or Rchan extension for example. } {} test vfs-3.2 {vfs helpers: crc} { # If this test fails, probably many other tests will fail too (at # least anything to do with 'zip' vfs). # # What this means is that tclvfs can't find some other # extension/code it requires -- you may need to install # the Trf extension for example. format %08x [::vfs::crc abcd] } {ed82cd11} test vfs-3.3 {vfs helpers: zip} { # If this test fails, probably many other tests will fail too (at # least anything to do with 'zip' vfs). # # What this means is that tclvfs can't find some other # extension/code it requires -- you may need to install # the Try extension for example. ::vfs::zip -mode compress 1234567890 } "\x78\x9c\x33\x34\x32\x36\x31\x35\x33\xb7\xb0\x34\x0\x0\xb\x2c\x2\xe" test vfs-3.4 {vfs helpers: zip} { # If this test fails, probably many other tests will fail too (at # least anything to do with 'zip' vfs). # # What this means is that tclvfs can't find some other # extension/code it requires -- you may need to install # the Try extension for example. ::vfs::zip -mode decompress "\x78\x9c\x33\x34\x32\x36\x31\x35\x33\xb7\xb0\x34\x0\x0\xb\x2c\x2\xe" } {1234567890} test vfs-4.1 {vfs glob with .. [Bug 2378350]} -setup { package require vfs::ns 0.5.1 } -body { namespace eval ::test {} namespace eval ::test::bar {} namespace eval ::test::baz {} proc ::test::waz {args} { blah blah} proc ::test::bar::lol {args} { body body } proc ::test::baz::noz {args} { moo moo } vfs::ns::Mount :: nstest set res [list] lappend res [catch {lsort [glob nstest/test/*]} msg] $msg \ [catch {lsort [glob nstest/test/baz/*]} msg] $msg \ [catch {lsort [glob nstest/test/bar/../baz/*]} msg] $msg } -cleanup { catch {vfs::unmount nstest} catch {namespace delete ::test} } -result [list \ 0 {nstest/test/bar nstest/test/baz nstest/test/waz} \ 0 {nstest/test/baz/noz} \ 0 {nstest/test/bar/../baz/noz} \ ] test vfs-4.2 {Test MatchInDirectory fix} -setup { package require vfs::ns 0.5.1 } -body { namespace eval ::test {} namespace eval ::test::quux {} proc ::test::waz {args} { blah blah} vfs::ns::Mount :: nstest set res [list] lappend res \ [catch {lsort [glob nstest/test/*]} msg] $msg \ [catch {lsort [glob nstest/test/quux/*]} msg] $msg \ [catch {lsort [glob -nocomplain nstest/test/quux/*]} msg] $msg \ [catch {lsort [glob nstest/test/quux/nothingthere/*]} msg] $msg \ [catch {lsort [glob -nocomplain nstest/test/quux/nothingthere/*]} msg] $msg \ } -cleanup { catch {vfs::unmount nstest} catch {namespace delete ::test} } -result [list \ 0 {nstest/test/quux nstest/test/waz} \ 1 {no files matched glob pattern "nstest/test/quux/*"} \ 0 {} \ 1 {no files matched glob pattern "nstest/test/quux/nothingthere/*"} \ 0 {} \ ] # cleanup ::tcltest::cleanupTests return # Local variables: # mode: tcl # End:./tclvfs/tests/all.tcl0000644000175000017500000000376411115366375014472 0ustar sergeisergei# all.tcl -- # # This file contains a top-level script to run all of the Tcl # tests. Execute it by invoking "source all.test" when running tcltest # in this directory. # # Copyright (c) 1998-2000 by Scriptics Corporation. # All rights reserved. # # RCS: @(#) $Id: all.tcl,v 1.3 2008/12/03 02:20:45 hobbs Exp $ set tcltestVersion [package require tcltest] namespace import -force tcltest::* #tcltest::testsDirectory [file dir [info script]] #tcltest::runAllTests set ::tcltest::testSingleFile false set ::tcltest::testsDirectory [file dir [info script]] proc vfsCreateInterp {name} { # Use the same setup to access vfs as the master if {[catch { interp create $name $name eval [list set ::auto_path $::auto_path] $name eval {package require vfs} } err]} { puts "$err ; $::errorInfo" } } # We need to ensure that the testsDirectory is absolute ::tcltest::normalizePath ::tcltest::testsDirectory package require vfs 1.4 puts stdout "Tests running in interp: [info nameofexecutable]" puts stdout "Tests running in working dir: $::tcltest::testsDirectory" if {[llength $::tcltest::skip] > 0} { puts stdout "Skipping tests that match: $::tcltest::skip" } if {[llength $::tcltest::match] > 0} { puts stdout "Only running tests that match: $::tcltest::match" } if {[llength $::tcltest::skipFiles] > 0} { puts stdout "Skipping test files that match: $::tcltest::skipFiles" } if {[llength $::tcltest::matchFiles] > 0} { puts stdout "Only sourcing test files that match: $::tcltest::matchFiles" } tcltest::testConstraint fsIsWritable [expr {1 - [catch {file mkdir isreadonly ; file delete isreadonly}]}] set timeCmd {clock format [clock seconds]} puts stdout "Tests began at [eval $timeCmd]" # source each of the specified tests foreach file [lsort [::tcltest::getMatchingFiles]] { set tail [file tail $file] puts stdout $tail if {[catch {source $file} msg]} { puts stdout $msg } } # cleanup puts stdout "\nTests ended at [eval $timeCmd]" ::tcltest::cleanupTests 1 return ./tclvfs/tclconfig/0000755000175000017500000000000012703651745014014 5ustar sergeisergei./tclvfs/tclconfig/tcl.m40000644000175000017500000040054311115367522015037 0ustar sergeisergei# tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: tcl.m4,v 1.22 2008/12/03 02:30:42 hobbs Exp $ AC_PREREQ(2.57) dnl TEA extensions pass us the version of TEA they think they dnl are compatible with (must be set in TEA_INIT below) dnl TEA_VERSION="3.7" # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TCLCONFIG], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), with_tclconfig=${withval}) AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case ${with_tclconfig} in */tclConfig.sh ) if test -f ${with_tclconfig}; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig=`echo ${with_tclconfig} | sed 's!/tclConfig\.sh$!!'` fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/Tcl.framework; pwd)` break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions]) else no_tcl= TCL_BIN_DIR=${ac_cv_c_tclconfig} AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, AC_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), with_tkconfig=${withval}) AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case ${with_tkconfig} in */tkConfig.sh ) if test -f ${with_tkconfig}; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig=`echo ${with_tkconfig} | sed 's!/tkConfig\.sh$!!'` fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)` else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/Tk.framework; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i; pwd)` break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions]) else no_tk= TK_BIN_DIR=${ac_cv_c_tkconfig} AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Subst the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC} TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC} TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd ${TCL_BIN_DIR}; pwd`" \ "`cd ${TCL_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i"` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L${TCL_BIN_DIR} ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC=${TK_BUILD_LIB_SPEC} TK_STUB_LIB_SPEC=${TK_BUILD_STUB_LIB_SPEC} TK_STUB_LIB_PATH=${TK_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd ${TK_BIN_DIR}; pwd`" \ "`cd ${TK_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i"` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L${TK_BIN_DIR} ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AC_HELP_STRING([--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 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) fi AC_SUBST(SHARED_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], [build with threads]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; *) if test "${TCL_THREADS}" = "1"; then AC_MSG_WARN([ --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to $(CFLAGS_OPTIMIZE) if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Formerly used as debug library extension; # always blank now. # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AC_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) AC_SUBST(TCL_DBGX) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AC_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command, but there are a few systems, like Next, where # this doesn't work. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows elif test -f /usr/lib/NextStep/software_version; then tcl_cv_sys_version=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else # Special check for weird MP-RAS system (uname returns weird # results, and the version is kept in special file). if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then tcl_cv_sys_version=MP-RAS-`awk '{print $[3]}' /etc/.relid` fi if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS - Name of the object file that implements dynamic # loading for Tcl on this system. # DL_LIBS - Library file(s) to include in tclsh and other base # applications in order for the "load" command to work. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-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. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol is # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${VERSION}${SHLIB_SUFFIX}. # TCL_NEEDS_EXP_FILE - # 1 means that an export file is needed to link to a # shared library. # TCL_EXP_FILE - The name of the installed export / import file which # should be used to link to the Tcl shared library. # Empty if Tcl is unshared. # TCL_BUILD_EXP_FILE - # The name of the built export / import file which # should be used to link to the Tcl shared library. # Empty if Tcl is unshared. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_CFLAGS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AC_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AC_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_TRY_LINK([ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, tcl_cv_cc_visibility_hidden=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AC_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # TEA specific: Cross-compiling options for Windows/CE builds? AS_IF([test "${TEA_PLATFORM}" = windows], [ AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince, AC_HELP_STRING([--enable-wince], [enable Win/CE support (where applicable)]), [doWince=$enableval], [doWince=no]) AC_MSG_RESULT([$doWince]) ]) # Step 1: set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Step 2: check for existence of -ldl library. This is needed because # Linux can use either -ldl or -ldld for dynamic loading. AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no) # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Step 3: set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case. do64bit_ok=no LDFLAGS_ORIG="$LDFLAGS" # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" TCL_EXPORT_FILE_SUFFIX="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O AS_IF([test "$GCC" = yes], [ # TEA specific: CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall -Wno-implicit-int" ], [CFLAGS_WARNING=""]) TCL_NEEDS_EXP_FILE=0 TCL_BUILD_EXP_FILE="" TCL_EXP_FILE="" dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. dnl AC_CHECK_TOOL(AR, ar) AC_CHECK_PROG(AR, ar, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" case $system in # TEA specific: windows) # 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 # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" 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" ; # default to AMD64 64-bit build 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 to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) fi if test "$GCC" = "yes" ; then AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) fi TEA_PATH_CELIB # 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 WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` 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]]) doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. 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 "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) elif 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 CFLAGS="$CFLAGS -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 _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) done AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode RC="windres" CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD="$CC -shared" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots # Bogus to avoid getting this turned off DL_OBJS="tclLoadNone.obj" ;; AIX-*) AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r) # ok ... ;; *) CC=${CC}_r ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker on AIX 4+ AS_IF([test "$do64bit" = yes -a "`uname -v`" -gt 3], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported with GCC on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" # AIX-5 has dl* in libc.so DL_LIBS="" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' ], [ CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' ]) LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ], [ AS_IF([test "$GCC" = yes], [SHLIB_LD='${CC} -shared'], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" ]) SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix ${SHLIB_LD} ${SHLIB_LD_FLAGS}" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} TCL_NEEDS_EXP_FILE=1 # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_EXPORT_FILE_SUFFIX='${PACKAGE_VERSION}.exp' ]) # AIX v<=4.1 has some different flags than 4.2+ AS_IF([test "$system" = "AIX-4.1" -o "`uname -v`" -lt 4], [ AC_LIBOBJ([tclLoadAix]) DL_LIBS="-lld" ]) # On AIX <=v4 systems, libbsd.a has to be linked in to support # non-blocking file IO. This library has to be linked in after # the MATH_LIBS or it breaks the pow() function. The way to # insure proper sequencing, is to add it to the tail of MATH_LIBS. # This library also supplies gettimeofday. # # AIX does not have a timezone field in struct tm. When the AIX # bsd library is used, the timezone global and the gettimeofday # methods are to be avoided for timezone deduction instead, we # deduce the timezone by comparing the localtime result on a # known GMT value. AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no) AS_IF([test $libbsd = yes], [ MATH_LIBS="$MATH_LIBS -lbsd" AC_DEFINE(USE_DELTA_FOR_TZ, 1, [Do we need a special AIX hack for timezones?]) ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS='${LIBS}' DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS='${LIBS}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS='${LIBS}' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) SHLIB_SUFFIX=".sl" AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS="" DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) ;; IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings # when you inline the string and math operations. Turn this off to # get rid of the warnings. #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) ;; GNU*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared' DL_OBJS="" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' DL_OBJS="tclLoadDl.o" DL_LIBS="-mshared -ldl" LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) ;; MP-RAS-02*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; MP-RAS-*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,-Bexport" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; NetBSD-1.*|FreeBSD-[[1-2]].*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ AC_EGREP_CPP(yes, [ #ifdef __ELF__ yes #endif ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) AS_IF([test $tcl_cv_ld_elf = yes], [ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' ], [ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' ]) # Ancient FreeBSD doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; OpenBSD-*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ AC_EGREP_CPP(yes, [ #ifdef __ELF__ yes #endif ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) AS_IF([test $tcl_cv_ld_elf = yes], [ LDFLAGS=-Wl,-export-dynamic ], [LDFLAGS=""]) # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*|FreeBSD-*) # FreeBSD 3.* and greater have ELF. # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, tcl_cv_cc_arch_ppc64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, tcl_cv_cc_arch_x86_64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatiblity version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" # Don't use -prebind when building for Mac OS X 10.4 or later only: AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ LDFLAGS="$LDFLAGS -prebind"]) LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_TRY_LINK([#include ], [XrmInitialize();], tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua -o "$tcl_cv_lib_x11_64" = no], [ AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done]) ]) ;; NEXTSTEP-*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -nostdlib -r' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadNext.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-1.0|OSF1-1.1|OSF1-1.2) # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 SHLIB_CFLAGS="" # Hack: make package name same as library name SHLIB_LD='ld -R -export $@:' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadOSF.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-1.*) # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 SHLIB_CFLAGS="-fPIC" AS_IF([test "$SHARED_BUILD" = 1], [SHLIB_LD="ld -shared"], [ SHLIB_LD="ld -non_shared" ]) SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa AS_IF([test "${TCL_THREADS}" = 1], [ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" # dlopen is in -lc on QNX DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) # Note, dlopen is available only on SCO 3.2.5 and greater. However, # this test works, since "uname -s" was non-standard in 3.2.4 and # below. AS_IF([test "$GCC" = yes], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SINIX*5.4*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-4*) SHLIB_CFLAGS="-PIC" SHLIB_LD="ld" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} # SunOS can't handle version numbers with dots in them in library # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it # requires an extra version number at the end of .so file names. # So, the library has to have a name like libtcl75.so.1.0 SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ arch=`isainfo` AS_IF([test "$arch" = "sparcv9 sparc"], [ AS_IF([test "$GCC" = yes], [ AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" ]) ], [ do64bit_ok=yes AS_IF([test "$do64bitVIS" = yes], [ CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" ], [ CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" ]) # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" ]) ], [AS_IF([test "$arch" = "amd64 i386"], [ AS_IF([test "$GCC" = yes], [ case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac ], [ do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" ], [AS_IF([test "$arch" = "amd64 i386"], [ # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" ])]) ]) ], [ case $system in SunOS-5.[[1-9]][[0-9]]*) SHLIB_LD='${CC} -G -z text ${LDFLAGS}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ]) ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_Bexport = yes], [ LDFLAGS="$LDFLAGS -Wl,-Bexport" ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) ]) dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Step 4: disable dynamic loading if requested via a command-line switch. AC_ARG_ENABLE(load, AC_HELP_STRING([--enable-load], [allow dynamic loading and "load" command (default: on)]), [tcl_ok=$enableval], [tcl_ok=yes]) AS_IF([test "$tcl_ok" = no], [DL_OBJS=""]) AS_IF([test "x$DL_OBJS" != x], [BUILD_DLTEST="\$(DLTEST_TARGETS)"], [ AC_MSG_WARN([Can't figure out how to do dynamic loading or shared libraries on this system.]) SHLIB_CFLAGS="" SHLIB_LD="" SHLIB_SUFFIX="" DL_OBJS="tclLoadNone.o" DL_LIBS="" LDFLAGS="$LDFLAGS_ORIG" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" BUILD_DLTEST="" ]) LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$DL_OBJS" != "tclLoadNone.o" -a "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) AC_SUBST(DL_LIBS) AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY # #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod insome versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # # tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and # CHECK on limits.h #-------------------------------------------------------------------- AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ AC_TRY_LINK([#include #include ], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) fi # TEA specific: AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_HAVE_HEADERS(sys/param.h) ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) # #-------------------------------------------------------------------- AC_DEFUN([TEA_PATH_X], [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include ], , not_really_there="yes") else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test found_xincludes = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK # #-------------------------------------------------------------------- AC_DEFUN([TEA_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in # There used to be code here to use FIONBIO under AIX. However, it # was reported that FIONBIO doesn't work under AIX 3.2.5. Since # using O_NONBLOCK seems fine under AIX 4.*, I removed the FIONBIO # code (JO, 5/31/97). OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; SunOS-4*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANLDER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR # #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_TRY_COMPILE([#include ], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_TRY_COMPILE([#include ], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) # #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS # LIBS # MATH_LIBS # # Results: # # Subst's the following var: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], [struct stat64 buf; int i = stat64("/", &buf);]) TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include #include ],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include ],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include ],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.7" AC_MSG_CHECKING([for correct TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.in]) fi if test x"$1" = x ; then AC_MSG_ERROR([ TEA version not specified.]) elif test "$1" != "${TEA_VERSION}" ; then AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) else AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) fi case "`uname -s`" in *win32*|*WIN32*|*CYGWIN_NT*|*CYGWIN_9*|*CYGWIN_ME*|*MINGW32_*) AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) CYGPATH=echo EXEEXT="" TEA_PLATFORM="unix" ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_STUB_SOURCES], [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_TCL_SOURCES], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_HEADERS], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_INCLUDES], [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CFLAGS], [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN([TEA_PREFIX], [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.in files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_PROG_RANLIB #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER], [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS TEA_MISSING_POSIX_HEADERS # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(RANLIB_STUB) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN([TEA_LIB_SPEC], [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substs the following vars: # TCL_TOP_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substs the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CONFIG], [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Subst the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG], [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . "${$1_BIN_DIR}/$1Config.sh" else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f "${$1_BIN_DIR}/Makefile" ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) ]) #------------------------------------------------------------------------ # TEA_PATH_CELIB -- # # Locate Keuchel's celib emulation layer for targeting Win/CE # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-celib=... # # Defines the following vars: # CELIB_DIR Full path to the directory containing # the include and platform lib files #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CELIB], [ # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_CACHE_VAL(ac_cv_c_celibconfig,[ # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_celibconfig}" = x ; then AC_MSG_ERROR([Cannot find celib support library directory]) else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` AC_MSG_RESULT([found $CELIB_DIR]) fi fi ]) # Local Variables: # mode: autoconf # End: ./tclvfs/tclconfig/install-sh0000755000175000017500000000421207544466437016030 0ustar sergeisergei#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5; it is not part of GNU. # # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" instcmd="$mvprog" chmodcmd="" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; *) if [ x"$src" = x ] then src=$1 else dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` fi # Make a temp file name in the proper directory. dstdir=`dirname $dst` dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp # and set any options; do chmod last to preserve setuid bits if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi # Now rename the file to the real destination. $doit $rmcmd $dst $doit $mvcmd $dsttmp $dst exit 0 ./tclvfs/tclconfig/README.txt0000644000175000017500000000145307544466437015526 0ustar sergeisergeiThese files comprise the basic building blocks for a Tcl Extension Architecture (TEA) extension. For more information on TEA see: http://www.tcl.tk/doc/tea/ This package is part of the Tcl project at SourceForge, and latest sources should be available there: http://tcl.sourceforge.net/ This package is a freely available open source package. You can do virtually anything you like with it, such as modifying it, redistributing it, and selling it either in whole or in part. CONTENTS ======== The following is a short description of the files you will find in the sample extension. README.txt This file install-sh Program used for copying binaries and script files to their install locations. tcl.m4 Collection of Tcl autoconf macros. Included by a package's aclocal.m4 to define SC_* macros. ./tclvfs/library/0000755000175000017500000000000012703651745013510 5ustar sergeisergei./tclvfs/library/template/0000755000175000017500000000000012703651745015323 5ustar sergeisergei./tclvfs/library/template/versionvfs.tcl0000644000175000017500000005621411115367522020234 0ustar sergeisergeiif 0 { ######################## versionvfs.tcl -- Written by Stephen Huntley (stephen.huntley@alum.mit.edu) License: Tcl license Version 1.5.2 A versioning virtual filesystem. Requires the template vfs in templatevfs.tcl. Similar to historical versioning filesystems, each edited version of a file is saved separately; each version file is tagged with a timestamp, and optional project tags. A deleted file is represented by a new zero-length file with timestamp and a tag reading "deleted". By default only the latest version is visible. If the latest version is marked deleted, it is invisible. Directories are versioned and tagged in the same way as files. Older versions can be retrieved by setting the -project and -time values appropriately. Usage: mount ?-keep -project -time ? Options: -keep maximum number of previous versions of a file to keep per project. -project a list of one or more version-identifying tags. Any file created or edited in the virtual file space will be given these tags. File versions with a tag matching the ones given here will be visible in preference to other, possibly later versions without the tag. If a file version has project tags but none of them is included in this project tag list, it will be invisible; the file itself will then be invisible unless a file version exists without any project tags, in which case it will be treated as the default. In cases where several file versions each have multiple tags that match in the project list, the version with the greatest number of matches will be visible. Deleted files are marked with the tag "deleted". If this value is in the project name list, then deleted files will become visible again. Newly-created and deleted directories are tagged and shown/hidden in the same way as files. -time A timestamp in the form returned by [clock seconds], or a string understandable by [clock scan]. Versions of files as they existed at the given time will be visible, rather than the default latest version. Version choices based on project tags will still be made, but versions later than the timestamp will be ignored in the decision process. The values of each option can be changed dynamically after mount by using the "file attributes" command on the mount virtual directory. Each option is editable as an attribute; i.e., "file attributes C:/version -project {version2 release}". Display of visible files will change dynamically based on decisions with new attribute values. In addition, new attributes are defined which can be queried for individual files: The command "file attributes $file -version_filename" will show the exact filename of the currently visible version of the given file as it is stored in the vfs, complete with timestamp and project tags if any. The command "file attributes $file -versions" will return a list containing information on all stored versions of the given file. Each element of the list is itself a three-element list: 1) the unique millisecond-level timestamp of the version, 2) a human-readable date string showing the time represented by the timestamp (can be used a a value for the -time attribute), and 3) a list of the project tags attached to the version, if any. The versioning vfs inherits the -cache and -volume options of the template vfs. ######################## } package require vfs::template 1.5 package require fileutil::globfind package provide vfs::template::version 1.5.2 namespace eval ::vfs::template::version { # read template procedures into current namespace. Do not edit: foreach templateProc [namespace eval ::vfs::template {info procs}] { set infoArgs [info args ::vfs::template::$templateProc] set infoBody [info body ::vfs::template::$templateProc] proc $templateProc $infoArgs $infoBody } # edit following procedures: proc close_ {channelID} { upvar path path root root relative relative # get hash of file as it existed before edit: array set fileStats $::vfs::template::version::filestats($channelID) unset ::vfs::template::version::filestats($channelID) # if new hash shows file is unchanged, return immediately: fconfigure $channelID -translation binary set hash [Hash $channelID] if [string equal -nocase $hash $fileStats(hash)] {return} # create new unique filename for new version: set fileName [VFileNameEncode [file join $path $relative]]\;[VCreateTag $root] catch {array set oldAttributes [file attributes $fileStats(filename)]} # delete file version created by open_ if it's a new file: if [string equal $fileStats(hash) {}] { file delete -- $fileStats(filename) } # save new version: set f [open $fileName w] fconfigure $f -translation binary seek $channelID 0 fcopy $channelID $f close $f # ensure attributes are the same for new version: foreach {attr value} [file attributes $fileName] { if ![info exists oldAttributes($attr)] {continue} if {$oldAttributes($attr) != $value} {catch {file attributes $fileName $attr $oldAttributes($attr)}} } return } proc file_atime {file time} { upvar path path root root relative relative # check if current version is latest, if not disallow edit: set latest [lindex [lindex [lsort [VersionsAll $path $relative]] end] 0] set acquired [lindex [split [set fileName [VAcquireFile $path $root $relative]] \;] 1] if ![string first .&dir [file tail $fileName]] {::vfs::filesystem posixerror $::vfs::posix(ENOENT)} if {($acquired != {}) && ($latest != $acquired)} {::vfs::filesystem posixerror $::vfs::posix(EPERM)} file atime $fileName $time } proc file_mtime {file time} { upvar path path root root relative relative # check if current version is latest, if not disallow edit: set latest [lindex [lindex [lsort [VersionsAll $path $relative]] end] 0] set acquired [lindex [split [set fileName [VAcquireFile $path $root $relative]] \;] 1] if ![string first .&dir [file tail $fileName]] {::vfs::filesystem posixerror $::vfs::posix(ENOENT)} if {($acquired != {}) && ($latest != $acquired)} {::vfs::filesystem posixerror $::vfs::posix(EPERM)} file mtime $fileName $time } proc file_attributes {file {attribute {}} args} { upvar path path root root relative relative set latest [lindex [lindex [lsort [set allVersions [VersionsAll $path $relative]]] end] 0] set acquired [lindex [split [set fileName [VAcquireFile $path $root $relative]] \;] 1] if ![string first .&dir [file tail $fileName]] {::vfs::filesystem posixerror $::vfs::posix(ENOENT)} # process vfs-specific attributes: if {($relative == {}) && ([string map {-keep 1 -project 1 -time 1} $attribute] == 1)} { set attribute [string range $attribute 1 end] if {$args == {}} { if ![info exists ::vfs::template::version::${attribute}($root)] {return} eval return \$::vfs::template::version::${attribute}(\$root) } set ::vfs::template::version::${attribute}($root) [lindex $args 0] if {[lindex $args 0] == {}} {unset ::vfs::template::version::${attribute}($root)} return } # process read-only vfs-specific attributes: if {$attribute == "-versions"} { if {$args == {}} {return $allVersions} error "cannot set attribute \"-versions\" for file \"[file tail $relative]\": attribute is readonly" } if {$attribute == "-version_filename"} { if {$args == {}} {return [file tail $fileName]} error "cannot set attribute \"-version_filename\" for file \"[file tail $relative]\": attribute is readonly" } # check if current version is latest, if not disallow edit: if {($args != {}) && ($acquired != {}) && ($latest != $acquired)} {::vfs::filesystem posixerror $::vfs::posix(EPERM)} set returnValue [eval file attributes \$fileName $attribute $args] # collect values for vfs-specific attributes: if {$attribute == {}} { append returnValue " [list -versions $allVersions]" if {$file != $fileName} {append returnValue " [list -version_filename [file tail $fileName]]"} if {$relative != {}} {return $returnValue} foreach atr "keep project time" { set $atr "-$atr {}" if [info exists ::vfs::template::version::${atr}($root)] {eval set $atr \[list "-$atr" \$::vfs::template::version::${atr}(\$root)\]} } append returnValue " $keep $project $time" } return $returnValue } proc file_delete {file} { upvar path path root root relative relative set dir 0 # make sure subfiles of directory are deleted: if [file isdirectory $file] { set subfiles [globfind $file] set subfiles [lsort -decreasing $subfiles] set deleted {} foreach sf $subfiles { if [file isdirectory $sf] {continue} globdelete $sf } set dir 1 return } set fileName [VAcquireFile $path $root $relative] # allow straight deletion of new zero-length file: if {!$dir && ([llength [VersionsAll $path $relative]] == 1) && ![file size $fileName]} { file delete -force -- $fileName return } # for all others, create new file with "deleted" tag set file [VFileNameEncode $file] set fileName $file\;[VCreateTag $root] if $dir {set fileName [file join $file .&dir[file tail $file]]\;[VCreateTag $root]} set fileName [split $fileName \;] set fileName [linsert $fileName 2 "deleted"] set fileName [join $fileName \;] close [open $fileName w] if $dir {catch {file attributes $fileName -hidden 1}} } proc file_executable {file} { upvar path path root root relative relative set fileName [VAcquireFile $path $root $relative] if ![string first .&dir [file tail $fileName]] {return 0} file executable $fileName } proc file_exists {file} { upvar path path root root relative relative set fileName [VAcquireFile $path $root $relative] if ![string first .&dir [file tail $fileName]] {return 0} if [file isdirectory $fileName] {return 1} expr ![string equal [file join $path $relative] $fileName] } proc file_mkdir {file} { upvar root root file mkdir $file # create a file to store timestamps and tags for directory: set fileName [VFileNameEncode $file] set fileName [file join $fileName .&dir[file tail $fileName]]\;[VCreateTag $root] close [open $fileName w] catch {file attributes $fileName -hidden 1} return } proc file_readable {file} { upvar path path root root relative relative set fileName [VAcquireFile $path $root $relative] if ![string first .&dir [file tail $fileName]] {return 0} file readable $fileName } proc file_stat {file array} { upvar path path root root relative relative $array fs set fileName [VAcquireFile $path $root $relative] if ![string first .&dir [file tail $fileName]] {error "no such file or directory"} file stat $fileName fs if {$fs(type) == "directory"} { return } if {$fileName == [file join $path $relative]} {error "no such file or directory"} return } proc file_writable {file} { upvar path path root root relative relative set fileName [VAcquireFile $path $root $relative] if ![string first .&dir [file tail $fileName]] {return 0} file writable $fileName } proc glob_ {directory dir nocomplain tails types typeString dashes pattern} { upvar path path root root relative relative set globList [glob -directory $dir -nocomplain -types $typeString *] set newGlobList {} set acquireAttempts {} foreach gL $globList { if [file isdirectory $gL] { set acquiredFile [VAcquireFile $path $root [file join $relative [file tail $gL]]] if ![string equal $acquiredFile $gL] {continue} } else { if ![string first .&dir [file tail $gL]] {continue} set gL [VFileNameDecode $gL] if {[lsearch $acquireAttempts $gL] > -1} {continue} lappend acquireAttempts $gL set acquiredFile [VAcquireFile $path $root [file join $relative [file tail $gL]]] if [string equal $acquiredFile $gL] {continue} } if [string match $pattern [file tail $gL]] {lappend newGlobList [file tail $gL]} } return $newGlobList } proc open_ {file mode} { upvar path path root root relative relative set fileName [VAcquireFile $path $root $relative] if {$mode == "r"} {return [open $fileName r]} set hash {} # Use memchans so if file contents don't change we are free to delete file rather than commit to # creating new version which is identical to last. # If file is new, create new tag for it and return memchan: if {$fileName == [file join $path $relative]} { set fileName [VFileNameEncode [file join $path $relative]]\;[VCreateTag $root] close [open $fileName $mode] set channelID [memchan] set ::vfs::template::version::filestats($channelID) "filename [list $fileName] hash [list $hash]" return $channelID } # otherwise, get hash of existing file and store it where close callback can grab it, # then return memchan: set f [open $fileName r] fconfigure $f -translation binary set hash [Hash $f] close $f set filed [memchan] if {[string index $mode 0] == "a"} { set f [open $fileName r] fconfigure $f -translation binary fconfigure $filed -translation binary fcopy $f $filed close $f seek $filed 0 } set fileStats(hash) $hash set fileStats(filename) $fileName set ::vfs::template::version::filestats($filed) [array get fileStats] return $filed } proc MountProcedure {args} { upvar volume volume # take real and virtual directories from command line args. set to [lindex $args end] if [string equal $volume {}] {set to [::file normalize $to]} set path [::file normalize [lindex $args end-1]] # make sure mount location exists: ::file mkdir $path # add custom handling for new vfs args here. namespace import -force ::fileutil::globfind::globfind set argsLength [llength $args] for {set i 0} {$i < $argsLength} {incr i} { switch -- [lindex $args $i] { -keep { set keep [lindex $args [incr i]] if ![string is digit -strict $keep] {continue} set ::vfs::template::version::keep($to) $keep } -project { set project [lindex $args [incr i]] set ::vfs::template::version::project($to) $project } -time { set time [lindex $args [incr i]] SetTime $time set ::vfs::template::version::time($to) $time } } } if [catch {glob -directory $path -type {f hidden} .&dir*}] { set root $to file_mkdir $path } # return two-item list consisting of real and virtual locations. lappend pathto $path lappend pathto $to return $pathto } proc UnmountProcedure {path to} { # add custom unmount handling of new vfs elements here. if [info exists ::vfs::template::version::keep($to)] {unset ::vfs::template::version::keep($to)} if [info exists ::vfs::template::version::project($to)] {unset ::vfs::template::version::project($to)} if [info exists ::vfs::template::version::time($to)] {unset ::vfs::template::version::time($to)} return } # utility proc called by file_delete for recursive deletion of dir contents: proc globdelete {file} { upvar root root deleted deleted set file [file join [file dirname $file] [lindex [split [file tail $file] \;] 0]] if {[lsearch $deleted $file] > -1} {return} lappend deleted $file set fileName $file\;[VCreateTag $root] set fileName [split $fileName \;] set fileName [linsert $fileName 2 "deleted"] set fileName [join $fileName \;] close [open $fileName w] if ![string first {.&} [file tail $fileName]] {catch {file attributes $fileName -hidden 1}} } # Can replace this proc with one that uses different hash function if preferred. proc Hash {channel} { seek $channel 0 if [catch {package present md5 2}] {package forget md5 ; package require md5 2} ::md5::md5 -hex -- [read $channel] } # figure out if time is a string, milliseconds or seconds count, return seconds count proc SetTime {time} { if ![string is digit -strict $time] {catch {set time [clock scan $time]}} if ![string is digit -strict $time] {error "invalid time value."} set time "[string range $time 0 [expr [string length [clock seconds]] - 1]]000" } # decide which version is preferred considering time and project settings: proc VAcquireFile {path root relative {actualpath {}}} { set fileName [VFileNameEncode [file join $path $relative]] if [file isdirectory [file join $path $relative]] { set fileName [file join $fileName .&dir[file tail $fileName]] set relative [file join $relative .&dir[file tail $relative]] } # grab all versions: set versions [glob -path $fileName -nocomplain -types f "\;*"] if [catch {::vfs::filesystem info $path}] {append versions " [glob -path $fileName -nocomplain -types "f hidden" "\;*"]"} set versions [string trim $versions] if {$versions == {}} {return [file join $path $relative]} set checkProject 0 if [info exists ::vfs::template::version::project($root)] { set projects [string map {; &s} [string map {& &a} $::vfs::template::version::project($root)]] set checkProject 1 } # find versions that have current project tags to see if keep setting requires deleting any: foreach ver $versions { set ver $root/[file tail $ver] lappend versionFiles $ver if !$checkProject {continue} foreach project $projects { if {[lsearch [lrange [split $ver \;] 1 end] $project] > -1} {lappend projectFiles $ver} } } unset versions # delete older versions if keep setting requires it: if ![catch {if {[llength $projectFiles] <= $::vfs::template::version::keep($root)} {error}}] { set keep $::vfs::template::version::keep($root) set projectFiles [lsort -decreasing -dictionary $projectFiles] set fileNumber [llength $projectFiles] for {set i [incr fileNumber -1]} {$i >= 0} {incr i -1} { if {[llength $projectFiles] <= $keep} {break} set delFile [file join [file dirname [file join $path $relative]] [file tail [lindex $projectFiles $i]]] if ![catch {file delete -- $delFile}] {set projectFiles [lreplace $projectFiles $i $i]} } } # find version that's best match with time and project settings: set fileName [file tail [lindex [lsort -command VersionSort $versionFiles] 0]] # if file version has "deleted" tag, return with no version info, indicating file doesn't exist: if !$checkProject { if {[lindex [split $fileName \;] 2] == "deleted"} {return [file join $path $relative]} } # if project attribute is set, and version has project tags, ensure version belongs to one of the set projects, # otherwise it will be invisible: if $checkProject { if {([lindex [split $fileName \;] 2] == "deleted") && ([lsearch $projects "deleted"] == -1)} {return [file join $path $relative]} set projectMember 0 set tags [lrange [split $fileName \;] 1 end] if {[lindex $tags 1] == "deleted"} {set tags [lreplace $tags 1 1]} foreach project $projects { if {[lsearch $tags $project] > -1} {set projectMember 1} } set projectLength [llength $tags] if {($projectLength > 1) && !$projectMember} {return [file join $path $relative]} } # if time tag value is before creation date of chosen version, make file invisible: if {[info exists ::vfs::template::version::time($root)] && ([lindex [split $fileName \;] 1] > "$::vfs::template::version::time($root)000")} { return [file join $path $relative] } if ![string first .&dir [file tail $relative]] { set fileName [file join $path [file dirname $relative]] return [file normalize $fileName] } return [file join [file dirname [file join $path $relative]] $fileName] } # create new version tag with millisecond-scale timestamp and curernt project tags: proc VCreateTag {root} { set tag [clock seconds][string range [clock clicks -milliseconds] end-2 end] if [info exists ::vfs::template::version::project($root)] { set projects [string map {; &s} [string map {& &a} $::vfs::template::version::project($root)]] set projectTag [join $projects \;] set tag [join "$tag $projectTag" \;] } return $tag } # return info on all versions of a file: proc VersionsAll {path relative} { set fileName [VFileNameEncode [file join $path $relative]] if [file isdirectory [file join $path $relative]] { set fileName [file join $fileName .&dir[file tail $fileName]] set relative [file join $relative .&dir[file tail $relative]] } set versions [glob -path $fileName -nocomplain -types f "\;*"] if [catch {::vfs::filesystem info $path}] {append versions " [glob -path $fileName -nocomplain -types "f hidden" "\;*"]"} set versions [string trim $versions] set newVersions {} foreach ver $versions { set ver [lrange [split $ver \;] 1 end] set ver [file tail [VFileNameDecode $ver]] set tag [lindex $ver 0] set time [string range $tag 0 end-3] set time [clock format $time -format "%Y%m%dT%H:%M:%S"] lappend newVersions "$tag $time [list [lrange $ver 1 end]]" } return $newVersions } # specialized command for lsort, decide which of two versions is preferred given # project and time settings: proc VersionSort {element1 element2} { set root [file dirname $element1] set element1 [file tail $element1] set element2 [file tail $element2] if [string equal $element1 $element2] {return 0} set sorted [lsort -dictionary -decreasing "$element1 $element2"] # decision 1: choose latest timestamp: if {[lindex $sorted 0] == $element1} {set returnValue -1} if {[lindex $sorted 0] == $element2} {set returnValue 1} set time1 [lindex [split $element1 \;] 1] set time2 [lindex [split $element2 \;] 1] set time $time1 if {$time2 > $time1} {set time $time2} # decision 2: if time setting exists, choose latest timestamp less than time setting: if [info exists ::vfs::template::version::time($root)] { set returnValue -1 set time $::vfs::template::version::time($root) if {!([string is digit -strict $time] && ([string length $time] == [string length $time1]))} { set time [SetTime $::vfs::template::version::time($root)] } if {$time1 > $time} {set time1 [expr $time2 - 1]} if {($time2 <= $time) && ($time2 > $time1)} {set returnValue 1} } # decision 3: choose version with greatest number of project tag matches with project setting: if [info exists ::vfs::template::version::project($root)] { set projects [string map {; &s} [string map {& &a} $::vfs::template::version::project($root)]] set project1 0 set project2 0 foreach project [lsort -unique $projects] { set sumproject1 [lsearch [lrange [split $element1 \;] 1 end] $project] set sumproject2 [lsearch [lrange [split $element2 \;] 1 end] $project] incr sumproject1 ; incr sumproject2 if $sumproject1 {incr project1} if $sumproject2 {incr project2} } if {$project1 > $project2} {set project1 1 ; set project2 0} if {$project1 < $project2} {set project1 0 ; set project2 1} # don't count "deleted" as a project tag for purpose of choosing default: set tagEnd1 [lindex [split $element1 \;] 2] if {$tagEnd1 == "deleted"} {set tagEnd1 [lindex [split $element1 \;] 3]} set tagEnd2 [lindex [split $element2 \;] 2] if {$tagEnd2 == "deleted"} {set tagEnd2 [lindex [split $element2 \;] 3]} # set version with no project tags as default choice: if {($tagEnd1 == {}) && !($tagEnd2 == {})} {set returnValue -1} if {!($tagEnd1 == {}) && ($tagEnd2 == {})} {set returnValue 1} # if a project tag match exists, replace default choice with it: if {$project2 && !$project1 && ($time2 <= $time)} {set returnValue 1} if {$project1 && !$project2 && ($time1 <= $time)} {set returnValue -1} } return $returnValue } # ampersand and semicolon are privileged chars in tagging, # encode and decode filenames containing them: proc VFileNameEncode {filename} { set filename [file dirname $filename]/[string map {& &a} [file tail $filename]] set filename [file dirname $filename]/[string map {; &s} [file tail $filename]] } proc VFileNameDecode {filename} { set filename [file dirname $filename]/[lindex [split [file tail $filename] \;] 0] set filename [file dirname $filename]/[string map {&s ;} [file tail $filename]] set filename [file dirname $filename]/[string map {&a &} [file tail $filename]] } } # end namespace ::vfs::template::version ./tclvfs/library/template/templatevfs.tcl0000644000175000017500000004616112062175000020350 0ustar sergeisergei#/usr/bin/env tclsh if 0 { ######################## templatevfs.tcl -- Written by Stephen Huntley (stephen.huntley@alum.mit.edu) License: Tcl license Version 1.5.4 The template virtual filesystem is designed as a prototype on which to build new virtual filesystems. Only a few simple, abstract procedures have to be overridden to produce a new vfs, requiring no knowledge of the Tclvfs API. In addition, several behind-the-scenes functions are provided to make new vfs's more stable and scalable, including file information caching and management of close callback errors. The template vfs provides a useful function of its own, it mirrors a real directory to a virtual location, analogous to a Unix-style link. Usage: mount ?-cache ? ?-volume? Options: -cache Sets number of seconds file stat and attributes information will dwell in cache after being retrieved. Default is 2. Setting value of 0 will essentially disable caching. This value is viewable and editable after mount by calling "file attributes -cache ?value?" -volume Volume specified in virtual directory pathname will be mounted as a virtual volume. The above options are inherited by all virtual filesystems built using the template. Side effects: Files whose names begin with ".vfs_" will be ignored and thus invisible to the user unless the variable ::vfs::template::vfs_retrieve exists. Sourcing this file will run code that overloads the exit command with a procedure that ensures that all vfs's are explicitly unmounted before the shell terminates. When a vfs built on the template vfs is mounted, the mount command options are stored in an array named vfs::template::mount with the virtual mount point as the array index name. Thus a vfs can be re-mounted by executing "eval" on the contents of the array element whose index is the vfs's virtual mount point. ######################## } package require vfs 1.0 # force sourcing of vfsUtils.tcl: set vfs::posix(load) x vfs::posixError load unset vfs::posix(load) package provide vfs::template 1.5.5 namespace eval ::vfs::template { if 0 { ######################## In order to create a new virtual filesystem: 1. copy the contents of this namespace eval statement to a new namespace eval statement with a unique new namespace defined 2. rewrite the copied procedures to retrieve and handle virtual filesystem information as desired and return it in the same format as the given native file commands. ######################## } package require vfs::template 1.5 # read template procedures into current namespace. Do not edit: foreach templateProc [namespace eval ::vfs::template {info procs}] { set infoArgs [info args ::vfs::template::$templateProc] set infoBody [info body ::vfs::template::$templateProc] proc $templateProc $infoArgs $infoBody } # edit following procedures: # Do not close channel within this procedure (will cause error). Simply # read info from channel as needed and return. proc close_ {channel} {return} # Variable $time is always defined. These procs only set time values. proc file_atime {file time} {file atime $file $time} proc file_mtime {file time} {file mtime $file $time} # Variables $attribute and $args may or may not be empty. # If $attribute is empty so is $args (retrieve all attributes and values). # If $args only is empty, retrieve value of specified attribute. # If $args has a value, set it as value of specified attribute. proc file_attributes {file {attribute {}} args} {eval file attributes \$file $attribute $args} # Variable $file may be a file or directory. # This proc only called if it is certain that deletion is the correct action. proc file_delete {file} {file delete -force -- $file} proc file_executable {file} {file executable $file} proc file_exists {file} {file exists $file} proc file_mkdir {file} {file mkdir $file} proc file_readable {file} {file readable $file} proc file_stat {file array} {upvar $array fs ; file stat $file fs} proc file_writable {file} {file writable $file} # All variables are always defined. # Return list of filenames only, not full pathnames. proc glob_ {directory dir nocomplain tails types typeString dashes pattern} {glob -directory $dir -nocomplain -tails -types $typeString -- $pattern} proc open_ {file mode} {open $file $mode} # MountProcedure is called once each time a vfs is newly mounted. proc MountProcedure {args} { upvar volume volume # take real and virtual directories from command line args. set to [lindex $args end] if [string equal $volume {}] {set to [::file normalize $to]} set path [::file normalize [lindex $args end-1]] # make sure mount location exists: ::file mkdir $path # add custom handling for new vfs args here. # return two-item list consisting of real and virtual locations. lappend pathto $path lappend pathto $to return $pathto } proc UnmountProcedure {path to} { # add custom unmount handling of new vfs elements here. return } } # end namespace ::vfs::template # Below are template API procedures; there should be no need to edit them. namespace eval ::vfs::template { proc mount {args} { # handle template command line args: set volume [lindex $args [lsearch $args "-volume"]] set cache 2 if {[set cacheIndex [lsearch $args "-cache"]] != -1} {set cache [lindex $args [incr cacheIndex]]} set args [string map "\" -volume \" { } \" -cache $cache \" { }" " $args "] # run unmount procedure if mount exists: set to [lindex $args end] if [info exists ::vfs::_unmountCmd($to)] {$::vfs::_unmountCmd($to) $to} # call custom mount procedure: # ensure files named ".vfs_*" can be opened set ::vfs::template::vfs_retrieve 1 set pathto [eval MountProcedure $args] # re-hide ".vfs_*" files unset -nocomplain ::vfs::template::vfs_retrieve set path [lindex $pathto 0] set to [lindex $pathto 1] if [string equal $volume {}] {set to [file normalize $to]} # preserve mount info for later duplication if desired: set ::vfs::template::mount($to) "[namespace current]::mount $volume -cache $cache $args" # if virtual location still mounted, unmount it by force: if {[lsearch [::vfs::filesystem info] $to] != -1} {::vfs::filesystem unmount $to} array unset ::vfs::_unmountCmd $to # set file info cache dwell time value: set [namespace current]::cache($to) $cache # register location with Tclvfs package: set div {} if {$volume ne {}} { if {[string index $to end] ne "/"} { set div / } } eval ::vfs::filesystem mount $volume \$to$div \[list [namespace current]::handler \$path\] ::vfs::RegisterMount $to [list [namespace current]::unmount] # ensure close callback background error appears at script execution level: trace remove execution ::close leave ::vfs::template::CloseTrace trace remove execution ::file leave ::vfs::template::FileTrace trace add execution ::close leave vfs::template::CloseTrace trace add execution ::file leave vfs::template::FileTrace return $to } # undo Tclvfs API hooks: proc unmount {to} { if {[lsearch [::vfs::filesystem info] $to] < 0} { set to [::file normalize $to] } set path [lindex [::vfs::filesystem info $to] end] # call custom unmount procedure: set ::vfs::template::vfs_retrieve 1 UnmountProcedure $path $to unset -nocomplain ::vfs::template::vfs_retrieve ::vfs::filesystem unmount $to array unset ::vfs::_unmountCmd [::file normalize $to] # clear file info caches: CacheClear $to } # vfshandler command required by Tclvfs API: proc handler {path cmd root relative actualpath args} { # puts [list $path $root $relative $cmd $args [namespace current]] set fileName [::file join $path $relative] set virtualName [::file join $root $relative] switch -- $cmd { access { set mode [lindex $args 0] set error [catch {Access $path $root $relative $actualpath $mode}] if $error {::vfs::filesystem posixerror $::vfs::posix(EACCES) ; return -code error $::vfs::posix(EACCES)} } createdirectory { CreateDirectory $path $root $relative $actualpath CacheClear $virtualName } deletefile { DeleteFile $path $root $relative $actualpath CacheClear $virtualName } fileattributes { set index [lindex $args 0] if {[llength $args] > 1} {set value [lindex $args 1]} set extra {} if [string equal $relative {}] {eval set extra \"-cache \$[namespace current]::cache(\$root)\"} # try to get values from cache first: array set attributes [CacheGet [namespace current]::attributes $virtualName [set [namespace current]::cache($root)]] # if not in cache, get them from file: if [string equal [array get attributes] {}] { array set attributes "[FileAttributes $path $root $relative $actualpath] $extra" CacheSet [namespace current]::attributes $virtualName [array get attributes] } set attribute [lindex [lsort [array names attributes]] $index] # if value given in args, set it and return: if [info exists value] { if [string equal $attribute "-cache"] { set [namespace current]::cache($root) $value } else { FileAttributesSet $path $root $relative $actualpath $attribute $value } CacheClear $virtualName return } # if attribute given in args, return its value: if ![string equal $index {}] { return $attributes($attribute) } # otherwise, just return all attribute names return [lsort [array names attributes]] } matchindirectory { set pattern [lindex $args 0] set types [lindex $args 1] return [MatchInDirectory $path $root $relative $actualpath $pattern $types] } open { # ensure files named ".vfs_*" can't be opened ordinarily: if {![string first ".vfs_" [file tail $relative]] && ![info exists ::vfs::template::vfs_retrieve]} {vfs::filesystem posixerror $::vfs::posix(EACCES)} set mode [lindex $args 0] if {$mode == {}} {set mode r} # workaround: Tclvfs can't handle channels in write-only modes; see Tclvfs bug #1004273 if {$mode == "w"} {set mode w+} if {$mode == "a"} {set mode a+} set permissions [lindex $args 1] set channelID [Open $path $root $relative $actualpath $mode $permissions] # ensure channel settings match file command defaults set eofChar {{} {}} if [string equal $::tcl_platform(platform) "windows"] {set eofChar "\x1a {}"} fconfigure $channelID -encoding [encoding system] -eofchar $eofChar -translation auto switch -glob -- $mode { "" - "r*" - "w*" { seek $channelID 0 } "a*" { seek $channelID 0 end } default { ::vfs::filesystem posixerror $::vfs::posix(EINVAL) return -code error $::vfs::posix(EINVAL) } } set result $channelID # designate handler as close callback command lappend result [list [namespace current]::handler $path close $root $relative $actualpath $channelID $mode] # make sure all interpreters can catch errors in close callback: foreach int [interp slaves] { InterpSeed $int } CacheClear $virtualName return $result } close { set channelID [lindex $args 0] set mode [lindex $args 1] if [string equal $mode "r"] {return} # never use real close command here, custom overloaded proc only. set err [catch {close_ $channelID} result] if $err {::vfs::template::closeerror $::errorInfo ; error $::errorInfo} return } removedirectory { set recursive [lindex $args 0] if !$recursive { if {[MatchInDirectory $path $root $relative $actualpath * 0] != {}} { ::vfs::filesystem posixerror $::vfs::posix(EEXIST) return -code error $::vfs::posix(EEXIST) } } if {$relative == {}} {unmount $root ; return} RemoveDirectory $path $root $relative $actualpath CacheClear $virtualName } stat { set stat [CacheGet [namespace current]::stat $virtualName [set [namespace current]::cache($root)]] if ![string equal $stat ""] { return $stat } set stat [Stat $path $root $relative $actualpath] CacheSet [namespace current]::stat $virtualName $stat return $stat } utime { set atime [lindex $args 0] set mtime [lindex $args 1] Utime $path $root $relative $actualpath $atime $mtime array unset [namespace current]::stat $virtualName,time ; array unset [namespace current]::stat $virtualName,value } } } # following commands carry out information processing requirements for each vfshandler subcommand: # note that all calls to file commands are redirected to simplified API procs at top of this script proc Access {path root relative actualpath mode} { set fileName [::file join $path $relative] set virtualName [::file join $root $relative] set modeString [::vfs::accessMode $mode] set modeString [split $modeString {}] set modeString [string map "F exists R readable W writable X executable" $modeString] set secs [clock seconds] foreach mode $modeString { set result [CacheGet [namespace current]::$mode $virtualName [set [namespace current]::cache($root)] $secs] if [string equal $result ""] { set result [eval file_$mode \$fileName] CacheSet [namespace current]::$mode $virtualName $result $secs } if !$result {error error} } return } proc CreateDirectory {path root relative actualpath} { file_mkdir [::file join $path $relative] } proc DeleteFile {path root relative actualpath} { set fileName [::file join $path $relative] # file delete -force -- $fileName file_delete $fileName } proc FileAttributes {path root relative actualpath} { set fileName [::file join $path $relative] return [file_attributes $fileName] } proc FileAttributesSet {path root relative actualpath attribute value} { set fileName [::file join $path $relative] file_attributes $fileName $attribute $value } proc MatchInDirectory {path root relative actualpath pattern types} { # special case: check for existence (see Tclvfs bug #1405317) if [string equal $pattern {}] { if ![::vfs::matchDirectories $types] {return {}} return [::file join $root $relative] } # convert types bitstring back to human-readable alpha string: foreach {type shift} {b 0 c 1 d 2 p 3 f 4 l 5 s 6} { if [expr {$types == 0 ? 1 : $types & (1<<$shift)}] {lappend typeString $type} } set pathName [::file join $path $relative] # get non-hidden files: set globList [glob_ -directory $pathName -nocomplain -tails -types $typeString -- $pattern] # if underlying location is not itself a vfs, get hidden files (Tclvfs doesn't pass "hidden" type to handler) if [catch {::vfs::filesystem info $path}] {set globList [concat $globList [glob_ -directory $pathName -nocomplain -tails -types "$typeString hidden" -- $pattern]]} # convert real path to virtual path: set newGlobList {} foreach gL $globList { if {![string first ".vfs_" $gL] && ![info exists ::vfs::template::vfs_retrieve]} {continue} set gL [::file join $root $relative $gL] lappend newGlobList $gL } set newGlobList [lsort -unique $newGlobList] return $newGlobList } proc Open {path root relative actualpath mode permissions} { set fileName [::file join $path $relative] set newFile 0 if ![file exists $fileName] {set newFile 1} set channelID [open_ $fileName $mode] if $newFile {catch {file_attributes $fileName -permissions $permissions}} return $channelID } proc RemoveDirectory {path root relative actualpath} { set fileName [::file join $path $relative] # file delete -force -- $fileName file_delete $fileName } proc Stat {path root relative actualpath} { file_stat [::file join $path $relative] fs return [array get fs] } proc Utime {path root relative actualpath atime mtime} { set fileName [::file join $path $relative] file_atime $fileName $atime file_mtime $fileName $mtime } # check value of ::errorInfo to ensure close callback didn't generate background # error; if it did, force error break. proc CloseTrace {commandString code result op} { if {[info exists ::vfs::template::vfs_error] && ($::vfs::template::vfs_error != {})} { set vfs_error $::vfs::template::vfs_error closeerror {} error $vfs_error } return } # file copy and file rename may trigger close callbacks internally, so check for close errors # after these commands complete. proc FileTrace {commandString code result op} { if {[string map {copy {} rename {}} [lindex $commandString 1]] != {}} {return} if {[info exists ::vfs::template::vfs_error] && ($::vfs::template::vfs_error != {})} { set vfs_error $::vfs::template::vfs_error closeerror {} error $vfs_error } return } # ensure ::errorInfo from background errors makes it into every child interpreter # so CloseTrace and FileTrace can intercept it. proc closeerror {errorInfo} { set ::vfs::template::vfs_error $errorInfo foreach int [interp slaves] { InterpSeed $int set ::vfs::template::vfs_error $::vfs::template::vfs_error } } # seed all interpreters with trace structures necessary to intercept close callback errors: proc InterpSeed {interp args} { interp eval $interp {namespace eval ::vfs::template {}} $interp alias ::vfs::template::closeerror ::vfs::template::closeerror $interp alias ::vfs::template::FileTrace ::vfs::template::FileTrace $interp alias ::vfs::template::CloseTrace ::vfs::template::CloseTrace interp eval $interp trace remove execution ::file leave ::vfs::template::FileTrace interp eval $interp trace remove execution ::close leave ::vfs::template::CloseTrace interp eval $interp trace add execution ::close leave ::vfs::template::CloseTrace interp eval $interp trace add execution ::file leave ::vfs::template::FileTrace interp eval $interp $args foreach int [interp slaves $interp] { InterpSeed $int $args } } # cache management functions: proc CacheClear {file} { foreach arr {exists readable writable executable stat attributes} { array unset [namespace current]::$arr $file,time array unset [namespace current]::$arr $file,value array unset [namespace current]::$arr $file/* } } proc CacheGet {array file cache args} { if [string equal [array names $array $file,time] {}] {return} if ![string equal $args {}] {set secs $args} else {set secs [clock seconds]} set fileTime [lindex [array get $array $file,time] 1] if {[expr $secs - $fileTime] < $cache} {return [lindex [array get $array $file,value] 1]} array unset $array $file,time ; array unset $array $file,value return } proc CacheSet {array file value args} { if ![string equal $args {}] {set secs $args} else {set secs [clock seconds]} set fileTime $file,time array set $array [list $fileTime $secs] set fileValue $file,value array set $array [list $fileValue $value] } # map built-in file selection dialogs to pure Tk equivalents, so virtual # filesystems can be browsed with same-looking code: proc tk_getOpenFile {args} { eval [eval list ::tk::dialog::file:: open $args] } proc tk_getSaveFile {args} { eval [eval list ::tk::dialog::file:: save $args] } proc tk_chooseDirectory {args} { eval [eval list ::tk::dialog::file::chooseDir:: $args] } # workaround for bug in tclkit: proc memchan {args} { if {$::tcl_platform(platform) == "windows"} { package require Memchan set chan [uplevel 1 ::memchan $args] return $chan } else { return [eval [linsert $args 0 ::vfs::memchan]] } } } # end namespace eval ::vfs::template # overload exit command so that all vfs's are explicitly # unmounted before program termination: catch {rename ::exit ::vfs::template::exit} proc ::exit {args} { foreach vfs [::vfs::filesystem info] { if [catch {$::vfs::_unmountCmd([file normalize $vfs]) $vfs} result] { puts "$vfs: $result" } } if {![llength $args]} { lappend args 0} ::vfs::template::exit [lindex $args 0] } ./tclvfs/library/template/tdelta.tcl0000644000175000017500000003575010521311435017277 0ustar sergeisergei# tdelta.tcl -- # # Produce an rdiff-style delta signature of one file with respect to another, # and re-create one file by applying the delta to the other. # # Written by Stephen Huntley (stephen.huntley@alum.mit.edu) # License: Tcl license # Version 1.0 # # Usage: # # tdelta [sizecheck [fingerprint]] # Returns a delta of the target file with respect to the reference file. # i.e., using patch to apply the delta to the target file will re-create the reference file. # # sizecheck and fingerprint are booleans which enable time-saving checks: # # if sizecheck is True then if the file size is # less than five times the block size, then no delta calculation is done and the # signature contains the full reference file contents. # # if fingerprint is True then 10 small strings ("fingerprints") are taken from the target # file and searched for in the reference file. If at least three aren't found, then # no delta calculation is done and the signature contains the full reference file contents. # # tpatch # Reconstitute original reference file by applying delta to target file. # # # global variables: # # blockSize # Size of file segments to compare. # Smaller blockSize tends to create smaller delta. # Larger blockSize tends to take more time to compute delta. # md5Size # Substring of md5 checksum to store in delta signature. # If security is less of a concern, set md5Size to a number # between 1-32 to create a more compact signature. package provide trsync 1.0 namespace eval ::trsync { if ![info exists blockSize] {variable blockSize 100} if ![info exists Mod] {variable Mod [expr pow(2,16)]} if ![info exists md5Size] {variable md5Size 32} variable temp if ![info exists temp] { catch {set temp $::env(TMP)} catch {set temp $::env(TEMP)} catch {set temp $::env(TRSYNC_TEMP)} if [catch {file mkdir $temp}] {set temp [pwd]} } if ![file writable $temp] {error "temp location not writable"} proc Backup {args} { return } proc ConstructFile {copyinstructions {eolNative 0} {backup {}}} { if [catch {package present md5 2}] {package forget md5 ; package require md5 2} set fileToConstruct [lindex $copyinstructions 0] set existingFile [lindex $copyinstructions 1] set blockSize [lindex $copyinstructions 2] array set fileStats [lindex $copyinstructions 3] array set digestInstructionArray [DigestInstructionsExpand [lindex $copyinstructions 4] $blockSize] array set dataInstructionArray [lindex $copyinstructions 5] unset copyinstructions if {[lsearch [file channels] $existingFile] == -1} { set existingFile [FileNameNormalize $existingFile] if {$fileToConstruct == {}} {file delete -force $existingFile ; return} catch { set existingID [open $existingFile r] fconfigure $existingID -translation binary } } else { set existingID $existingFile fconfigure $existingID -translation binary } set temp $::trsync::temp if {[lsearch [file channels] $fileToConstruct] == -1} { set fileToConstruct [FileNameNormalize $fileToConstruct] set constructTag "trsync.[md5::md5 -hex "[clock seconds] [clock clicks]"]" set constructID [open $temp/$constructTag w] } else { set constructID $fileToConstruct } fconfigure $constructID -translation binary if $eolNative {set eolNative [string is ascii -strict [array get dataInstructionArray]]} set filePointer 1 while {$filePointer <= $fileStats(size)} { if {[array names dataInstructionArray $filePointer] != {}} { puts -nonewline $constructID $dataInstructionArray($filePointer) set segmentLength [string length $dataInstructionArray($filePointer)] array unset dataInstructionArray $filePointer set filePointer [expr $filePointer + $segmentLength] } elseif {[array names digestInstructionArray $filePointer] != {}} { if ![info exists existingID] {error "Corrupt copy instructions."} set blockNumber [lindex $digestInstructionArray($filePointer) 0] set blockMd5Sum [lindex $digestInstructionArray($filePointer) 1] seek $existingID [expr $blockNumber * $blockSize] set existingBlock [read $existingID $blockSize] set existingBlockMd5Sum [string range [md5::md5 -hex -- $existingBlock] 0 [expr [string length $blockMd5Sum] - 1]] if ![string equal -nocase $blockMd5Sum $existingBlockMd5Sum] {error "digest file contents mismatch"} puts -nonewline $constructID $existingBlock if $eolNative {set eolNative [string is ascii -strict $existingBlock]} unset existingBlock set filePointer [expr $filePointer + $blockSize] } else { error "Corrupt copy instructions." } } catch {close $existingID} set fileStats(eolNative) $eolNative if {[lsearch [file channels] $fileToConstruct] > -1} {return [array get fileStats]} close $constructID if $eolNative { fcopy [set fin [open $temp/$constructTag r]] [set fout [open $temp/${constructTag}fcopy w]] close $fin close $fout file delete -force $temp/$constructTag set constructTag "${constructTag}fcopy" } catch {file attributes $temp/$constructTag -readonly 0} result catch {file attributes $temp/$constructTag -permissions rw-rw-rw-} result catch {file attributes $temp/$constructTag -owner $fileStats(uid)} result catch {file attributes $temp/$constructTag -group $fileStats(gid)} result catch {file mtime $temp/$constructTag $fileStats(mtime)} result catch {file atime $temp/$constructTag $fileStats(atime)} result if [string equal $fileToConstruct $existingFile] { catch {file attributes $existingFile -readonly 0} result catch {file attributes $existingFile -permissions rw-rw-rw-} result } Backup $backup $fileToConstruct file mkdir [file dirname $fileToConstruct] file rename -force $temp/$constructTag $fileToConstruct array set attributes $fileStats(attributes) array set attrConstruct [file attributes $fileToConstruct] foreach attr [array names attributes] { if [string equal [array get attributes $attr] [array get attrConstruct $attr]] {continue} if {[string equal $attr "-longname"] || [string equal $attr "-shortname"] || [string equal $attr "-permissions"]} {continue} catch {file attributes $fileToConstruct $attr $attributes($attr)} result } catch {file attributes $fileToConstruct -permissions $fileStats(mode)} result return } proc CopyInstructions {filename digest} { if [catch {package present md5 2}] {package forget md5 ; package require md5 2} if {[lsearch [file channels] $filename] == -1} { set filename [FileNameNormalize $filename] file stat $filename fileStats array set fileAttributes [file attributes $filename] array unset fileAttributes -longname array unset fileAttributes -shortname set arrayadd attributes ; lappend arrayadd [array get fileAttributes] ; array set fileStats $arrayadd set f [open $filename r] } else { set f $filename set fileStats(attributes) {} } fconfigure $f -translation binary seek $f 0 end set fileSize [tell $f] seek $f 0 set fileStats(size) $fileSize set digestFileName [lindex $digest 0] set blockSize [lindex $digest 1] set digest [lrange $digest 2 end] if {[lsearch -exact $digest fingerprints] > -1} { set fingerPrints [lindex $digest end] set digest [lrange $digest 0 end-2] set fileContents [read $f] set matchCount 0 foreach fP $fingerPrints { if {[string first $fP $fileContents] > -1} {incr matchCount} if {$matchCount > 3} {break} } unset fileContents seek $f 0 if {$matchCount < 3} {set digest {}} } set digestLength [llength $digest] for {set i 0} {$i < $digestLength} {incr i} { set arrayadd [lindex [lindex $digest $i] 1] lappend arrayadd $i array set Checksums $arrayadd } set digestInstructions {} set dataInstructions {} set weakChecksum {} set startBlockPointer 0 set endBlockPointer 0 if ![array exists Checksums] { set dataInstructions 1 lappend dataInstructions [read $f] set endBlockPointer $fileSize } while {$endBlockPointer < $fileSize} { set endBlockPointer [expr $startBlockPointer + $blockSize] incr startBlockPointer if {$weakChecksum == {}} { set blockContents [read $f $blockSize] set blockNumberSequence [SequenceBlock $blockContents] set weakChecksumInfo [WeakChecksum $blockNumberSequence] set weakChecksum [format %.0f [lindex $weakChecksumInfo 0]] set startDataPointer $startBlockPointer set endDataPointer $startDataPointer set dataBuffer {} } if {[array names Checksums $weakChecksum] != {}} { set md5Sum [md5::md5 -hex -- $blockContents] set blockIndex $Checksums($weakChecksum) set digestmd5Sum [lindex [lindex $digest $blockIndex] 0] if [string equal -nocase $digestmd5Sum $md5Sum] { if {$endDataPointer > $startDataPointer} { lappend dataInstructions $startDataPointer lappend dataInstructions $dataBuffer } lappend digestInstructions $startBlockPointer lappend digestInstructions "$blockIndex [string range $md5Sum 0 [expr $::trsync::md5Size - 1]]" set weakChecksum {} set startBlockPointer $endBlockPointer continue } } if {$endBlockPointer >= $fileSize} { lappend dataInstructions $startDataPointer lappend dataInstructions $dataBuffer$blockContents break } set rollChar [read $f 1] binary scan $rollChar c* rollNumber set rollNumber [expr ($rollNumber + 0x100)%0x100] lappend blockNumberSequence $rollNumber set blockNumberSequence [lrange $blockNumberSequence 1 end] binary scan $blockContents a1a* rollOffChar blockContents set blockContents $blockContents$rollChar set dataBuffer $dataBuffer$rollOffChar incr endDataPointer set weakChecksumInfo "[eval RollChecksum [lrange $weakChecksumInfo 1 5] $rollNumber] [lindex $blockNumberSequence 0]" set weakChecksum [format %.0f [lindex $weakChecksumInfo 0]] } close $f lappend copyInstructions $filename lappend copyInstructions $digestFileName lappend copyInstructions $blockSize lappend copyInstructions [array get fileStats] lappend copyInstructions [DigestInstructionsCompress $digestInstructions $blockSize] lappend copyInstructions $dataInstructions return $copyInstructions } proc Digest {filename blockSize {sizecheck 0} {fingerprint 0}} { if [catch {package present md5 2}] {package forget md5 ; package require md5 2} set digest "[list $filename] $blockSize" if {[lsearch [file channels] $filename] == -1} { set filename [FileNameNormalize $filename] set digest "[list $filename] $blockSize" if {!([file isfile $filename] && [file readable $filename])} {return $digest} set f [open $filename r] } else { set f $filename } fconfigure $f -translation binary seek $f 0 end set fileSize [tell $f] seek $f 0 if {$sizecheck && ($fileSize < [expr $blockSize * 5])} {close $f ; return $digest} while {![eof $f]} { set blockContents [read $f $blockSize] set md5Sum [md5::md5 -hex -- $blockContents] set blockNumberSequence [SequenceBlock $blockContents] set weakChecksum [lindex [WeakChecksum $blockNumberSequence] 0] lappend digest "$md5Sum [format %.0f $weakChecksum]" } if $fingerprint { set fileIncrement [expr $fileSize/10] set fpLocation [expr $fileSize - 21] set i 0 while {$i < 10} { if {$fpLocation < 0} {set fpLocation 0} seek $f $fpLocation lappend fingerPrints [read $f 20] set fpLocation [expr $fpLocation - $fileIncrement] incr i } lappend digest fingerprints lappend digest [lsort -unique $fingerPrints] } close $f return $digest } proc DigestInstructionsCompress {digestInstructions blockSize} { if [string equal $digestInstructions {}] {return {}} set blockSpan $blockSize foreach {pointer blockInfo} $digestInstructions { if ![info exists currentBlockInfo] { set currentPointer $pointer set currentBlockInfo $blockInfo set md5Size [string length [lindex $blockInfo 1]] continue } if {$pointer == [expr $currentPointer + $blockSpan]} { set md5 [lindex $blockInfo 1] lappend currentBlockInfo $md5 incr blockSpan $blockSize } else { lappend newDigestInstructions $currentPointer lappend newDigestInstructions "[lindex $currentBlockInfo 0] [list "$md5Size [string map {{ } {}} [lrange $currentBlockInfo 1 end]]"]" set currentPointer $pointer set currentBlockInfo $blockInfo set blockSpan $blockSize } } lappend newDigestInstructions $currentPointer lappend newDigestInstructions "[lindex $currentBlockInfo 0] [list "$md5Size [string map {{ } {}} [lrange $currentBlockInfo 1 end]]"]" return $newDigestInstructions } proc DigestInstructionsExpand {digestInstructions blockSize} { if [string equal $digestInstructions {}] {return {}} foreach {pointer blockInfo} $digestInstructions { set blockNumber [lindex $blockInfo 0] set md5Size [lindex [lindex $blockInfo 1] 0] set blockString [lindex [lindex $blockInfo 1] 1] set blockLength [string length $blockString] set expandedBlock {} for {set i $md5Size} {$i <= $blockLength} {incr i $md5Size} { append expandedBlock " [string range $blockString [expr $i - $md5Size] [expr $i - 1]]" } set blockInfo "$blockNumber $expandedBlock" foreach md5 [lrange $blockInfo 1 end] { lappend newDigestInstructions $pointer lappend newDigestInstructions "$blockNumber $md5" incr pointer $blockSize incr blockNumber } } return $newDigestInstructions } proc FileNameNormalize {filename} { file normalize $filename } proc RollChecksum {a(k,l)_ b(k,l)_ k l Xsub_k Xsub_l+1 } { set Mod $trsync::Mod set a(k+1,l+1)_ [expr ${a(k,l)_} - $Xsub_k + ${Xsub_l+1}] set b(k+1,l+1)_ [expr ${b(k,l)_} - (($l - $k + 1) * $Xsub_k) + ${a(k+1,l+1)_}] set a(k+1,l+1)_ [expr fmod(${a(k+1,l+1)_},$Mod)] set b(k+1,l+1)_ [expr fmod(${b(k+1,l+1)_},$Mod)] set s(k+1,l+1)_ [expr ${a(k+1,l+1)_} + ($Mod * ${b(k+1,l+1)_})] return "${s(k+1,l+1)_} ${a(k+1,l+1)_} ${b(k+1,l+1)_} [incr k] [incr l]" } proc SequenceBlock {blockcontents} { binary scan $blockcontents c* blockNumberSequence set blockNumberSequenceLength [llength $blockNumberSequence] for {set i 0} {$i < $blockNumberSequenceLength} {incr i} { set blockNumberSequence [lreplace $blockNumberSequence $i $i [expr ([lindex $blockNumberSequence $i] + 0x100)%0x100]] } return $blockNumberSequence } proc WeakChecksum {Xsub_k...Xsub_l} { set a(k,i)_ 0 set b(k,i)_ 0 set Mod $trsync::Mod set k 1 set l [llength ${Xsub_k...Xsub_l}] for {set i $k} {$i <= $l} {incr i} { set Xsub_i [lindex ${Xsub_k...Xsub_l} [expr $i - 1]] set a(k,i)_ [expr ${a(k,i)_} + $Xsub_i] set b(k,i)_ [expr ${b(k,i)_} + (($l - $i + 1) * $Xsub_i)] } set a(k,l)_ [expr fmod(${a(k,i)_},$Mod)] set b(k,l)_ [expr fmod(${b(k,i)_},$Mod)] set s(k,l)_ [expr ${a(k,l)_} + ($Mod * ${b(k,l)_})] return "${s(k,l)_} ${a(k,l)_} ${b(k,l)_} $k $l [lindex ${Xsub_k...Xsub_l} 0]" } proc tdelta {referenceFile targetFile blockSize {sizecheck 0} {fingerprint 0}} { if {$::trsync::md5Size < 1} {error "md5Size must be greater than zero."} set signature [Digest $targetFile $blockSize $sizecheck $fingerprint] return [CopyInstructions $referenceFile $signature] } proc tpatch {targetFile copyInstructions fileToConstruct {eolNative 0}} { set copyInstructions [lreplace $copyInstructions 0 1 $fileToConstruct $targetFile] return [ConstructFile $copyInstructions $eolNative] } namespace export tdelta tpatch } # end namespace eval ::trsync ./tclvfs/library/template/tclIndex0000644000175000017500000000173711267270744017030 0ustar sergeisergei# Tcl autoload index file, version 2.0 # This file is generated by the "auto_mkindex" command # and sourced to set up indexing information for one or # more commands. Typically each line is a command that # sets an element in the auto_index array, where the # element name is the name of a command and the value is # a script that loads the command. set auto_index(::vfs::template::mount) [list package require vfs::template 1.5.3] set auto_index(::vfs::template::collate::mount) [list source [file join $dir collatevfs.tcl]] set auto_index(::vfs::template::quota::mount) [list source [file join $dir quotavfs.tcl]] set auto_index(::vfs::template::version::mount) [list source [file join $dir versionvfs.tcl]] set auto_index(::vfs::template::version::delta::mount) [list source [file join $dir deltavfs.tcl]] set auto_index(::vfs::template::chroot::mount) [list source [file join $dir chrootvfs.tcl]] set auto_index(::vfs::template::fish::mount) [list source [file join $dir fishvfs.tcl]] ./tclvfs/library/template/quotavfs.tcl0000644000175000017500000004745311115367522017705 0ustar sergeisergeiif 0 { ######################## quotavfs.tcl -- Written by Stephen Huntley (stephen.huntley@alum.mit.edu) License: Tcl license Version 1.5.2 A quota-enforcing virtual filesystem. Requires the template vfs in templatevfs.tcl. Quotas can be set on any quantity returned by "file stat" or "file attributes", plus the attribute "filename", which is the fully normalized pathname of the file. Two types of quota can be set: an incremented count of files matching a certain criterion, and a running total of a certain quantity. Each quota is defined by a set of switches composing a "quota group," any number of quota groups can be defined. A file must fit within all quotas defined to avoid triggering quota enforcement. The quotas are enforced as a FIFO stack of files; that is, if a new file is copied to the vfs whose attributes exceed a quota, the file is not rejected, rather, the already present files with the oldest access times that contribute to the quota are deleted until there is room within the quota limit for the addition of the new file. The exception for the running total variety is if the file's attribute is large enough to exceed the quota by itself, it is barred without first deleting all other files contributing to the quota. At mount time, all files in the existing directory are examined and quotas calculated. Files may be deleted to keep quotas under their defined limits. After mount, when a new file is moved into the virtual directory or an existing file edited, its properties are examined with respect to the defined quotas; if no room can be made for it, the move or edit is rejected. Usage: mount ?... ? Quota group definition: - -[quota|ruletotal] or - -total Options: - Where is any item returned by the "file stat" or "file attributes" commands, with the dash prepended as needed, for example: -archive, -permissions, -size, -mtime etc. The attribute "filename" is assumed to exist as well, defined as the file's full pathname. The quantity need not exist, so the same command line could be used on Unix or Windows, for example. Nonexistent quantities have no effect and are ignored. The rule is the criterion a file must meet to have the quota applied to it. It may take the form of a list of glob patterns as used by the "string match" command: if the quantity value matches all the patterns, the quota is applied. The rule may be Tcl code, to which the quantity value will be appended and then evaluated. The code should return 1 if the file is judged to meet the quota criterion, or 0 if not. If glob patterns are used, each pattern in the list may, in addition to symbols used by "string match", have a "!" prepended to it, which will negate the sense of the match. -quota If the quota group contains this switch, then the vfs will keep a running count of all files that satisfy the quota group's rule. It will not allow more than the number of files specified in to exist in the virtual file space. -total If the quota group contains this switch, then the vfs will track the sum of the values of the specified quantity of all files. It will not allow the sum specified in to be exceeded in the virtual file space. -ruletotal Like -total, but a rule is defined, and only files satisfying the rule have their values added to the quota sum. The quota vfs inherits the -cache and -volume options of the template vfs. Examples -- to set a 10 MB size limit on your ftp upload directory: mount -size -total 10000000 C:/temp/upload C:/vfs/ftp/pub To allow only PNG or JPEG files in a photo collection: mount -filename {!*.png !*.jpg !*.jpeg} -quota 0 /home/shuntley/photos /vfs/photo To ban GIF files from your web site images subdirectory: mount -filename {C:/Program Files/Apache/htdocs/images/*.gif} -quota 0 {C:/Program Files/Apache/htdocs} /docroot To disallow creation of subdirectories: mount -type directory -quota 0 /ftp/upload /intake Use a rule to allow only 1 MB of files greater than 10kB in size: mount -size {expr 10000 <} -ruletotal 1000000 /tmp /vfs/dump Use two quota groups to allow only log files and keep only 1 more than one week: mount -filename !*.log -quota 0 -mtime {expr [clock scan {7 days ago}] >} -quota 1 /var/log /vfs/history ######################## } package require vfs::template 1.5 package require fileutil::globfind package provide vfs::template::quota 1.5.2 namespace eval ::vfs::template::quota { # read template procedures into current namespace. Do not edit: foreach templateProc [namespace eval ::vfs::template {info procs}] { set infoArgs [info args ::vfs::template::$templateProc] set infoBody [info body ::vfs::template::$templateProc] proc $templateProc $infoArgs $infoBody } # edit following procedures: proc close_ {channel} { upvar path path root root relative relative fconfigure $channel -translation binary seek $channel 0 end set quotaSize [tell $channel] seek $channel 0 set filechannel [lindex $::vfs::template::quota::channels($channel) 0] set newFile [lindex $::vfs::template::quota::channels($channel) 1] unset ::vfs::template::quota::channels($channel) set file [file join $path $relative] # Check if edited size violates any size quotas before allowing commit: if [catch {QuotaAdd $file}] { close $filechannel if $newFile {catch {file delete -force $file}} error "Disk quota exceeded" } seek $filechannel 0 fcopy $channel $filechannel close $filechannel return } proc file_atime {file time} { upvar root root file atime $file $time append ::vfs::template::quota::atimes($root) " $time [list $file]" if {$::vfs::template::quota::files($file) < $time} {set ::vfs::template::quota::files($file) $time ; return} set ::vfs::template::quota::files($file) $time set aList {} foreach {atime afile} $::vfs::template::quota::atimes($root) { lappend aList "$atime [list $afile]" } set atimes {} foreach aset [lsort -dictionary $aList] { set atime [lindex $aset 0] set afile [lindex $aset 1] append atimes " $atime [list $afile]" } set ::vfs::template::quota::atimes($root) $atimes } proc file_mtime {file time} {file mtime $file $time} proc file_attributes {file {attribute {}} args} {eval file attributes \$file $attribute $args} proc file_delete {file} { upvar root root array set quotaArray $::vfs::template::quota::quota($root) QuotaDelete $file set ::vfs::template::quota::quota($root) [array get quotaArray] return } proc file_executable {file} {file executable $file} proc file_exists {file} {file exists $file} proc file_mkdir {file} { upvar root root file mkdir $file globfind $file QuotaAdd return } proc file_readable {file} {file readable $file} proc file_stat {file array} {upvar $array fs ; ::file stat $file fs} proc file_writable {file} {file writable $file} proc glob_ {directory dir nocomplain tails types typeString dashes pattern} {glob -directory $dir -nocomplain -tails -types $typeString -- $pattern} proc open_ {file mode} { upvar root root permissions permissions upvar newFile newFile if {$mode == "r"} { set atime [clock seconds] append ::vfs::template::quota::atimes($root) " $atime [list $file]" set ::vfs::template::quota::files($file) $atime return [open $file r] } if $newFile { set now [clock seconds] set fstat "mtime $now atime $now mode $permissions type file ctime $now size 0" QuotaAdd $file } set channel [open $file $mode] # Check if new file violates any quotas by adding it to quota tallies: # if $newFile { # set err [catch {QuotaAdd $file} result] # if $err { # close $channel # file delete -force -- $file # vfs::filesystem posixerror $::vfs::posix(EDQUOT) # error "Disk quota exceeded" # } # } # remove file from quota tallies until channel is closed: array set quotaArray $::vfs::template::quota::quota($root) QuotaDelete $file 0 set ::vfs::template::quota::quota($root) [array get quotaArray] # Use memchan to store edits so edit can be rejected if it violates size quotas: set memchannel [memchan] fconfigure $channel -translation binary fconfigure $memchannel -translation binary seek $channel 0 fcopy $channel $memchannel set [namespace current]::channels($memchannel) "$channel $newFile" return $memchannel } proc MountProcedure {args} { upvar volume volume # take real and virtual directories from command line args. set to [lindex $args end] if [string equal $volume {}] {set to [::file normalize $to]} set path [::file normalize [lindex $args end-1]] # make sure mount location exists: ::file mkdir $path # add custom handling for new vfs args here. namespace import -force ::fileutil::globfind::globfind set quotaArgs [lrange $args 0 end-2] ParseArgs ::vfs::template::quota::quota($to) $quotaArgs # Initialize quotas: set root $to set aList {} foreach afile [globfind $path] { file stat $afile fs lappend aList "$fs(atime) [list $afile]" } set atimes {} foreach aset [lsort -dictionary $aList] { set atime [lindex $aset 0] set afile [lindex $aset 1] append atimes " $atime [list $afile]" set ::vfs::template::quota::files($afile) $atime } set ::vfs::template::quota::atimes($root) $atimes globfind $path QuotaAdd set ::vfs::template::quota::atimes($root) $atimes # return two-item list consisting of real and virtual locations. lappend pathto $path lappend pathto $to return $pathto } proc UnmountProcedure {path to} { # add custom unmount handling of new vfs elements here. unset -nocomplain ::vfs::template::quota::quota($to) unset -nocomplain ::vfs::template::quota::atimes($to) return } # Default rule for quotas with pattern specified: proc CheckPattern {pattern value} { foreach ptn $pattern { set negate [string equal [string index $ptn 0] !] if $negate {set ptn [string range $ptn 1 end]} set match [string match $ptn $value] if $negate {set match [expr !$match]} if !$match {return 0} } return 1 } # Used as argument to proc globfind to recurse down dir hierarchies and process each file and dir found: proc QuotaAdd {fileName} { set caller [lindex [info level -1] 0] if {$caller == "MountProcedure"} {set init 1} else {set init 0} upvar path path root root quotaSize quotaSize fstat fstat if ![string first ".vfs_" [file tail $fileName]] {return 0} if {[info exists path] && ($fileName == $path)} {return 0} array set quotaArray $::vfs::template::quota::quota($root) set overLimit {} set items [lsort -unique [string map {",type " " " ",rule " " " ",quota " " " ",current " " "} " [array names quotaArray] "]] set delete 1 if [info exists fstat] { array set fs $fstat } else { set noexist [catch {file stat $fileName fs}] if $noexist {return 0} } set fs(filename) $fileName # if this call is being used to check edits, replace file size with channel size and don't delete file if edit too big: if [info exists quotaSize] {set fs(size) $quotaSize ; set delete 0 ; unset quotaSize} # Update queue which tracks which files to try deleting first to make room for new files: append ::vfs::template::quota::atimes($root) " $fs(atime) [list $fileName]" set ::vfs::template::quota::files($fileName) $fs(atime) # Check each defined quota to see if given file violates it: foreach item $items { regexp {([0-9]*),(.*)} $item trash groupCount item if ![info exists fs($item)] {if [file exists $fileName] {array set fs [file attributes $fileName]}} if ![info exists fs($item)] {continue} set contrib [eval $quotaArray($groupCount,$item,rule) [list $fs($item)]] if $contrib { if {$quotaArray($groupCount,$item,type) == "total"} { # If file quantity by itself would violate quota, reject immediately: if {$fs($item) > $quotaArray($groupCount,$item,quota)} { if $delete {catch {file delete -force -- $fileName} result} if [info exists ::vfs::template::quota::debug] { puts "\n$fileName violates quota by itself: $item: $fs($item) quota: $quotaArray($groupCount,$item,quota)" if $delete {puts "$fileName deleted: $result"} } if $init {return 0} else {vfs::filesystem posixerror $::vfs::posix(EDQUOT)} } set quotaArray($groupCount,$item,current) [expr $quotaArray($groupCount,$item,current) + $fs($item)] } else { if {$quotaArray($groupCount,$item,quota) == 0} { if $delete {catch {file delete -force -- $fileName} result} if [info exists ::vfs::template::quota::debug] { puts "\n$fileName violates quota by itself: $item: $fs($item) quota: $quotaArray($groupCount,$item,quota)" if $delete {puts "$fileName deleted: $result"} } if $init {return 0} else {vfs::filesystem posixerror $::vfs::posix(EDQUOT)} } incr quotaArray($groupCount,$item,current) } # If file violates quota, store quota to see if room can be made by deleting older files: if {$quotaArray($groupCount,$item,current) > $quotaArray($groupCount,$item,quota)} {lappend overLimit "$groupCount,$item"} } } # if given file puts some quotas over limit, see if room can be made by deleting older files: foreach item $overLimit { set itm [lindex [split $item ,] 1] if {$quotaArray($item,current) <= $quotaArray($item,quota)} {continue} # examine queue of stored atimes to find older files: foreach {atime afile} $::vfs::template::quota::atimes($root) { # If stored atime doesn't match latest value, delete record and move on: if {($::vfs::template::quota::files($afile) != $atime) || ![file exists $afile]} { set deleteLoc [lsearch -exact $::vfs::template::quota::atimes($root) $afile] set ::vfs::template::quota::atimes($root) [lreplace $::vfs::template::quota::atimes($root) [expr $deleteLoc - 1] $deleteLoc] if {[lsearch -exact $::vfs::template::quota::atimes($root) $afile] < 0} {unset ::vfs::template::quota::files($afile)} continue } # if file from queue is in fact newer than given file, skip it: if {$atime > $fs(atime)} {continue} # if stored filename is same as given filename, given filename violates quota and must be rejected: if {$afile == $fileName} { if !$delete {set quotaSize $fs(size)} catch {QuotaDelete $fileName $delete} set ::vfs::template::quota::quota($root) [array get quotaArray] if $init {return 0} else {vfs::filesystem posixerror $::vfs::posix(EDQUOT)} } # If stored file contributes to quota, delete it and remove from quota tally: if {$itm == "filename"} { set itm_val $afile } elseif {[string index $itm 0] == "-"} { set itm_val [file attributes $afile $itm] } else { file stat $afile iv set itm_val $iv($itm) } set contrib [eval $quotaArray($item,rule) [list $itm_val]] if $contrib { if {$quotaArray($item,type) == "total"} { set itm [lindex [split $item ,] 1] if {[string index $itm 0] == "-"} { set itm_val [file attributes $afile $itm] } else { file stat $afile iv set itm_val $iv($itm) } if !$itm_val {continue} } set ::vfs::template::quota::quota($root) [array get quotaArray] QuotaDelete $afile } # If deletions make room for new file, then OK: if {$quotaArray($item,current) <= $quotaArray($item,quota)} {break} } } set ::vfs::template::quota::quota($root) [array get quotaArray] return 0 } proc QuotaDelete {fileName {delete 1}} { upvar quotaArray quotaArray quotaSize quotaSize set items [lsort -unique [string map {",type " " " ",rule " " " ",quota " " " ",current " " "} " [array names quotaArray] "]] # If given fileName is a dir, must remove all contents from quota tallies before removing dir itself: set files [lsort -decreasing [globfind $fileName]] set type file # Must parse contents twice, eliminate files first, then dirs: foreach file [concat $files //// $files] { if {$file == "////"} {set type directory ; continue} # cache quantity info to save time on second pass: if ![info exists stat($file)] { file stat $file fs set fs(filename) $fileName if [info exists quotaSize] {set fs(size) $quotaSize} set stat($file) [array get fs] } array set fs $stat($file) # If file type is wrong for this pass, continue: if {($type == "file") && ($fs(type) == "directory")} {continue} if {($type == "directory") && ($fs(type) != "directory")} {continue} # Check each quota to see if current file contributes to it: foreach item $items { regexp {([0-9]*),(.*)} $item trash groupCount item if ![info exists fs($item)] {if [file exists $file] {array set fs [file attributes $file]} ; set stat($file) [array get fs]} if ![info exists fs($item)] {continue} set contrib [eval $quotaArray($groupCount,$item,rule) [list $fs($item)]] if $contrib { if {$quotaArray($groupCount,$item,type) == "total"} { set quotaArray($groupCount,$item,current) [expr $quotaArray($groupCount,$item,current) - $fs($item)] } else { incr quotaArray($groupCount,$item,current) -1 } if [info exists ::vfs::template::quota::debug] { puts "\n$file contributed to quota: rule: $quotaArray($groupCount,$item,rule) quota: $quotaArray($groupCount,$item,quota) current: $quotaArray($groupCount,$item,current)" } } } # After removing file from quota tallies, delete it: if $delete {file delete -force -- $file} if {$delete && [info exists ::vfs::template::quota::debug]} { puts "\n$file deleted" } } return } # Decided on new command line syntax, rather than rewrite whole vfs, # this proc casts new syntax into old format, then processes as before: proc ParseArgs {argsStore args} { upvar path path set args [lindex $args 0] array set attrs [file attributes $path] set quotas {} set totals {} set rtotals {} set newArgs {} # find location of each quota group: set qPosition [lsearch -all $args "-quota"] set tPosition [lsearch -all $args "-total"] set rPosition [lsearch -all $args "-ruletotal"] # break group defs into separate categories: foreach qp $qPosition { incr qp append quotas " [lrange $args [expr $qp - 3] $qp]" } foreach tp $tPosition { incr tp append totals " [lrange $args [expr $tp - 2] $tp]" } foreach rp $rPosition { incr rp append rtotals " [lrange $args [expr $rp - 3] $rp]" } # cast each category into old syntax: foreach {type pr quota number} $quotas { set patrul "-pattern" if {[lsearch -exact [info commands [string trim [string range $pr 0 [string first { } $pr]]]] [string trim [string range $pr 0 [string first { } $pr]]]] > -1} { set patrul "-rule" } if ![info exists attrs($type)] {set type [string range $type 1 end]} append newArgs " -number: -item $type $patrul [list $pr] -quota $number" } foreach {type total number} $totals { if ![info exists attrs($type)] {set type [string range $type 1 end]} append newArgs " -total: -item $type -quota $number" } foreach {type pr rtotal number} $rtotals { set patrul "-pattern" if {[lsearch -exact [info commands [string trim [string range $pr 0 [string first { } $pr]]]] [string trim [string range $pr 0 [string first { } $pr]]]] > -1} { set patrul "-rule" } if ![info exists attrs($type)] {set type [string range $type 1 end]} append newArgs " -total: -item $type $patrul [list $pr] -quota $number" } # process old syntax: unset args lappend args [string trim $newArgs] set groupCount 0 set args [lindex $args 0] set argsIndex [llength $args] for {set i $argsIndex} {$i >= 0} {incr i -1} { switch -- [lindex $args $i] { -number: - -total: { set item $itemSet(item) if ![info exists itemSet(rule)] {set itemSet(rule) "CheckPattern *"} set argsArray($groupCount,$item,type) [string range [lindex $args $i] 1 end-1] set argsArray($groupCount,$item,rule) $itemSet(rule) set argsArray($groupCount,$item,quota) $itemSet(quota) set argsArray($groupCount,$item,current) 0 array unset itemSet incr groupCount } -item { set itemSet(item) [lindex $args [expr $i + 1]] } -pattern { set itemSet(rule) "CheckPattern [list [lindex $args [expr $i + 1]]]" } -quota { set itemSet(quota) [lindex $args [expr $i + 1]] } -rule { set itemSet(rule) [lindex $args [expr $i + 1]] } } } set $argsStore [array get argsArray] } } # end namespace ::vfs::template::quota ./tclvfs/library/template/globfind.tcl0000644000175000017500000004245011544536122017611 0ustar sergeisergeiif 0 { ######################## globfind.tcl -- Written by Stephen Huntley (stephen.huntley@alum.mit.edu) License: Tcl license Version 1.5.3 The proc globfind is a replacement for tcllib's fileutil::find Usage: globfind ?basedir ?filtercmd? ?switches?? Options: basedir - the directory from which to start the search. Defaults to current directory. filtercmd - Tcl command; for each file found in the basedir, the filename will be appended to filtercmd and the result will be evaluated. The evaluation should return 0 or 1; only files whose return code is 1 will be included in the final return result. switches - The switches will "prefilter" the results before the filtercmd is applied. The available switches are: -depth - sets the number of levels down from the basedir into which the filesystem hierarchy will be searched. A value of zero is interpreted as infinite depth. -pattern - a glob-style filename-matching wildcard. ex: -pattern *.pdf -types - any value acceptable to the "types" switch of the glob command. ex: -types {d hidden} Side effects: If somewhere within the search space a directory is a link to another directory within the search space, then the variable ::fileutil::globfind::REDUNDANCY will be set to 1 (otherwise it will be set to 0). The name of the redundant directory will be appended to the variable ::fileutil::globfind::redundant_files. This information may be used to help track down and eliminate infinitely looping links in the search space. Unlike fileutil::find, the name of the basedir will be included in the results if it fits the prefilter and filtercmd criteria (thus emulating the behavior of the standard Unix GNU find utility). ---- globfind is designed as a fast and simple alternative to fileutil::find. It takes advantage of glob's ability to use multiple patterns to scan deeply into a directory structure in a single command, hence the name. It reports symbolic links along with other files by default, but checks for nesting of links which might otherwise lead to infinite search loops. It reports hidden files by default unless the -types switch is used to specify exactly what is wanted. globfind may be used with Tcl versions earlier than 8.4, but emulation of missing features of the glob command in those versions will result in slower performance. globfind is generally two to three times faster than fileutil::find, and fractionally faster than perl's File::Find function for comparable searches. The filtercmd may be omitted if only prefiltering is desired; in this case it may be a bit faster to use the proc globtraverse, which uses the same basedir value and command-line switches as globfind, but does not take a filtercmd value. If one wanted to search for pdf files for example, one could use the command: globfind $basedir {string match -nocase *.pdf} It would, however, in this case be much faster to use: globtraverse $basedir -pattern *.pdf ######################## } package provide fileutil::globfind 1.5 namespace eval ::fileutil::globfind { namespace export globfind globtraverse proc globfind {{basedir .} {filtercmd {}} args} { set returnFiles {} set types {} set basedir [file normalize $basedir] # account for possibility that filtercmd is missing by # reformatting $args variable: set args [concat [list $filtercmd] $args] if [expr fmod([llength $args],2)] { set filtercmd [lindex $args 0] set args [lrange $args 1 end] } else { set filtercmd {} } set filt [string length $filtercmd] set 83ok [package vsatisfies [package present Tcl] 8.3] # process command-line switches: foreach {flag value} $args { if {[string first $flag -types] >= 0} {set flag "-types"} if {[string first $flag -pattern] >= 0} {set flag "-pattern"} if {[string first $flag -depth] >= 0} {set flag "-depth"} switch -- $flag { -types { set types [list $value] # can't use -types pre-8.3, because it doesn't exist in glob command. # thus if it is specified, error out: if !$83ok {error {error: "-types" flag not supported in version 8.2 and earlier}} # bug in 8.3, if -types {hidden f} is used, possible crash. So disallow: if {(![package vcompare [package present Tcl] 8.3]) && ($tcl_platform(platform) == "unix") && ([lsearch $types "hidden"] >= 0) && ([lsearch $types "f"] >= 0)} { error {Tcl 8.3 bug: potential program crash if "-types {hidden f}" used} } set types "-types $types" } -pattern {set pattern [list $value]} -depth {set depth [expr [list $value]]} default {error "$flag: incorrect flag value"} } } # add basedir to result if it satisfies prefilter conditions: set returnFiles [eval [eval list globtraverse [list [file dirname $basedir]] $args -depth 1]] if {[lsearch -exact $returnFiles $basedir] >= 0} {set returnFiles [list $basedir]} else {set returnFiles {}} # get all files in basedir that satisfy prefilter conditions: set returnFiles [concat $returnFiles [eval [eval list globtraverse \$basedir $args]]] # get hidden files if no specific types requested: if {$types == {}} { # save redundant file values already gathered: set redundant_files {} if [set REDUNDANCY $[namespace current]::REDUNDANCY] { set redundant_files $[namespace current]::redundant_files } # get hidden files: set returnFiles [concat $returnFiles [eval [eval list globtraverse \$basedir $args -type hidden]]] # virtual filesystems ignore hidden tag, so just in case, filter out duplicates: set returnFiles [lsort -unique $returnFiles] # collate redundant file info: if $[namespace current]::REDUNDANCY { set [namespace current]::redundant_files [concat $[namespace current]::redundant_files $redundant_files] } else { set [namespace current]::redundant_files $redundant_files } set [namespace current]::REDUNDANCY [expr ($[namespace current]::REDUNDANCY || $REDUNDANCY)] } # apply filtercmd to prefiltered results if one is specified: if $filt { set filterFiles {} foreach filename $returnFiles { if [uplevel $filtercmd [list $filename]] { lappend filterFiles $filename } } } else { set filterFiles $returnFiles } return $filterFiles } proc globtraverse {{basedir .} args} { set [namespace current]::REDUNDANCY 0 unset -nocomplain [namespace current]::redundant_files set depth 0 # search 16 directory levels per iteration, glob can't handle more patterns than that at once. set maxDepth 16 set pattern * set types {} set resultList {} set basedir [file normalize $basedir] if ![file isdirectory $basedir] {return} set baseDepth [llength [file split $basedir]] ; # calculate starting depth lappend checkDirs $basedir ; # initialize list of dirs to check # format basedir variable for later infinite loop checking: set basedir $basedir/ set basedir [string map {// /} $basedir] set 83ok [package vsatisfies [package present Tcl] 8.3] # process command-line switches: foreach {flag value} $args { if {[string first $flag -types] >= 0} {set flag "-types"} if {[string first $flag -pattern] >= 0} {set flag "-pattern"} if {[string first $flag -depth] >= 0} {set flag "-depth"} switch -- $flag { -types { set types [list $value] if !$83ok {error {error: "-types" flag not supported in version 8.2 and earlier}} if {(![package vcompare [package present Tcl] 8.3]) && ($tcl_platform(platform) == "unix") && ([lsearch $types "hidden"] >= 0) && ([lsearch $types "f"] >= 0)} { error {Tcl 8.3 bug: potential program crash if "-types {hidden f}" used} } set types "-types $types" } -pattern {set pattern [list $value]} -depth {set depth [expr [list $value]]} default {error "$flag: incorrect flag value"} } } # Main result-gathering loop: while {[llength $checkDirs]} { set currentDir [lindex $checkDirs 0] set currentDepth [expr [llength [file split $currentDir]] - $baseDepth] ; # distance from start depth set searchDepth [expr $depth - $currentDepth] ; # distance from max depth to search to # build multi-pattern argument to feed to glob command: set globPatternTotal {} set globPattern * set incrPattern /* for {set i 1} {$i <= $maxDepth} {incr i} { set customPattern [string range $globPattern 0 end-1] append customPattern $pattern lappend globPatternTotal $customPattern append globPattern $incrPattern incr searchDepth -1 if {$searchDepth == 0} {break} } # save pattern to use for iterative dir search later: set dirPattern [string range $globPattern 0 end-2] # glob pre-8.3 doesn't support -directory switch; emulate it if necessary: if $83ok { set contents [eval glob -nocomplain -directory \$currentDir $types -- $globPatternTotal] } else { set wd [pwd] set newContents {} cd $currentDir if [catch {set contents [eval glob -nocomplain -- $globPatternTotal]} err] { cd $wd error $err } cd $wd foreach item $contents { set item [file join $currentDir $item] lappend newContents $item } set contents $newContents unset newContents } set resultList [concat $resultList $contents] # check if iterative dir search is necessary (if specified depth not yet reached): set contents {} set findDirs 1 if {([expr $currentDepth + [llength [file split $dirPattern]]] >= $depth) && ($depth > 0)} {set findDirs 0} # find dirs at current depth boundary to prime iterative search. # Pre-8.3 glob doesn't support -type or -dir switches; emulate if necessary: if {$83ok && $findDirs} { set contents [glob -nocomplain -directory $currentDir -type d -- $dirPattern] } elseif $findDirs { set wd [pwd] set newContents {} cd $currentDir if [catch {set contents [glob -nocomplain -- $dirPattern/]} err] { cd $wd error $err } cd $wd foreach item $contents { set item [file join $currentDir [string range $item 0 end-1]] lappend newContents $item } set contents $newContents unset newContents } # check for redundant links in dir list: set contentLength [llength $contents] set i 0 while {$i < $contentLength} { set item [lindex $contents end-$i] incr i # kludge to fully resolve link to native name: set linkValue [file dirname [file normalize [file join $item __dummy__]]] # if item is a link, and native name is already in the search space, skip it: if {($linkValue != $item) && (![string first $basedir/ $linkValue/])} { set [namespace current]::REDUNDANCY 1 lappend [namespace current]::redundant_files $item continue } lappend checkDirs $item } # remove current search dir from search list to prime for next iteration: set checkDirs [lrange $checkDirs 1 end] } return $resultList } # Tcl pre-8.4 lacks [file normalize] command; emulate it if necessary: proc ::fileutil::globfind::file {args} { if {[lindex $args 0] == "normalize"} { set filename [lindex $args 1] set tail [file tail $filename] set filename [::fileutil::fullnormalize [file dirname $filename]] set filename [file join $filename $tail] return $filename } else { return [uplevel ::file $args] } } # Eliminate emulation of [file normalize] if version 8.4 or better: if [package vsatisfies [package present Tcl] 8.4] { rename ::fileutil::globfind::file {} } else { package require fileutil 1.13 } # ----------------- # Following are sample filter commands that can be used with globfind: # scfind: a command suitable for use as a filtercmd with globfind, arguments # duplicate a subset of GNU find args. proc scfind {args} { set filename [file join [pwd] [lindex $args end]] set switches [lrange $args 0 end-1] array set types { f file d directory c characterSpecial b blockSpecial p fifo l link s socket } array set signs { - < + > } array set multiplier { time 86400 min 3600 } file stat $filename fs set pass 1 set switchLength [llength $switches] for {set i 0} {$i < $switchLength} {incr i} { set sw [lindex $switches $i] switch -- $sw { -type { set value [lindex $switches [incr i]] if ![string equal $fs(type) $types($value)] {return 0} } -regex { set value [lindex $switches [incr i]] if ![regexp $value $filename] {return 0} } -size { set value [lindex $switches [incr i]] set sign "==" if [info exists signs([string index $value 0])] { set sign $signs([string index $value 0]) set value [string range $value 1 end] } set sizetype [string index $value end] set value [string range $value 0 end-1] if [string equal $sizetype b] {set value [expr $value * 512]} if [string equal $sizetype k] {set value [expr $value * 1024]} if [string equal $sizetype w] {set value [expr $value * 2]} if ![expr $fs(size) $sign $value] {return 0} } -atime - -mtime - -ctime - -amin - -mmin - -cmin { set value [lindex $switches [incr i]] set sw [string range $sw 1 end] set time "[string index $sw 0]time" set interval [string range $sw 1 end] set sign "==" if [info exists signs([string index $value 0])] { set sign $signs([string index $value 0]) set value [string range $value 1 end] } set value [expr [clock seconds] - ($value * $multiplier($interval))] if ![expr $value $sign $fs($time)] {return 0} } } } return 1 } # find: example use of globfind and scfind to duplicate a subset of the # command line interface of GNU find. # ex: # find $env(HOME) -type l -atime +1 proc find {args} { globfind [lindex $args 0] [list [subst "scfind $args"]] } # ----------------- # globsync: sync two locations so that the target looks just like the source: # If "destructive" is set to 1, files in the target will be deleted if files in equivalent # locations in source don't exist. If 0, files that exist only in target will be left # alone, leaving target not an exact duplicate of source. # if "log" is set to 1, progress messages will be written to stdout. If 0, not. # "source" is location to be duplicated. # "target" is location to be synced to look like source. # file is parameter fed to globsync by globfind. # ex: globfind ~user_a {globsync 1 1 ~user_a ~user_b} proc globsync {destructive log source target file} { set source [file normalize $source] set target [file normalize $target] set sourceLength [llength [file split $source]] set targetLength [llength [file split $target]] set targetFile [file normalize [file join $target [join [lrange [file split $file] $sourceLength end] /]]] array set sourceAttr [file attributes $file] file stat $file fs array set sourceAttr "mtime $fs(mtime)" if ![file isdirectory $file] { if [file isdirectory $targetFile] {file delete -force -- $targetFile} set err [catch {file copy -force -- $file $targetFile} result] if $err {set err [catch {file mkdir [file dirname $targetFile] ; file copy -force -- $file $targetFile} result]} if $err {errHandle $result} if $log {puts "copied $file to $targetFile"} array set targetAttr [file attributes $targetFile] foreach attr [array names sourceAttr] { if {[array get sourceAttr $attr] != [array get targetAttr $attr]} {catch {file attributes $targetFile $attr $sourceAttr($attr)}} } return 0 } set err [catch {file mkdir $targetFile} result] if $err {set err [catch {file delete -force -- $targetFile ; file mkdir $targetFile} result]} if $err {errHandle $result} array set targetAttr [file attributes $targetFile] file stat $targetFile fs array set targetAttr "mtime $fs(mtime)" foreach attr [array names sourceAttr] { if {[array get sourceAttr $attr] != [array get targetAttr $attr]} { catch {file attributes $targetFile $attr $sourceAttr($attr)} } } set sourceDirs [glob -dir $file -nocomplain -type d *] if {[lindex [file system $file] 0] != "tclvfs"} {append sourceDirs " [glob -dir $file -nocomplain -type {d hidden} *]"} set targetDirs [glob -dir $targetFile -nocomplain -type d *] if {[lindex [file system $targetFile] 0] != "tclvfs"} {append sourceDirs " [glob -dir $targetFile -nocomplain -type {d hidden} *]"} if !$destructive {set targetDirs {}} foreach td $targetDirs { set sd [file join $source [join [lrange [file split $td] $targetLength end] /]] if {[lsearch $sourceDirs $sd] < 0} { file delete -force -- $td if $log {puts "deleted directory $td"} } } set sourceFiles [glob -dir $file -nocomplain -types {b c f l p s} *] if {[lindex [file system $file] 0] != "tclvfs"} {append sourceFiles " [glob -dir $file -nocomplain -types {b c f l p s hidden} *]"} set targetFiles {} if $destructive { set targetFiles [glob -dir $targetFile -nocomplain -types {b c f l p s} *] if {[lindex [file system $targetFile] 0] != "tclvfs"} {append targetFiles " [glob -dir $targetFile -nocomplain -types {b c f l p s hidden} *]"} } foreach tf $targetFiles { set sf [file join $source [join [lrange [file split $tf] $targetLength end] /]] if {[lsearch $sourceFiles $sf] < 0} { file delete -force -- $tf if $log {puts "deleted file $tf"} } } return 0 } proc errHandle {result} { error $result } } # end namespace ::fileutil::globfind ./tclvfs/library/template/fishvfs.tcl0000644000175000017500000004461311115367522017500 0ustar sergeisergei#! /usr/bin/env tclsh if 0 { ######################## fishvfs.tcl -- A "FIles transferred over SHell" virtual filesystem This is not an official "FISH" protocol client as described at: http://mini.net/tcl/12792 but it utilizes the same concept of turning any computer that offers access via ssh, rsh or similar shell into a file server. Written by Stephen Huntley (stephen.huntley@alum.mit.edu) License: Tcl license Version 1.5.2 Usage: mount ?-volume? \ ?-cache ? \ # cache retention seconds ?-exec? \ # location of executable ?-transport ? \ # can be ssh, rsh or plink ?-user ? \ # remote computer login name ?-password ? \ # remote computer login password ?-host ? \ # remote computer domain name ?-port ? \ # override default port ?