pax_global_header00006660000000000000000000000064152624502060014514gustar00rootroot0000000000000052 comment=9345a871483c253a6ae4520e1a4fe0e4b72689fd cyanogilvie-teabase-9345a87/000077500000000000000000000000001526245020600157155ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/.gitignore000066400000000000000000000000171526245020600177030ustar00rootroot00000000000000Makefile *.swp cyanogilvie-teabase-9345a87/Makefile.in000066400000000000000000000057161526245020600177730ustar00rootroot00000000000000VALGRINDEXTRA = VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \ --leak-check=yes -v --suppressions=suppressions --keep-debuginfo=yes \ --trace-children=yes --error-exitcode=2 $(VALGRINDEXTRA) PGOGEN_BUILD = -fprofile-generate=prof PGO_BUILD = @PGO_BUILD@ PGO= CFLAGS += $(PGO) CONFIGUREFLAGS = {CFLAGS=-O3 -flto -march=native} PACKAGE_LOAD = "apply {dir {source [file join \$$dir pkgIndex.tcl]; package require -exact $(PACKAGE_NAME) $(PACKAGE_VERSION)}} `@CYGPATH@ $(top_builddir)`" PACKAGE_LOAD_EMBED = apply\ {dir\ {source\ [file\ join\ \$$dir\ pkgIndex.tcl];\ package\ require\ -exact\ $(PACKAGE_NAME)\ $(PACKAGE_VERSION)}}\ `@CYGPATH@\ $(top_builddir)` CONTAINER = cyanogilvie/alpine-tcl:v0.9.118-gdb benchmark: binaries libraries $(TCLSH) `@CYGPATH@ $(srcdir)/bench/run.tcl` $(BENCHFLAGS) -load $(PACKAGE_LOAD) tags: generic/* ctags-exuberant --langmap=c:+.re generic/* vim-core: $(TCLSH_ENV) $(PKG_ENV) vim -c 'packadd termdebug' -c "set mouse=a" -c "set number" -c "set foldlevel=100" -c "Termdebug $(TCLSH_PROG) core" -c Winbar generic/ vim-gdb: binaries libraries $(TCLSH_ENV) $(PKG_ENV) vim -c "set number" -c "set mouse=a" -c "set foldlevel=100" -c "Termdebug -ex set\ print\ pretty\ on --args $(TCLSH_PROG) tests/all.tcl -singleproc 1 -load $(PACKAGE_LOAD_EMBED) $(TESTFLAGS)" -c "2windo set nonumber" -c "1windo set nonumber" vim-benchmark-gdb: binaries libraries $(TCLSH_ENV) $(PKG_ENV) vim -c "set number" -c "set mouse=a" -c "set foldlevel=100" -c "Termdebug -ex set\ print\ pretty\ on --args $(TCLSH_PROG) bench/run.tcl -load $(PACKAGE_LOAD_EMBED) $(BENCHFLAGS)" -c "2windo set nonumber" -c "1windo set nonumber" pgo: rm -rf prof make -C . PGO="$(PGOGEN_BUILD)" clean binaries libraries test benchmark make -C . PGO="$(PGO_BUILD)" clean binaries libraries coverage: make -C . PGO="--coverage" clean binaries libraries test TESTFLAGS="$(TESTFLAGS)" test-container: docker run --rm -it $(DOCKER_ARGS) -v "$(realpath $(srcdir)):/src/local:ro" $(CONTAINER) /src/local/teabase/dtest.tcl "$(TESTFLAGS)" build-container: mkdir -p "$(top_builddir)/dockerbuild" docker run --rm -it $(DOCKER_ARGS) -v "$(realpath $(srcdir)):/src/local:ro" -v "$(top_builddir)/dockerbuild:/install" $(CONTAINER) /src/local/teabase/dbuild.tcl "$(shell id -u)" "$(shell id -g)" benchmark-container: mkdir -p "$(top_builddir)/rundata" docker run --rm -it $(DOCKER_ARGS) -v "$(realpath $(srcdir)):/src/local:ro" -v "$(realpath $(srcdir))/rundata:/src/local/rundata" $(CONTAINER) /src/local/teabase/dbench.tcl "-rundata /src/local/rundata $(BENCHFLAGS)" "$(CONFIGUREFLAGS)" benchmark-container-pgo: mkdir -p "$(top_builddir)/rundata" docker run --rm -it $(DOCKER_ARGS) -v "$(realpath $(srcdir)):/src/local:ro" -v "$(realpath $(srcdir))/rundata:/src/local/rundata" $(CONTAINER) /src/local/teabase/dbench.tcl "-rundata /src/local/rundata $(BENCHFLAGS)" "$(CONFIGUREFLAGS)" pgo .PHONY: vim-gdb vim-core pgo coverage benchmark test-container build-container benchmark-container cyanogilvie-teabase-9345a87/__builddir.in000066400000000000000000000000121526245020600203320ustar00rootroot00000000000000@BUILDDIR@cyanogilvie-teabase-9345a87/__srcdir.in000066400000000000000000000000131526245020600200230ustar00rootroot00000000000000@SOURCEDIR@cyanogilvie-teabase-9345a87/ax_cc_for_build.m4000066400000000000000000000057061526245020600212710ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_cc_for_build.html # =========================================================================== # # SYNOPSIS # # AX_CC_FOR_BUILD # # DESCRIPTION # # Find a build-time compiler. Sets CC_FOR_BUILD and EXEEXT_FOR_BUILD. # # LICENSE # # Copyright (c) 2010 Reuben Thomas # Copyright (c) 1999 Richard Henderson # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 dnl Get a default for CC_FOR_BUILD to put into Makefile. AC_DEFUN([AX_CC_FOR_BUILD], [# Put a plausible default for CC_FOR_BUILD in Makefile. if test -z "$CC_FOR_BUILD"; then if test "x$cross_compiling" = "xno"; then CC_FOR_BUILD='$(CC)' else CC_FOR_BUILD=gcc fi fi AC_SUBST(CC_FOR_BUILD) # Also set EXEEXT_FOR_BUILD. if test "x$cross_compiling" = "xno"; then EXEEXT_FOR_BUILD='$(EXEEXT)' else AC_CACHE_CHECK([for build system executable suffix], bfd_cv_build_exeext, [rm -f conftest* echo 'int main () { return 0; }' > conftest.c bfd_cv_build_exeext= ${CC_FOR_BUILD} -o conftest conftest.c 1>&5 2>&5 for file in conftest.*; do case $file in *.c | *.o | *.obj | *.ilk | *.pdb) ;; *) bfd_cv_build_exeext=`echo $file | sed -e s/conftest//` ;; esac done rm -f conftest* test x"${bfd_cv_build_exeext}" = x && bfd_cv_build_exeext=no]) EXEEXT_FOR_BUILD="" test x"${bfd_cv_build_exeext}" != xno && EXEEXT_FOR_BUILD=${bfd_cv_build_exeext} fi AC_SUBST(EXEEXT_FOR_BUILD)])dnl cyanogilvie-teabase-9345a87/ax_check_compile_flag.m4000066400000000000000000000040701526245020600224260ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS cyanogilvie-teabase-9345a87/ax_gcc_builtin.m4000066400000000000000000000133461526245020600211400ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_gcc_builtin.html # =========================================================================== # # SYNOPSIS # # AX_GCC_BUILTIN(BUILTIN) # # DESCRIPTION # # This macro checks if the compiler supports one of GCC's built-in # functions; many other compilers also provide those same built-ins. # # The BUILTIN parameter is the name of the built-in function. # # If BUILTIN is supported define HAVE_. Keep in mind that since # builtins usually start with two underscores they will be copied over # into the HAVE_ definition (e.g. HAVE___BUILTIN_EXPECT for # __builtin_expect()). # # The macro caches its result in the ax_cv_have_ variable (e.g. # ax_cv_have___builtin_expect). # # The macro currently supports the following built-in functions: # # __builtin_assume_aligned # __builtin_bswap16 # __builtin_bswap32 # __builtin_bswap64 # __builtin_choose_expr # __builtin___clear_cache # __builtin_clrsb # __builtin_clrsbl # __builtin_clrsbll # __builtin_clz # __builtin_clzl # __builtin_clzll # __builtin_complex # __builtin_constant_p # __builtin_ctz # __builtin_ctzl # __builtin_ctzll # __builtin_expect # __builtin_ffs # __builtin_ffsl # __builtin_ffsll # __builtin_fpclassify # __builtin_huge_val # __builtin_huge_valf # __builtin_huge_vall # __builtin_inf # __builtin_infd128 # __builtin_infd32 # __builtin_infd64 # __builtin_inff # __builtin_infl # __builtin_isinf_sign # __builtin_nan # __builtin_nand128 # __builtin_nand32 # __builtin_nand64 # __builtin_nanf # __builtin_nanl # __builtin_nans # __builtin_nansf # __builtin_nansl # __builtin_object_size # __builtin_parity # __builtin_parityl # __builtin_parityll # __builtin_popcount # __builtin_popcountl # __builtin_popcountll # __builtin_powi # __builtin_powif # __builtin_powil # __builtin_prefetch # __builtin_trap # __builtin_types_compatible_p # __builtin_unreachable # # Unsupported built-ins will be tested with an empty parameter set and the # result of the check might be wrong or meaningless so use with care. # # LICENSE # # Copyright (c) 2013 Gabriele Svelto # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AC_DEFUN([AX_GCC_BUILTIN], [ AS_VAR_PUSHDEF([ac_var], [ax_cv_have_$1]) AC_CACHE_CHECK([for $1], [ac_var], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([], [ m4_case([$1], [__builtin_assume_aligned], [$1("", 0)], [__builtin_bswap16], [$1(0)], [__builtin_bswap32], [$1(0)], [__builtin_bswap64], [$1(0)], [__builtin_choose_expr], [$1(0, 0, 0)], [__builtin___clear_cache], [$1("", "")], [__builtin_clrsb], [$1(0)], [__builtin_clrsbl], [$1(0)], [__builtin_clrsbll], [$1(0)], [__builtin_clz], [$1(0)], [__builtin_clzl], [$1(0)], [__builtin_clzll], [$1(0)], [__builtin_complex], [$1(0.0, 0.0)], [__builtin_constant_p], [$1(0)], [__builtin_ctz], [$1(0)], [__builtin_ctzl], [$1(0)], [__builtin_ctzll], [$1(0)], [__builtin_expect], [$1(0, 0)], [__builtin_ffs], [$1(0)], [__builtin_ffsl], [$1(0)], [__builtin_ffsll], [$1(0)], [__builtin_fpclassify], [$1(0, 1, 2, 3, 4, 0.0)], [__builtin_huge_val], [$1()], [__builtin_huge_valf], [$1()], [__builtin_huge_vall], [$1()], [__builtin_inf], [$1()], [__builtin_infd128], [$1()], [__builtin_infd32], [$1()], [__builtin_infd64], [$1()], [__builtin_inff], [$1()], [__builtin_infl], [$1()], [__builtin_isinf_sign], [$1(0.0)], [__builtin_nan], [$1("")], [__builtin_nand128], [$1("")], [__builtin_nand32], [$1("")], [__builtin_nand64], [$1("")], [__builtin_nanf], [$1("")], [__builtin_nanl], [$1("")], [__builtin_nans], [$1("")], [__builtin_nansf], [$1("")], [__builtin_nansl], [$1("")], [__builtin_object_size], [$1("", 0)], [__builtin_parity], [$1(0)], [__builtin_parityl], [$1(0)], [__builtin_parityll], [$1(0)], [__builtin_popcount], [$1(0)], [__builtin_popcountl], [$1(0)], [__builtin_popcountll], [$1(0)], [__builtin_powi], [$1(0, 0)], [__builtin_powif], [$1(0, 0)], [__builtin_powil], [$1(0, 0)], [__builtin_prefetch], [$1("")], [__builtin_trap], [$1()], [__builtin_types_compatible_p], [$1(int, int)], [__builtin_unreachable], [$1()], [m4_warn([syntax], [Unsupported built-in $1, the test may fail]) $1()] ) ])], [AS_VAR_SET([ac_var], [yes])], [AS_VAR_SET([ac_var], [no])]) ]) AS_IF([test yes = AS_VAR_GET([ac_var])], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1), 1, [Define to 1 if the system has the `$1' built-in function])], []) AS_VAR_POPDEF([ac_var]) ]) cyanogilvie-teabase-9345a87/dbench.tcl000077500000000000000000000014261526245020600176520ustar00rootroot00000000000000#!/usr/local/bin/tclsh file mkdir /tmp/build cd /tmp/build foreach file [glob -nocomplain /src/local/*] { set fqfn [file join /src/local $file] if {[file exists $fqfn]} { exec cp -a $fqfn . } } exec -ignorestderr autoconf >@ stdout # Without --enable-symbols, tcl.m4 hard codes the flags in tclConfig.sh's CFLAGS_OPTIMIZE /after/ any value we can configure exec -ignorestderr ./configure --enable-symbols {*}[lindex $argv 1] --with-tcl=/usr/local/lib --enable-testmode >@ stdout file delete -- {*}[glob -nocomplain tools/bin/*] switch -- [lindex $argv 2] { pgo { exec -ignorestderr make clean pgo >@ stdout exec -ignorestderr make benchmark BENCHFLAGS=[lindex $argv 0] >@ stdout } default { exec -ignorestderr make clean benchmark BENCHFLAGS=[lindex $argv 0] >@ stdout } } cyanogilvie-teabase-9345a87/dbuild.tcl000077500000000000000000000017061526245020600176730ustar00rootroot00000000000000#!/usr/local/bin/tclsh package require platform puts "dbuild.tcl platform: [platform::generic]" switch -glob -- [platform::generic] { *-x86_64 { set cflags {-O3 -march=haswell} } *-aarch64 { set cflags {-O3 -moutline-atomics -march=armv8.2-a} } default { set cflags {-O3} } } file mkdir /tmp/build cd /tmp/build foreach file [glob -nocomplain /src/local/*] { set fqfn [file join /src/local $file] if {[file exists $fqfn]} { exec cp -a $fqfn . } } exec -ignorestderr autoconf >@ stdout exec -ignorestderr ./configure --enable-symbols --with-tcl=/usr/local/lib >@ stdout file delete -- {*}[glob -nocomplain tools/bin/*] exec -ignorestderr make clean install-binaries install-libraries DESTDIR=/tmp/install >@ stdout set target [file join /install [platform::generic]] file mkdir $target exec -ignorestderr sh -c "cp -a /tmp/install/usr/local/lib/* $target" >@ stdout exec -ignorestderr chown -R [lindex $argv 0]:[lindex $argv 1] $target >@ stdout cyanogilvie-teabase-9345a87/defer.h000066400000000000000000000024051526245020600171540ustar00rootroot00000000000000#ifndef _DEFER_H #define _DEFER_H #if HAVE_NATIVE_DEFER /* Compiler supports _Defer natively (e.g. clang 22+ with -fdefer-ts). * Guard against already providing this macro per the TS. */ # ifndef defer # define defer _Defer # endif #elif HAVE_DEFER_POLYFILL /* GCC polyfill using nested functions + __attribute__((cleanup)). * Credit: Jens Gustedt (author of the C2y defer proposal). * Always use braces: defer { ... } */ # define defer _Defer # define _Defer _Defer_A(__COUNTER__) # define _Defer_A(N) _Defer_B(N) # define _Defer_B(N) _Defer_C(_Defer_func_ ## N, _Defer_var_ ## N) # define _Defer_C(F, V) \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \ auto void F(int*); \ __attribute__((__cleanup__(F), __deprecated__, __unused__)) \ int V; \ __attribute__((__always_inline__, __deprecated__, __unused__)) \ inline auto void F(__attribute__((__unused__)) int*V) #else # error "No defer support available" #endif #endif /* _DEFER_H */ cyanogilvie-teabase-9345a87/dtest.tcl000077500000000000000000000007321526245020600175510ustar00rootroot00000000000000#!/usr/local/bin/tclsh file mkdir /tmp/build cd /tmp/build foreach file [glob -nocomplain /src/local/*] { set fqfn [file join /src/local $file] if {[file exists $fqfn]} { exec cp -r $fqfn . } } exec -ignorestderr autoconf >@ stdout exec -ignorestderr ./configure --enable-symbols --with-tcl=/usr/local/lib --enable-testmode >@ stdout file delete -force -- {*}[glob -nocomplain tools/bin/*] local exec -ignorestderr make clean test TESTFLAGS=[lindex $argv 0] >@ stdout cyanogilvie-teabase-9345a87/getbytes.h000066400000000000000000000036361526245020600177240ustar00rootroot00000000000000#ifndef _GETBYTES_H #define _GETBYTES_H #if GETBYTES_SHIM #include #include /* * Polyfill for Tcl_GetBytesFromObj, added in Tcl 8.7/9.0. Returns the * byte-array interpretation of obj, or NULL (with a TCL VALUE BYTES * errorCode and readable error message) if the string representation * contains any characters outside the 0..255 range. * * This matches Tcl 9's Tcl_GetBytesFromObj semantics. Older * Tcl_GetByteArrayFromObj accepted any string, silently truncating * Unicode characters to their low 8 bits — which is usually wrong when * the caller wanted "bytes or error". */ static inline uint8_t* Tcl_GetBytesFromObj(Tcl_Interp* interp, Tcl_Obj* obj, Tcl_Size* lenPtr) { Tcl_Size bytelen; uint8_t* bytes; /* Already a bytearray internal rep — no validation needed. */ if (obj->typePtr != NULL && strcmp(obj->typePtr->name, "bytearray") == 0) { bytes = Tcl_GetByteArrayFromObj(obj, &bytelen); if (lenPtr) *lenPtr = bytelen; return bytes; } /* * Validate the string rep is pure-byte before shimmering to bytearray. * The error message matches Tcl 9's Tcl_GetBytesFromObj: the index * is the number of valid bytes seen so far (one per ch<=0xFF), and * the bad-character field is the tail of the string starting at the * offending character. */ int strlen_int; const char* str = Tcl_GetStringFromObj(obj, &strlen_int); int good = 0; for (int i=0; i < strlen_int; ) { Tcl_UniChar ch; int chlen = Tcl_UtfToUniChar(str + i, &ch); if (ch > 0xFF) { if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "expected byte sequence but character %d was '%s' (U+%06X)", good, str + i, (int)ch)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "BYTES", NULL); } return NULL; } i += chlen; good++; } bytes = Tcl_GetByteArrayFromObj(obj, &bytelen); if (lenPtr) *lenPtr = bytelen; return bytes; } #endif /* GETBYTES_SHIM */ #endif /* _GETBYTES_H */ cyanogilvie-teabase-9345a87/init/000077500000000000000000000000001526245020600166605ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/init/meson.build000066400000000000000000000272251526245020600210320ustar00rootroot00000000000000teabase_initialized = true if not is_variable('deps') deps = [] endif if not is_variable('tea_want_shims') tea_want_shims = [] endif # Tcl-package dependencies needed at test/benchmark time, expressed as # meson dependency() objects. teabase reads `tcl_pkg_path` (binary # packages — added to TCLLIBPATH) and `tcl_tm_path` (pure-Tcl .tm # modules — added to TCL__TM_PATH) from each dep's variables; # same names are used in .pc files and in declare_dependency(variables:) # subproject fallbacks. Any dep that exports neither is ignored. # # tea_bench_deps is conceptually additive to tea_test_deps (benchmarks # inherit the test deps). Keeping them separate lets a project add # heavyweight bench-only fixtures that aren't fetched/built when only # `meson test` runs. if not is_variable('tea_test_deps') tea_test_deps = [] endif if not is_variable('tea_bench_deps') tea_bench_deps = [] endif # Extra build targets (executables, custom_targets, shared_modules ...) # that must exist before `meson test` runs. For tools accessed via # tea_host_env's PATH (re2c, packcc, ...) and for subproject-fallback # Tcl packages whose underlying targets would otherwise not get built # (tea_test_deps holds dependency() objects, which can't appear in a # test()'s `depends:` list). # # tea_bench_extra_depends is the bench-only counterpart, also additive: # `meson test --benchmark` builds tea_extra_depends + tea_bench_extra_depends. if not is_variable('tea_extra_depends') tea_extra_depends = [] endif if not is_variable('tea_bench_extra_depends') tea_bench_extra_depends = [] endif # Live host env (used for configure-time run_command and meson.add_devenv). # Mutations to tea_host_env are mirrored into tea_host_env_ops so we can # replay the same modifications onto fresh environment objects later. # meson's environment() can't be cloned and stores a reference (not a # snapshot) when passed to test() — without an op log there's no way to # build distinct test_env / bench_env objects with overlapping content. # Each entry: {'op': 'set' | 'prepend', 'var': str, 'value': str} if not is_variable('tea_host_env') tea_host_env = environment() endif if not is_variable('tea_host_env_ops') tea_host_env_ops = [] endif if not is_variable('tea_build_env') tea_build_env = environment() endif add_project_arguments('-DHAVE_CONFIG_H=1', language: 'c') tcl_dep = dependency('tcl') if tcl_dep.type_name() == 'internal' pkg_dir = 'lib' / meson.project_name()+'-'+meson.project_version() else pkg_dir = tcl_dep.get_variable('libdir') / meson.project_name()+'-'+meson.project_version() endif # Use tcl_dep for compile args (includes) only, link against stubs library tcl_hdr_dep = tcl_dep.partial_dependency(compile_args: true, includes: true) deps += tcl_hdr_dep if tcl_dep.type_name() == 'internal' # Subproject fallback: stubs library is already part of tcl_dep deps += tcl_dep.partial_dependency(links: true) else # Distro packages provide an unversioned libtclstub.a; a source-built Tcl # installs only libtclstub..a (and Windows builds # tclstub). Tcl's minor versions are single digits, which # also drops an alpha/beta suffix ("8.7a2"). _tcl_v = tcl_dep.version().split('.') _tcl_mm = [_tcl_v[0], _tcl_v.length() > 1 ? _tcl_v[1].substring(0, 1) : '0'] _tcl_libdir = tcl_dep.get_variable('libdir') _stub_dep = disabler() foreach _name : ['tclstub', 'tclstub' + '.'.join(_tcl_mm), 'tclstub' + ''.join(_tcl_mm)] _stub_dep = cc.find_library(_name, dirs: [_tcl_libdir], required: false) if _stub_dep.found() break endif endforeach if not _stub_dep.found() error('Tcl stubs library not found in @0@ (tried tclstub, tclstub@1@, tclstub@2@)'.format( _tcl_libdir, '.'.join(_tcl_mm), ''.join(_tcl_mm))) endif deps += _stub_dep endif add_project_arguments('-DUSE_TCL_STUBS=1', language: 'c') add_project_arguments('-DUSE_TCL_STUBS=1', language: 'cpp') if 'hedley' in tea_want_shims hedley_dep = dependency('hedley', version: '>=15', allow_fallback: true, required: false) if hedley_dep.found() deps += hedley_dep add_project_arguments('-DHAVE_HEDLEY_H', language: 'c') add_project_arguments('-DHAVE_HEDLEY_H', language: 'cpp') endif endif teaconf = conf teaconf.set('PACKAGE_NAME', meson.project_name()) teaconf.set('PACKAGE_VERSION', meson.project_version()) conf.set_quoted('PACKAGE_NAME', meson.project_name()) conf.set_quoted('PACKAGE_VERSION', meson.project_version()) # Polyfill checks look only at Tcl's headers (has_header_symbol compiles but # doesn't link: the symbol counts whether tclDecls.h declares it or, in stubs # mode, #defines it), so they give the same answer for 8.6 and 9, stubs or not, # a shared or static-only libtcl, and a subproject fallback (whose internal # dependency is usable here once reduced to its include/compile args). Don't # use has_function: it links against libtcl, which fails spuriously when that # needs more than -ltcl (a static libtcl9.0.a wants -lz -lpthread ...), and a # failed link wrongly enables a shim whose typedefs then clash with Tcl 9's. # # They're cheap, so they run whether or not the project lists the shim in # tea_want_shims: teabase's own sources (instance_tracking.c) include tip445.h, # and including tip445.h / getbytes.h is a no-op where Tcl has the API. conf.set10('TIP445_SHIM', not cc.has_header_symbol('tcl.h', 'Tcl_FetchInternalRep', dependencies: tcl_hdr_dep)) conf.set10('GETBYTES_SHIM', not cc.has_header_symbol('tcl.h', 'Tcl_GetBytesFromObj', dependencies: tcl_hdr_dep)) if tcl_dep.type_name() != 'internal' if not cc.compiles('#include \nTcl_Size foo=0;', dependencies: tcl_dep) conf.set('Tcl_Size', 'int') endif if not cc.has_header_symbol('tcl.h', 'TCL_SIZE_MODIFIER', dependencies: tcl_dep) conf.set('TCL_SIZE_MODIFIER', '""') endif if not cc.has_define('MODULE_SCOPE', prefix: '#include ', dependencies: tcl_dep) add_project_arguments('-DMODULE_SCOPE=extern', language: 'c') add_project_arguments('-DMODULE_SCOPE=extern "C"', language: 'cpp') endif # Detect libtommath configuration when requested by the consuming project. # Set tea_want_tommath = true before subdir('teabase/init') to enable. if is_variable('tea_want_tommath') and tea_want_tommath # tclTomMath.h may #include "tommath.h" which may not be installed # even when Tcl has internal tommath. Probe first to avoid a hard # error from has_define / sizeof. _tommath_hdr_ok = cc.compiles( '#include \n#include \nmp_digit d;', name: 'tclTomMath.h usable', dependencies: tcl_dep, ) if _tommath_hdr_ok tcl_has_internal_tommath = not cc.has_define('TCL_WITH_EXTERNAL_TOMMATH', prefix: '#include ', dependencies: tcl_dep) tcl_mp_digit_size = cc.sizeof('mp_digit', prefix: '#include \n#include ', dependencies: tcl_dep) else # Header broken or missing tommath.h — assume internal tommath tcl_has_internal_tommath = true tcl_mp_digit_size = cc.sizeof('size_t') endif endif else # Internal subproject provides Tcl 9 source — all features present if is_variable('tea_want_tommath') and tea_want_tommath tcl_has_internal_tommath = true tcl_mp_digit_size = cc.sizeof('size_t') endif endif # defer.h support: set tea_want_defer = true before subdir('teabase/init') to # enable #include "teabase/defer.h". Detects either native _Defer (clang 22+, # with or without -fdefer-ts), or GCC nested-function + cleanup-attribute # polyfill. Errors if neither is available. if is_variable('tea_want_defer') and tea_want_defer _defer_native = ''' int main(void) { int x = 0; _Defer { x = 1; } return x; } ''' _defer_polyfill = ''' void cleanup(int *p) { (void)p; } int main(void) { __attribute__((__cleanup__(cleanup))) int x; auto void f(int*); inline auto void f(__attribute__((__unused__)) int *p) {} return 0; } ''' if cc.compiles(_defer_native, name: 'native _Defer') conf.set10('HAVE_NATIVE_DEFER', true) elif cc.compiles(_defer_native, args: ['-fdefer-ts'], name: 'native _Defer (-fdefer-ts)') conf.set10('HAVE_NATIVE_DEFER', true) add_project_arguments('-fdefer-ts', language: 'c') elif cc.compiles(_defer_polyfill, name: 'GCC defer polyfill support') conf.set10('HAVE_DEFER_POLYFILL', true) else error('No defer support: need _Defer (clang 22+ with -fdefer-ts) or GCC 9+ nested functions') endif endif tclver_full = tcl_dep.version() tclver_parts = tclver_full.split('.') tclver_major = tclver_parts[0] tclver_minor = tclver_parts[1] # Strip alpha/beta suffixes tclver_minor = tclver_minor.split('a')[0].split('b')[0].split('rc')[0] tclver = tclver_major + '.' + tclver_minor exe_suffix = host_machine.system() == 'windows' ? '.exe' : '' exec_prefix = tcl_dep.get_variable('exec_prefix') tclsh_search = [] foreach name : [ exec_prefix / 'bin/tclsh', exec_prefix / 'tclsh', 'tclsh', ] tclsh_search += [ name + tclver + exe_suffix, name + exe_suffix, ] endforeach if tclver_major.to_int() >= 9 tea_pkg_so_name = 'tcl9' + meson.project_name() else tea_pkg_so_name = meson.project_name() endif tea_pkg_stub_name = meson.project_name() + 'stub' conf.set_quoted('PACKAGE_LIBNAME', tea_pkg_so_name) conf.set_quoted('PACKAGE_STUBLIB', tea_pkg_stub_name) tcl_is_internal = tcl_dep.type_name() == 'internal' if tcl_is_internal # Get the host tclsh directly from the subproject. For tests this # runs via the exe_wrapper in cross builds. build_tclsh (used in # run_command at configure time) can't be a compiled target, so it's # only set in native builds where the subproject's tclsh IS a native # program. tcl_subproj = subproject('tcl') tclsh = tcl_subproj.get_variable('tclsh_exe') _tcl_lib = tcl_subproj.get_variable('tcl_library') _tcl_pre = tcl_subproj.get_variable('exec_prefix') tea_host_env.set('TCL_LIBRARY', _tcl_lib) tea_host_env.prepend('PATH', _tcl_pre) tea_host_env_ops += [ {'op': 'set', 'var': 'TCL_LIBRARY', 'value': _tcl_lib}, { 'var': 'PATH', 'value': _tcl_pre}, ] build_tclsh = tclsh tea_build_env.set('TCL_LIBRARY', _tcl_lib) tea_build_env.prepend('PATH', _tcl_pre) else tclsh = find_program(tclsh_search, native: false, required: false) if tclsh.found() and meson.can_run_host_binaries() if run_command(tclsh, '../tools/check_ver.tcl', tclver, check: false, env: tea_host_env).returncode() != 0 error('Tcl version of found tclsh: '+tclsh.full_path()+' does not match the Tcl version of the Tcl dependency: ' + tclver) endif build_tclsh = tclsh endif if not is_variable('build_tclsh') # Try to find a build machine tclsh for configure-time scripts exe_suffix = build_machine.system() == 'windows' ? '.exe' : '' exec_prefix = tcl_dep.get_variable('exec_prefix') tclsh_search = [] foreach name : [ exec_prefix / 'bin/tclsh', exec_prefix / 'tclsh', 'tclsh', ] tclsh_search += [ name + tclver + exe_suffix, name + exe_suffix, ] endforeach build_tclsh = find_program(tclsh_search, native: true, required: false) if build_tclsh.found() if run_command(build_tclsh, '../tools/check_ver.tcl', tclver, check: false, env: tea_build_env).returncode() != 0 error('Tcl version of found tclsh: '+build_tclsh.full_path()+' does not match the Tcl version of the Tcl dependency: ' + tclver) endif endif endif if tclsh.found() _tclsh_dir = fs.parent(tclsh.full_path()) tea_host_env.prepend('PATH', _tclsh_dir) tea_host_env_ops += {'var': 'PATH', 'value': _tclsh_dir} endif if build_tclsh.found() tea_build_env.prepend('PATH', fs.parent(build_tclsh.full_path())) endif endif cyanogilvie-teabase-9345a87/instance_tracking.c000066400000000000000000000056451526245020600215610ustar00rootroot00000000000000#include #include #include "tip445.h" // Tcl_FreeInternalRep on Tcl 8.6 void register_instance(struct tracked_instances* instances, Tcl_Obj* obj, void* inst /* if NULL: use hash tracking */) { // Splice this instance before the tail sentinel Tcl_MutexLock(&instances->mtx); if (inst) { struct tracked_instance* i = inst; *i = (struct tracked_instance){ .self = obj, .prev = instances->tail.prev, .next = &instances->tail, }; i->prev->next = i; i->next->prev = i; } else { int isnew; (void)Tcl_CreateHashEntry(&instances->hashtable, obj, &isnew); if (!isnew) Tcl_Panic("Obj %p already registered", (void*)obj); } Tcl_MutexUnlock(&instances->mtx); } void forget_instance(struct tracked_instances* instances, Tcl_Obj* obj, void* inst /* if NULL: use hash tracking */) { Tcl_MutexLock(&instances->mtx); if (inst) { struct tracked_instance* i = inst; i->prev->next = i->next; i->next->prev = i->prev; i->next = NULL; i->prev = NULL; i->self = NULL; } else { Tcl_HashEntry* he = Tcl_FindHashEntry(&instances->hashtable, obj); if (!he) Tcl_Panic("Obj %p not registered", (void*)obj); Tcl_DeleteHashEntry(he); } Tcl_MutexUnlock(&instances->mtx); } void init_instance_tracking(struct tracked_instances* instances) { if (!instances->head.next) { Tcl_MutexLock(&instances->mtx); if (!instances->head.next) { instances->head.next = &instances->tail; instances->tail.prev = &instances->head; Tcl_InitHashTable(&instances->hashtable, TCL_ONE_WORD_KEYS); } Tcl_MutexUnlock(&instances->mtx); } } void finalize_instance_tracking(struct tracked_instances* instances) { Tcl_MutexLock(&instances->mtx); if (instances->head.next) { struct tracked_instance* s = instances->head.next; // First pass: ensure everything has a string rep (reduce thrashing during freeintrep pass) while (s->next) { Tcl_GetString(s->self); // Ensure string rep exists s = s->next; } // Second pass: remove intrep s = instances->head.next; while (s->next) { Tcl_GetString(s->self); // Should always be a nop, here in case of pathological free_intrep interactions Tcl_FreeInternalRep(s->self); s = instances->head.next; } Tcl_HashSearch search; Tcl_HashEntry* he = NULL; // First pass: ensure everything has a string rep (reduce thrashing during freeintrep pass) for (he = Tcl_FirstHashEntry(&instances->hashtable, &search); he; he=Tcl_NextHashEntry(&search)) { Tcl_Obj* obj = Tcl_GetHashKey(&instances->hashtable, he); Tcl_GetString(obj); } // Second pass: remove intrep while ((he = Tcl_FirstHashEntry(&instances->hashtable, &search))) { Tcl_Obj* obj = Tcl_GetHashKey(&instances->hashtable, he); Tcl_GetString(obj); // Should always be a nop, here in case of pathological free_intrep interactions Tcl_FreeInternalRep(obj); } Tcl_DeleteHashTable(&instances->hashtable); } Tcl_MutexUnlock(&instances->mtx); Tcl_MutexFinalize(&instances->mtx); } cyanogilvie-teabase-9345a87/instance_tracking.h000066400000000000000000000017321526245020600215570ustar00rootroot00000000000000#ifndef TEABASE_INSTANCE_TRACKING_H #define TEABASE_INSTANCE_TRACKING_H #include struct tracked_instance { // linked list accounting for all live Tcl values of our ObjType(s), to degrade to pure strings before we leave struct tracked_instance* next; struct tracked_instance* prev; Tcl_Obj* self; // No reference held (would create circular references) }; struct tracked_instances { Tcl_Mutex mtx; struct tracked_instance head; struct tracked_instance tail; Tcl_HashTable hashtable; // Alternateive mechanism for ObjTypes that have nowhere to put a struct tracked_instance }; void register_instance(struct tracked_instances* instances, Tcl_Obj* obj, void* inst /* if NULL: use hash tracking */); void forget_instance(struct tracked_instances* instances, Tcl_Obj* obj, void* inst /* if NULL: use hash tracking */); void init_instance_tracking(struct tracked_instances* instances); void finalize_instance_tracking(struct tracked_instances* instances); #endif cyanogilvie-teabase-9345a87/meson.build000066400000000000000000000302141526245020600200570ustar00rootroot00000000000000if not is_variable('teabase_initialized') subdir('init') endif inc += include_directories('.') inc += include_directories('pkg_config_h') if is_variable('tea_genstubs') genstubs = custom_target('genstubs', output: [meson.project_name() + 'StubInit.c', meson.project_name() + 'Decls.h'], command: [ build_tclsh, files('tools/genStubs.tcl'), meson.current_build_dir(), tea_genstubs[0] ], install: true, install_tag: [false, meson.is_subproject() ? 'deps' : 'runtime'], install_dir: [false, pkg_dir], env: tea_build_env, ) deps += declare_dependency(sources: genstubs) # Build and install stubs library for dependent extensions. # The stub lib is just the function-pointer table plus a one-line init # function — there is nothing to step into, nothing to optimize across, and # nothing to link. Three things would otherwise bloat a ~1.5KB archive to # hundreds of KB: # # 1. Compile flags that serialize the entire TclStubs type surface (~600 # typed function pointers, plus every visible macro) that the included # headers (tcl.h + generated Decls.h) pull in: # -g/-ggdb3 (debug buildtypes) -> DWARF type + macro info # -flto -ffat-lto-objects (env CFLAGS, e.g. the alpine-tcl release # build) -> embedded GIMPLE LTO IR # (.gnu.lto_* sections) # Force -g0 and -fno-lto so the lib stays tiny regardless of buildtype or # inherited CFLAGS. These land after env CFLAGS on the command line # (target c_args have higher precedence in meson), so they win. # # 2. Link dependencies folded in via `deps`. The stub lib needs only the # headers and the generated StubInit.c source; it links nothing. Passing # the full `deps` (which carries link_with static libs like libtcc) would # fold those archives' objects into this one. Take a partial_dependency # keeping compile args / includes / sources but dropping the links. stub_deps = [] foreach _d : deps stub_deps += _d.partial_dependency( compile_args: true, includes: true, sources: true, ) endforeach stubs_lib = static_library(tea_pkg_stub_name, tea_genstubs[1], dependencies: stub_deps, include_directories: inc, c_args: cc.get_supported_arguments('-g0', '-fno-lto'), install: true, install_dir: pkg_dir, install_tag: meson.is_subproject() ? 'deps' : 'runtime', ) endif pkg_so = shared_module(tea_pkg_so_name, pkg_sources, install: true, install_dir: pkg_dir, install_tag: meson.is_subproject() ? 'deps' : 'runtime', dependencies: deps, include_directories: inc, ) _pkg_lib_file = fs.name(pkg_so.full_path()) _pname = meson.project_name() teaconf.set('PKG_LIB_FILE', _pkg_lib_file) # Also expose as a C string macro for extensions that need to know their # own on-disk filename at runtime (e.g. to advertise a link-name matching # the in-memory copy for consumers that generate and load code dynamically). conf.set_quoted('PKG_LIB_FILE', _pkg_lib_file) # TEA convention: Tcl 8 libs are "lib.so", Tcl 9 are "libtcl9.so". # Both names are always provided so that two builds (one per Tcl major version) # can be installed side by side in the same package directory. if tclver_major.to_int() >= 9 _base = _pkg_lib_file.replace('tcl9' + _pname, _pname) else _base = _pkg_lib_file endif teaconf.set('PKG_LIB_FILE8', _base) teaconf.set('PKG_LIB_FILE9', _base.replace(_pname, 'tcl9' + _pname)) if not is_variable('teaconf_files') teaconf_files = [] endif teaconf_files += files('../pkgIndex.tcl.in') foreach f : teaconf_files fname = fs.name(f) configure_file(input: f, output: fname.endswith('.in') ? '@BASENAME@' : fname, configuration: teaconf, install: true, install_dir: pkg_dir, install_tag: meson.is_subproject() ? 'deps' : 'runtime', ) endforeach # Arrange for our the package path to be first in $::auto_path and to be # able to load any subproject packages. # Mirror this build dir into the host env (so devenv tclsh and # configure-time run_command can find the just-built package), and # record the same op so derived test/bench envs replay it. tea_host_env.prepend('TCLLIBPATH', meson.current_build_dir(), separator: ' ') tea_host_env_ops += {'var': 'TCLLIBPATH', 'value': meson.current_build_dir()} # Translate a list of tea_*_deps dependency() objects into env-mod ops: # tcl_pkg_path -> TCLLIBPATH (binary `package require` packages) # tcl_tm_path -> TCL__TM_PATH (pure-Tcl .tm modules) # Same variable names land in pkg-config (.pc) files and in subproject # declare_dependency(variables: {...}), so this works uniformly for # system installs and fallbacks. Deps exporting neither (e.g. plain C # libraries like libtcc) are silently skipped. _tm_path_var = 'TCL' + tclver_major + '_' + tclver_minor + '_TM_PATH' _test_dep_ops = [] _bench_dep_ops = [] foreach _dep : tea_test_deps _pkg_path = _dep.get_variable('tcl_pkg_path', default_value: '') if _pkg_path != '' _test_dep_ops += {'var': 'TCLLIBPATH', 'value': _pkg_path} endif _tm_path = _dep.get_variable('tcl_tm_path', default_value: '') if _tm_path != '' _test_dep_ops += {'var': _tm_path_var, 'value': _tm_path} endif endforeach foreach _dep : tea_bench_deps _pkg_path = _dep.get_variable('tcl_pkg_path', default_value: '') if _pkg_path != '' _bench_dep_ops += {'var': 'TCLLIBPATH', 'value': _pkg_path} endif _tm_path = _dep.get_variable('tcl_tm_path', default_value: '') if _tm_path != '' _bench_dep_ops += {'var': _tm_path_var, 'value': _tm_path} endif endforeach # Write a sentinel file with the meson build root so that package init # scripts can locate build-dir or source artifacts. Not installed. _builddir_conf = configuration_data() _builddir_conf.set('BUILDDIR', meson.project_build_root()) _builddir_conf.set('SOURCEDIR', meson.global_source_root()) configure_file( output: '__builddir', configuration: _builddir_conf, input: '__builddir.in', ) configure_file( output: '__srcdir', configuration: _builddir_conf, input: '__srcdir.in', ) if tclsh.found() and not meson.is_subproject() # Build test_env and bench_env as fresh environment() objects rather # than aliasing tea_host_env. meson stores the env arg to test() by # reference (not as a snapshot), so any later modification — like # adding bench-only deps for benchmark() — would leak back into the # already-registered test(). Replaying tea_host_env_ops keeps base # PATH/TCLLIBPATH/TCL_LIBRARY content intact in both, while each env # gets only the dep additions appropriate for its scope. test_env = environment() foreach _op : tea_host_env_ops + _test_dep_ops if 'op' in _op and _op['op'] == 'set' test_env.set(_op['var'], _op['value']) else # 'prepend' if _op['var'] == 'TCLLIBPATH' test_env.prepend(_op['var'], _op['value'], separator: ' ') else test_env.prepend(_op['var'], _op['value']) endif endif endforeach test_env.set('ERROR_ON_FAILURES', '1') bench_env = environment() foreach _op : tea_host_env_ops + _test_dep_ops + _bench_dep_ops if 'op' in _op and _op['op'] == 'set' bench_env.set(_op['var'], _op['value']) else # 'prepend' if _op['var'] == 'TCLLIBPATH' bench_env.prepend(_op['var'], _op['value'], separator: ' ') else bench_env.prepend(_op['var'], _op['value']) endif endif endforeach bench_env.set('ERROR_ON_FAILURES', '1') # Compose the tcltest -load script: source the generated pkgIndex.tcl # from the build dir and require the package under test. Driving # tclsh directly (via the thin test_preamble.tcl below — in-process # `source`, not a subprocess) means `meson test --test-args` flows # through to tcltest's configure, and `meson test --wrapper valgrind` # instruments the tclsh running the tests without --trace-children. # The -load script itself gets re-used verbatim by tcltest when it # spawns per-file subprocesses under `singleProcess 0`, so keep it # self-contained (no reliance on anything the preamble sets up). # # Path and package name are interpolated inside Tcl {...} brace # quoting, which is literal except for brace matching — so we only # need to backslash-escape any braces they contain. # # The pkgIndex.tcl file expects `$dir` to be the directory that # contains it (Tcl's normal package-require machinery sets this). # Source it via [apply] with a dir argument so `$dir` is bound # locally to the build dir; otherwise the source fails with # "can't read $dir", tcltest swallows it, and the fallback # `package require` in loadtdom.tcl silently loads an installed # copy of the package instead of the one we just built. _pkgdir_esc = meson.current_build_dir() \ .replace('{', '\\{').replace('}', '\\}') _pname_esc = meson.project_name() \ .replace('{', '\\{').replace('}', '\\}') _loadscript = 'apply {dir {' \ + 'source [file join $dir pkgIndex.tcl]; ' \ + 'package require -exact {' + _pname_esc + '} ' \ + meson.project_version() \ + '}} {' + _pkgdir_esc + '}' _test_deps_met = true foreach _dep : tea_test_deps if not _dep.found() _test_deps_met = false endif endforeach if _test_deps_met test('tcltest', tclsh, args: [ # test_preamble.tcl splices $env(TESTFLAGS) onto $::argv before # sourcing tests/all.tcl, preserving the backwards-compatible way # of injecting top-level tcltest options (like -match / -file) — # those have to land in argv *before* the test script's own # `configure {*}$argv` runs, which is too early for the -load # script hook to reach. meson.current_source_dir() / 'tools/test_preamble.tcl', meson.project_source_root() / 'tests/all.tcl', '-load', _loadscript, ], verbose: true, depends: [pkg_so] + tea_extra_depends, env: test_env, ) endif _bench_deps_met = true foreach _dep : tea_bench_deps if not _dep.found() _bench_deps_met = false endif endforeach if _bench_deps_met benchmark('bench', tclsh, depends: [pkg_so] + tea_extra_depends + tea_bench_extra_depends, args: [ meson.project_source_root() / 'teabase/run_bench.tcl', '-load', _loadscript, ], verbose: true, workdir: meson.project_source_root() / 'bench', timeout: 120, env: bench_env, ) endif vim = find_program('vim', version: '>=8.1', native: true, required: false) if not vim.found() vim = find_program('nvim', version: '>=0.4', native: true, required: false) endif if vim.found() and not tcl_is_internal and is_variable('build_tclsh') and build_tclsh.found() termdebug_arg = run_command(build_tclsh, meson.current_source_dir() / 'tools/make_termdebug_arg.tcl', meson.current_build_dir(), meson.project_source_root(), tclsh.full_path(), meson.project_name(), meson.project_version(), check: true, env: tea_build_env, ).stdout().strip() td_conf = configuration_data() td_conf.set('TERMDEBUG_ARG', termdebug_arg) termdebug_vim = configure_file( input: 'termdebug.vim.in', output: 'termdebug.vim', configuration: td_conf, ) message('Found Vim/Neovim: ' + vim.full_path() + ' for vim-gdb target') run_target('vim-gdb', command: [vim, '-S', termdebug_vim], ) endif endif subdir('pkg_config_h') # Fold test/bench dep additions into tea_host_env now that test/bench # environments have been built fresh (so they aren't affected by these # late mutations). devenv-launched tclsh ought to see the same package # search paths as bench_env — important for subproject-fallback deps # that aren't system-installed. foreach _op : _test_dep_ops + _bench_dep_ops if 'op' in _op and _op['op'] == 'set' tea_host_env.set(_op['var'], _op['value']) else if _op['var'] == 'TCLLIBPATH' tea_host_env.prepend(_op['var'], _op['value'], separator: ' ') else tea_host_env.prepend(_op['var'], _op['value']) endif endif endforeach meson.add_devenv(tea_host_env) cyanogilvie-teabase-9345a87/names.c000066400000000000000000000570601526245020600171740ustar00rootroot00000000000000#define _POSIX_C_SOURCE 200809L #define _XOPEN_SOURCE 700 #include #include "names.h" #include #include #include #include int adjectivesc = 0; static const char* adjectives[] = { "Different", "Used", "Important", "Every", "Large", "Available", "Popular", "Able", "Basic", "Known", "Various", "Difficult", "Several", "United", "Historical", "Hot", "Useful", "Mental", "Scared", "Additional", "Emotional", "Old", "Political", "Similar", "Healthy", "Financial", "Medical", "Traditional", "Federal", "Entire", "Strong", "Actual", "Significant", "Successful", "Electrical", "Expensive", "Pregnant", "Intelligent", "Interesting", "Poor", "Happy", "Responsible", "Cute", "Helpful", "Recent", "Willing", "Nice", "Wonderful", "Impossible", "Serious", "Huge", "Rare", "Technical", "Typical", "Competitive", "Critical", "Electronic", "Immediate", "Aware", "Educational", "Environmental", "Global", "Legal", "Relevant", "Accurate", "Capable", "Dangerous", "Dramatic", "Efficient", "Powerful", "Foreign", "Hungry", "Practical", "Psychological", "Severe", "Suitable", "Numerous", "Sufficient", "Unusual", "Consistent", "Cultural", "Existing", "Famous", "Pure", "Afraid", "Obvious", "Careful", "Latter", "Unhappy", "Acceptable", "Aggressive", "Boring", "Distinct", "Eastern", "Logical", "Reasonable", "Strict", "Administrative", "Automatic", "Civil", "Former", "Massive", "Southern", "Unfair", "Visible", "Alive", "Angry", "Desperate", "Exciting", "Friendly", "Lucky", "Realistic", "Sorry", "Ugly", "Unlikely", "Anxious", "Comprehensive", "Curious", "Impressive", "Informal", "Inner", "Pleasant", "Sexual", "Sudden", "Terrible", "Unable", "Weak", "Wooden", "Asleep", "Confident", "Conscious", "Decent", "Embarrassed", "Guilty", "Lonely", "Mad", "Nervous", "Odd", "Remarkable", "Substantial", "Suspicious", "Tall", "Tiny", "More", "Some", "One", "All", "Many", "Most", "Other", "Such", "Even", "New", "Just", "Good", "Any", "Each", "Much", "Own", "Great", "Another", "Same", "Few", "Free", "Right", "Still", "Best", "Public", "Human", "Both", "Local", "Sure", "Better", "General", "Specific", "Enough", "Long", "Small", "Less", "High", "Certain", "Little", "Common", "Next", "Simple", "Hard", "Past", "Big", "Possible", "Particular", "Real", "Major", "Personal", "Current", "Left", "National", "Least", "Natural", "Physical", "Short", "Last", "Single", "Individual", "Main", "Potential", "Professional", "International", "Lower", "Open", "According", "Alternative", "Special", "Working", "True", "Whole", "Clear", "Dry", "Easy", "Cold", "Commercial", "Full", "Low", "Primary", "Worth", "Necessary", "Positive", "Present", "Close", "Creative", "Green", "Late", "Fit", "Glad", "Proper", "Complex", "Content", "Due", "Effective", "Middle", "Regular", "Fast", "Independent", "Original", "Wide", "Beautiful", "Complete", "Active", "Negative", "Safe", "Visual", "Wrong", "Ago", "Quick", "Ready", "Straight", "White", "Direct", "Excellent", "Extra", "Junior", "Pretty", "Unique", "Classic", "Final", "Overall", "Private", "Separate", "Western", "Alone", "Familiar", "Official", "Perfect", "Bright", "Broad", "Comfortable", "Flat", "Rich", "Warm", "Young", "Heavy", "Valuable", "Correct", "Leading", "Slow", "Clean", "Fresh", "Normal", "Secret", "Tough", "Brown", "Cheap", "Deep", "Objective", "Secure", "Thin", "Chemical", "Cool", "Extreme", "Exact", "Fair", "Fine", "Formal", "Opposite", "Remote", "Total", "Vast", "Lost", "Smooth", "Dark", "Double", "Equal", "Firm", "Frequent", "Internal", "Sensitive", "Constant", "Minor", "Previous", "Raw", "Soft", "Solid", "Weird", "Amazing", "Annual", "Busy", "Dead", "False", "Round", "Sharp", "Thick", "Wise", "Equivalent", "Initial", "Narrow", "Nearby", "Proud", "Spiritual", "Wild", "Adult", "Apart", "Brief", "Crazy", "Prior", "Rough", "Sad", "Sick", "Strange", "External", "Illegal", "Loud", "Mobile", "Nasty", "Ordinary", "Royal", "Senior", "Super", "Tight", "Upper", "Yellow", "Dependent", "Funny", "Gross", "Ill", "Spare", "Sweet", "Upstairs", "Usual", "Brave", "Calm", "Dirty", "Downtown", "Grand", "Honest", "Loose", "Male", "Quiet", "Brilliant", "Dear", "Drunk", "Empty", "Female", "Inevitable", "Neat", "Ok", "Representative", "Silly", "Slight", "Smart", "Stupid", "Temporary", "Weekly", "That", "This", "What", "Which", "Time", "These", "Work", "No", "Only", "Then", "First", "Money", "Over", "Business", "His", "Game", "Think", "After", "Life", "Day", "Home", "Economy", "Away", "Either", "Fat", "Key", "Training", "Top", "Level", "Far", "Fun", "House", "Kind", "Future", "Action", "Live", "Period", "Subject", "Mean", "Stock", "Chance", "Beginning", "Upset", "Chicken", "Head", "Material", "Salt", "Car", "Appropriate", "Inside", "Outside", "Standard", "Medium", "Choice", "North", "Square", "Born", "Capital", "Shot", "Front", "Living", "Plastic", "Express", "Feeling", "Otherwise", "Plus", "Savings", "Animal", "Budget", "Minute", "Character", "Maximum", "Novel", "Plenty", "Select", "Background", "Forward", "Glass", "Joint", "Master", "Red", "Vegetable", "Ideal", "Kitchen", "Mother", "Party", "Relative", "Signal", "Street", "Connect", "Minimum", "Sea", "South", "Status", "Daughter", "Hour", "Trick", "Afternoon", "Gold", "Mission", "Agent", "Corner", "East", "Neither", "Parking", "Routine", "Swimming", "Winter", "Airline", "Designer", "Dress", "Emergency", "Evening", "Extension", "Holiday", "Horror", "Mountain", "Patient", "Proof", "West", "Wine", "Expert", "Native", "Opening", "Silver", "Waste", "Plane", "Leather", "Purple", "Specialist", "Bitter", "Incident", "Motor", "Pretend", "Prize", "Resident", NULL }; int nounsc = 0; static const char* nouns[] = { "People", "History", "Way", "Art", "World", "Information", "Map", "Two", "Family", "Government", "Health", "System", "Computer", "Meat", "Year", "Thanks", "Music", "Person", "Reading", "Method", "Data", "Food", "Understanding", "Theory", "Law", "Bird", "Literature", "Problem", "Software", "Control", "Knowledge", "Power", "Ability", "Economics", "Love", "Internet", "Television", "Science", "Library", "Nature", "Fact", "Product", "Idea", "Temperature", "Investment", "Area", "Society", "Activity", "Story", "Industry", "Media", "Thing", "Oven", "Community", "Definition", "Safety", "Quality", "Development", "Language", "Management", "Player", "Variety", "Video", "Week", "Security", "Country", "Exam", "Movie", "Organization", "Equipment", "Physics", "Analysis", "Policy", "Series", "Thought", "Basis", "Boyfriend", "Direction", "Strategy", "Technology", "Army", "Camera", "Freedom", "Paper", "Environment", "Child", "Instance", "Month", "Truth", "Marketing", "University", "Writing", "Article", "Department", "Difference", "Goal", "News", "Audience", "Fishing", "Growth", "Income", "Marriage", "User", "Combination", "Failure", "Meaning", "Medicine", "Philosophy", "Teacher", "Communication", "Night", "Chemistry", "Disease", "Disk", "Energy", "Nation", "Road", "Role", "Soup", "Advertising", "Location", "Success", "Addition", "Apartment", "Education", "Math", "Moment", "Painting", "Politics", "Attention", "Decision", "Event", "Property", "Shopping", "Student", "Wood", "Competition", "Distribution", "Entertainment", "Office", "Population", "President", "Unit", "Category", "Cigarette", "Context", "Introduction", "Opportunity", "Performance", "Driver", "Flight", "Length", "Magazine", "Newspaper", "Relationship", "Teaching", "Cell", "Dealer", "Finding", "Lake", "Member", "Message", "Phone", "Scene", "Appearance", "Association", "Concept", "Customer", "Death", "Discussion", "Housing", "Inflation", "Insurance", "Mood", "Woman", "Advice", "Blood", "Effort", "Expression", "Importance", "Opinion", "Payment", "Reality", "Responsibility", "Situation", "Skill", "Statement", "Wealth", "Application", "City", "County", "Depth", "Estate", "Foundation", "Grandmother", "Heart", "Perspective", "Photo", "Recipe", "Studio", "Topic", "Collection", "Depression", "Imagination", "Passion", "Percentage", "Resource", "Setting", "Ad", "Agency", "College", "Connection", "Criticism", "Debt", "Description", "Memory", "Patience", "Secretary", "Solution", "Administration", "Aspect", "Attitude", "Director", "Personality", "Psychology", "Recommendation", "Response", "Selection", "Storage", "Version", "Alcohol", "Argument", "Complaint", "Contract", "Emphasis", "Highway", "Loss", "Membership", "Possession", "Preparation", "Steak", "Union", "Agreement", "Cancer", "Currency", "Employment", "Engineering", "Entry", "Interaction", "Mixture", "Preference", "Region", "Republic", "Tradition", "Virus", "Actor", "Classroom", "Delivery", "Device", "Difficulty", "Drama", "Election", "Engine", "Football", "Guidance", "Hotel", "Owner", "Priority", "Protection", "Suggestion", "Tension", "Variation", "Anxiety", "Atmosphere", "Awareness", "Bath", "Bread", "Candidate", "Climate", "Comparison", "Confusion", "Construction", "Elevator", "Emotion", "Employee", "Employer", "Guest", "Height", "Leadership", "Mall", "Manager", "Operation", "Recording", "Sample", "Transportation", "Charity", "Cousin", "Disaster", "Editor", "Efficiency", "Excitement", "Extent", "Feedback", "Guitar", "Homework", "Leader", "Mom", "Outcome", "Permission", "Presentation", "Promotion", "Reflection", "Refrigerator", "Resolution", "Revenue", "Session", "Singer", "Tennis", "Basket", "Bonus", "Cabinet", "Childhood", "Church", "Clothes", "Coffee", "Dinner", "Drawing", "Hair", "Hearing", "Initiative", "Judgment", "Lab", "Measurement", "Mode", "Mud", "Orange", "Poetry", "Police", "Possibility", "Procedure", "Queen", "Ratio", "Relation", "Restaurant", "Satisfaction", "Sector", "Signature", "Significance", "Song", "Tooth", "Town", "Vehicle", "Volume", "Wife", "Accident", "Airport", "Appointment", "Arrival", "Assumption", "Baseball", "Chapter", "Committee", "Conversation", "Database", "Enthusiasm", "Error", "Explanation", "Farmer", "Gate", "Girl", "Hall", "Historian", "Hospital", "Injury", "Instruction", "Maintenance", "Manufacturer", "Meal", "Perception", "Pie", "Poem", "Presence", "Proposal", "Reception", "Replacement", "Revolution", "River", "Son", "Speech", "Tea", "Village", "Warning", "Winner", "Worker", "Writer", "Assistance", "Breath", "Buyer", "Chest", "Chocolate", "Conclusion", "Contribution", "Cookie", "Courage", "Dad", "Desk", "Drawer", "Establishment", "Examination", "Garbage", "Grocery", "Honey", "Impression", "Improvement", "Independence", "Insect", "Inspection", "Inspector", "King", "Ladder", "Menu", "Penalty", "Piano", "Potato", "Profession", "Professor", "Quantity", "Reaction", "Requirement", "Salad", "Sister", "Supermarket", "Tongue", "Weakness", "Wedding", "Affair", "Ambition", "Analyst", "Apple", "Assignment", "Assistant", "Bathroom", "Bedroom", "Beer", "Birthday", "Celebration", "Championship", "Cheek", "Client", "Consequence", "Departure", "Diamond", "Dirt", "Ear", "Fortune", "Friendship", "Funeral", "Gene", "Girlfriend", "Hat", "Indication", "Intention", "Lady", "Midnight", "Negotiation", "Obligation", "Passenger", "Pizza", "Platform", "Poet", "Pollution", "Recognition", "Reputation", "Shirt", "Sir", "Speaker", "Stranger", "Surgery", "Sympathy", "Tale", "Throat", "Trainer", "Uncle", "Youth", "Time", "Work", "Film", "Water", "Money", "Example", "While", "Business", "Study", "Game", "Life", "Form", "Air", "Day", "Place", "Number", "Part", "Field", "Fish", "Back", "Process", "Heat", "Hand", "Experience", "Job", "Book", "End", "Point", "Type", "Home", "Economy", "Value", "Body", "Market", "Guide", "Interest", "State", "Radio", "Course", "Company", "Price", "Size", "Card", "List", "Mind", "Trade", "Line", "Care", "Group", "Risk", "Word", "Fat", "Force", "Key", "Light", "Training", "Name", "School", "Top", "Amount", "Level", "Order", "Practice", "Research", "Sense", "Service", "Piece", "Web", "Boss", "Sport", "Fun", "House", "Page", "Term", "Test", "Answer", "Sound", "Focus", "Matter", "Kind", "Soil", "Board", "Oil", "Picture", "Access", "Garden", "Range", "Rate", "Reason", "Future", "Site", "Demand", "Exercise", "Image", "Case", "Cause", "Coast", "Action", "Age", "Bad", "Boat", "Record", "Result", "Section", "Building", "Mouse", "Cash", "Class", "Nothing", "Period", "Plan", "Store", "Tax", "Side", "Subject", "Space", "Rule", "Stock", "Weather", "Chance", "Figure", "Man", "Model", "Source", "Beginning", "Earth", "Program", "Chicken", "Design", "Feature", "Head", "Material", "Purpose", "Question", "Rock", "Salt", "Act", "Birth", "Car", "Dog", "Object", "Scale", "Sun", "Note", "Profit", "Rent", "Speed", "Style", "War", "Bank", "Craft", "Half", "Inside", "Outside", "Standard", "Bus", "Exchange", "Eye", "Fire", "Position", "Pressure", "Stress", "Advantage", "Benefit", "Box", "Frame", "Issue", "Step", "Cycle", "Face", "Item", "Metal", "Paint", "Review", "Room", "Screen", "Structure", "View", "Account", "Ball", "Discipline", "Medium", "Share", "Balance", "Bit", "Black", "Bottom", "Choice", "Gift", "Impact", "Machine", "Shape", "Tool", "Wind", "Address", "Average", "Career", "Culture", "Morning", "Pot", "Sign", "Table", "Task", "Condition", "Contact", "Credit", "Egg", "Hope", "Ice", "Network", "North", "Square", "Attempt", "Date", "Effect", "Link", "Post", "Star", "Voice", "Capital", "Challenge", "Friend", "Self", "Shot", "Brush", "Couple", "Debate", "Exit", "Front", "Function", "Lack", "Living", "Plant", "Plastic", "Spot", "Summer", "Taste", "Theme", "Track", "Wing", "Brain", "Button", "Click", "Desire", "Foot", "Gas", "Influence", "Notice", "Rain", "Wall", "Base", "Damage", "Distance", "Feeling", "Pair", "Savings", "Staff", "Sugar", "Target", "Text", "Animal", "Author", "Budget", "Discount", "File", "Ground", "Lesson", "Minute", "Officer", "Phase", "Reference", "Register", "Sky", "Stage", "Stick", "Title", "Trouble", "Bowl", "Bridge", "Campaign", "Character", "Club", "Edge", "Evidence", "Fan", "Letter", "Lock", "Maximum", "Novel", "Option", "Pack", "Park", "Plenty", "Quarter", "Skin", "Sort", "Weight", "Baby", "Background", "Carry", "Dish", "Factor", "Fruit", "Glass", "Joint", "Master", "Muscle", "Red", "Strength", "Traffic", "Trip", "Vegetable", "Appeal", "Chart", "Gear", "Ideal", "Kitchen", "Land", "Log", "Mother", "Net", "Party", "Principle", "Relative", "Sale", "Season", "Signal", "Spirit", "Street", "Tree", "Wave", "Belt", "Bench", "Commission", "Copy", "Drop", "Minimum", "Path", "Progress", "Project", "Sea", "South", "Status", "Stuff", "Ticket", "Tour", "Angle", "Blue", "Breakfast", "Confidence", "Daughter", "Degree", "Doctor", "Dot", "Dream", "Duty", "Essay", "Father", "Fee", "Finance", "Hour", "Juice", "Limit", "Luck", "Milk", "Mouth", "Peace", "Pipe", "Seat", "Stable", "Storm", "Substance", "Team", "Trick", "Afternoon", "Bat", "Beach", "Blank", "Catch", "Chain", "Consideration", "Cream", "Crew", "Detail", "Gold", "Interview", "Kid", "Mark", "Match", "Mission", "Pain", "Pleasure", "Score", "Screw", "Sex", "Shop", "Shower", "Suit", "Tone", "Window", "Agent", "Band", "Block", "Bone", "Calendar", "Cap", "Coat", "Contest", "Corner", "Court", "Cup", "District", "Door", "East", "Finger", "Garage", "Guarantee", "Hole", "Hook", "Implement", "Layer", "Lecture", "Lie", "Manner", "Meeting", "Nose", "Parking", "Partner", "Profile", "Respect", "Rice", "Routine", "Schedule", "Swimming", "Telephone", "Tip", "Winter", "Airline", "Bag", "Battle", "Bed", "Bill", "Bother", "Cake", "Code", "Curve", "Designer", "Dimension", "Dress", "Ease", "Emergency", "Evening", "Extension", "Farm", "Fight", "Gap", "Grade", "Holiday", "Horror", "Horse", "Host", "Husband", "Loan", "Mistake", "Mountain", "Nail", "Noise", "Occasion", "Package", "Patient", "Pause", "Phrase", "Proof", "Race", "Relief", "Sand", "Sentence", "Shoulder", "Smoke", "Stomach", "String", "Tourist", "Towel", "Vacation", "West", "Wheel", "Wine", "Arm", "Aside", "Associate", "Bet", "Blow", "Border", "Branch", "Breast", "Brother", "Buddy", "Bunch", "Chip", "Coach", "Cross", "Document", "Draft", "Dust", "Expert", "Floor", "God", "Golf", "Habit", "Iron", "Judge", "Knife", "Landscape", "League", "Mail", "Mess", "Native", "Opening", "Parent", "Pattern", "Pin", "Pool", "Pound", "Request", "Salary", "Shame", "Shelter", "Shoe", "Silver", "Tackle", "Tank", "Trust", "Assist", "Bake", "Bar", "Bell", "Bike", "Blame", "Boy", "Brick", "Chair", "Closet", "Clue", "Collar", "Comment", "Conference", "Devil", "Diet", "Fear", "Fuel", "Glove", "Jacket", "Lunch", "Monitor", "Mortgage", "Nurse", "Pace", "Panic", "Peak", "Plane", "Reward", "Row", "Sandwich", "Shock", "Spite", "Spray", "Surprise", "Till", "Transition", "Weekend", "Welcome", "Yard", "Alarm", "Bend", "Bicycle", "Bite", "Blind", "Bottle", "Cable", "Candle", "Clerk", "Cloud", "Concert", "Counter", "Flower", "Grandfather", "Harm", "Knee", "Lawyer", "Leather", "Load", "Mirror", "Neck", "Pension", "Plate", "Purple", "Ruin", "Ship", "Skirt", "Slice", "Snow", "Specialist", "Stroke", "Switch", "Trash", "Tune", "Zone", "Anger", "Award", "Bid", "Bitter", "Boot", "Bug", "Camp", "Candy", "Carpet", "Cat", "Champion", "Channel", "Clock", "Comfort", "Cow", "Crack", "Engineer", "Entrance", "Fault", "Grass", "Guy", "Hell", "Highlight", "Incident", "Island", "Joke", "Jury", "Leg", "Lip", "Mate", "Motor", "Nerve", "Passage", "Pen", "Pride", "Priest", "Prize", "Promise", "Resident", "Resort", "Ring", "Roof", "Rope", "Sail", "Scheme", "Script", "Sock", "Station", "Toe", "Tower", "Truck", "Witness", "A", "You", "It", "Can", "Will", "If", "One", "Many", "Most", "Other", "Use", "Make", "Good", "Look", "Help", "Go", "Great", "Being", "Few", "Might", "Still", "Public", "Read", "Keep", "Start", "Give", "Human", "Local", "General", "She", "Specific", "Long", "Play", "Feel", "High", "Tonight", "Put", "Common", "Set", "Change", "Simple", "Past", "Big", "Possible", "Particular", "Today", "Major", "Personal", "Current", "National", "Cut", "Natural", "Physical", "Show", "Try", "Check", "Second", "Call", "Move", "Pay", "Let", "Increase", "Single", "Individual", "Turn", "Ask", "Buy", "Guard", "Hold", "Main", "Offer", "Potential", "Professional", "International", "Travel", "Cook", "Alternative", "Following", "Special", "Working", "Whole", "Dance", "Excuse", "Cold", "Commercial", "Low", "Purchase", "Deal", "Primary", "Worth", "Fall", "Necessary", "Positive", "Produce", "Search", "Present", "Spend", "Talk", "Creative", "Tell", "Cost", "Drive", "Green", "Support", "Glad", "Remove", "Return", "Run", "Complex", "Due", "Effective", "Middle", "Regular", "Reserve", "Independent", "Leave", "Original", "Reach", "Rest", "Serve", "Watch", "Beautiful", "Charge", "Active", "Break", "Negative", "Safe", "Stay", "Visit", "Visual", "Affect", "Cover", "Report", "Rise", "Walk", "White", "Beyond", "Junior", "Pick", "Unique", "Anything", "Classic", "Final", "Lift", "Mix", "Private", "Stop", "Teach", "Western", "Concern", "Familiar", "Fly", "Official", "Broad", "Comfortable", "Gain", "Maybe", "Rich", "Save", "Stand", "Young", "Fail", "Heavy", "Hello", "Lead", "Listen", "Valuable", "Worry", "Handle", "Leading", "Meet", "Release", "Sell", "Finish", "Normal", "Press", "Ride", "Secret", "Spread", "Spring", "Tough", "Wait", "Brown", "Deep", "Display", "Flow", "Hit", "Objective", "Shoot", "Touch", "Cancel", "Chemical", "Cry", "Dump", "Extreme", "Push", "Conflict", "Eat", "Fill", "Formal", "Jump", "Kick", "Opposite", "Pass", "Pitch", "Remote", "Total", "Treat", "Vast", "Abuse", "Beat", "Burn", "Deposit", "Print", "Raise", "Sleep", "Somewhere", "Advance", "Anywhere", "Consist", "Dark", "Double", "Draw", "Equal", "Fix", "Hire", "Internal", "Join", "Kill", "Sensitive", "Tap", "Win", "Attack", "Claim", "Constant", "Drag", "Drink", "Guess", "Minor", "Pull", "Raw", "Soft", "Solid", "Wear", "Weird", "Wonder", "Annual", "Count", "Dead", "Doubt", "Feed", "Forever", "Impress", "Nobody", "Repeat", "Round", "Sing", "Slide", "Strip", "Whereas", "Wish", "Combine", "Command", "Dig", "Divide", "Equivalent", "Hang", "Hunt", "Initial", "March", "Mention", "Smell", "Spiritual", "Survey", "Tie", "Adult", "Brief", "Crazy", "Escape", "Gather", "Hate", "Prior", "Repair", "Rough", "Sad", "Scratch", "Sick", "Strike", "Employ", "External", "Hurt", "Illegal", "Laugh", "Lay", "Mobile", "Nasty", "Ordinary", "Respond", "Royal", "Senior", "Split", "Strain", "Struggle", "Swim", "Train", "Upper", "Wash", "Yellow", "Convert", "Crash", "Dependent", "Fold", "Funny", "Grab", "Hide", "Miss", "Permit", "Quote", "Recover", "Resolve", "Roll", "Sink", "Slip", "Spare", "Suspect", "Sweet", "Swing", "Twist", "Upstairs", "Usual", "Abroad", "Brave", "Calm", "Concentrate", "Estimate", "Grand", "Male", "Mine", "Prompt", "Quiet", "Refuse", "Regret", "Reveal", "Rush", "Shake", "Shift", "Shine", "Steal", "Suck", "Surround", "Anybody", "Bear", "Brilliant", "Dare", "Dear", "Delay", "Drunk", "Female", "Hurry", "Inevitable", "Invite", "Kiss", "Neat", "Pop", "Punch", "Quit", "Reply", "Representative", "Resist", "Rip", "Rub", "Silly", "Smile", "Spell", "Stretch", "Stupid", "Tear", "Temporary", "Tomorrow", "Wake", "Wrap", "Yesterday", NULL }; TCL_DECLARE_MUTEX(things_mutex) static int hash_tables_initialized = 0; static int maxlen_adjective = 0; static int maxlen_noun = 0; static Tcl_HashTable things; // Map void* -> name static Tcl_HashTable names; // Map name -> void* Tcl_ThreadDataKey outbuf; static void init() { int new; Tcl_HashEntry* he = NULL; struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); Tcl_MutexLock(&things_mutex); if (hash_tables_initialized == 0) { srandom((int)ts.tv_nsec); for (adjectivesc=0; adjectives[adjectivesc]; adjectivesc++) { int len = strlen(adjectives[adjectivesc]); if (len > maxlen_adjective) maxlen_adjective = len; } for (nounsc=0; nouns[nounsc]; nounsc++) { int len = strlen(nouns[nounsc]); if (len > maxlen_noun) maxlen_noun = len; } Tcl_InitHashTable(&things, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&names, TCL_STRING_KEYS); he = Tcl_CreateHashEntry(&names, "NULL", &new); Tcl_SetHashValue(he, NULL); hash_tables_initialized = 1; } Tcl_MutexUnlock(&things_mutex); } void names_shutdown() { Tcl_MutexLock(&things_mutex); if (hash_tables_initialized) { Tcl_HashEntry* he; Tcl_HashSearch search; for (he = Tcl_FirstHashEntry(&things, &search); he; he = Tcl_NextHashEntry(&search)) { char* chosen = Tcl_GetHashValue(he); ckfree(chosen); } Tcl_DeleteHashTable(&things); Tcl_DeleteHashTable(&names); hash_tables_initialized = 0; } Tcl_MutexUnlock(&things_mutex); Tcl_MutexFinalize(&things_mutex); } const char* randwords() { const int maxlen = 41; int adj = random() % adjectivesc; int noun = random() % nounsc; char* out = Tcl_GetThreadData(&outbuf, maxlen); snprintf(out, maxlen, "%s%s", adjectives[adj], nouns[noun]); return out; } void* thing(const char *const name) { Tcl_HashEntry* he_name = NULL; if (hash_tables_initialized == 0) init(); Tcl_MutexLock(&things_mutex); he_name = Tcl_FindHashEntry(&things, name); Tcl_MutexUnlock(&things_mutex); return Tcl_GetHashValue(he_name); } const char* name(const void *const thing) { int new; Tcl_HashEntry* he_thing = NULL; Tcl_HashEntry* he_name = NULL; const char* candidate = NULL; char* chosen = NULL; int chosenlen; if (thing == NULL) return "NULL"; if (hash_tables_initialized == 0) init(); Tcl_MutexLock(&things_mutex); he_thing = Tcl_CreateHashEntry(&things, thing, &new); Tcl_MutexUnlock(&things_mutex); if (!new) return Tcl_GetHashValue(he_thing); new = 0; while (!new) { candidate = randwords(); Tcl_MutexLock(&things_mutex); he_name = Tcl_CreateHashEntry(&names, candidate, &new); Tcl_MutexUnlock(&things_mutex); } chosenlen = strlen(candidate)+1; chosen = ckalloc(chosenlen); memcpy(chosen, candidate, chosenlen); Tcl_SetHashValue(he_name, thing); Tcl_SetHashValue(he_thing, chosen); return chosen; } // vim: ts=4 shiftwidth=4 cyanogilvie-teabase-9345a87/names.h000066400000000000000000000002731526245020600171730ustar00rootroot00000000000000#ifndef _NAMES_H #define _NAMES_H const char* name(const void *const thing); // name given thing void* thing(const char *const name); // thing given name void names_shutdown(); #endif cyanogilvie-teabase-9345a87/pkg_config_h/000077500000000000000000000000001526245020600203325ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/pkg_config_h/meson.build000066400000000000000000000002171526245020600224740ustar00rootroot00000000000000# Generate the config.h in a private location that is not in the exported include path configure_file(output: 'config.h', configuration: conf) cyanogilvie-teabase-9345a87/polyfill.h000066400000000000000000000007511526245020600177230ustar00rootroot00000000000000#ifndef POLYFILL #define POLYFILL #ifndef Tcl_DStringToObj static Tcl_Obj* Tcl_DStringToObj(Tcl_DString* ds) { Tcl_Obj* res = NULL; if (ds->string == ds->staticSpace) { return ds->length ? Tcl_NewStringObj(ds->string, ds->length) : Tcl_NewObj(); } else { res = Tcl_NewObj(); res->bytes = ds->string; res->length = ds->length; } ds->string = ds->staticSpace; ds->spaceAvl = TCL_DSTRING_STATIC_SIZE; ds->length = 0; ds->staticSpace[0] = 0; return res; } #endif #endif cyanogilvie-teabase-9345a87/register_config.c000066400000000000000000000011701526245020600212310ustar00rootroot00000000000000#include #include void register_config(Tcl_Interp* interp, const char* pkgdir) { /* Despite what the Tcl_RegisterConfig manpage claims, these values *ARE* * copied, so using `pkgdir` here is fine. (8.6 and 9.0) */ Tcl_RegisterConfig(interp, PACKAGE_NAME, (Tcl_Config[]){ {"libdir,runtime", pkgdir}, {"includedir,runtime", pkgdir}, {"packagedir,runtime", pkgdir}, {"library", PACKAGE_LIBNAME}, {"stublib", PACKAGE_STUBLIB}, {"header", PACKAGE_NAME ".h"}, {0} }, "utf-8"); } void deregiser_config(Tcl_Interp* interp) { Tcl_DeleteCommand(interp, "::" PACKAGE_NAME "::pkgconfig"); } cyanogilvie-teabase-9345a87/register_config.h000066400000000000000000000003071526245020600212370ustar00rootroot00000000000000#ifndef TEABASE_REGISTER_CONFIG_H #define TEABASE_REGISTER_CONFIG_H #include void register_config(Tcl_Interp* interp, const char* pkgdir); void deregiser_config(Tcl_Interp* interp); #endif cyanogilvie-teabase-9345a87/run_bench.tcl000066400000000000000000000025071526245020600203700ustar00rootroot00000000000000# vim: ft=tcl foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4 set this_script [file normalize [info script]] set seen {} while {[file type $this_script] eq "link"} { dict set seen $this_script 1 set this_script [file normalize [file join [file dirname $this_script] [file readlink $this_script]]] if {[dict exists $seen $this_script]} { error "Symlink loop detected while trying to resolve [file normalize [info script]]" } } unset seen set here [file dirname $this_script] tcl::tm::path add $here package require teabase_bench proc main {} { global here env try { puts "[string repeat - 80]\nStarting benchmarks\n" if {[llength [glob -nocomplain -type f [file join [pwd] *.bench]]]} { set benchdir [pwd] } else { set benchdir [file dirname [file normalize [info script]]] } teabase_bench::run_benchmarks $benchdir {*}$::argv } on ok {} { exit 0 } trap {BENCH BAD_RESULT} {errmsg options} { puts stderr $errmsg exit 1 } trap {BENCH BAD_CODE} {errmsg options} { puts stderr $errmsg exit 1 } trap {BENCH INVALID_ARG} {errmsg options} { puts stderr $errmsg exit 1 } trap exit code { exit $code } on error {errmsg options} { puts stderr "Unhandled error from benchmark_mode: [dict get $options -errorinfo]" exit 2 } } main # vim: ft=tcl foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4 cyanogilvie-teabase-9345a87/subprojects/000077500000000000000000000000001526245020600202605ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/subprojects/brotli.wrap000066400000000000000000000002231526245020600224430ustar00rootroot00000000000000[wrap-git] clone-recursive = true url = https://github.com/cyanogilvie/tcl-brotli revision = v0.4.5 depth = 1 [provide] dependency_names = brotli cyanogilvie-teabase-9345a87/subprojects/cbor.wrap000066400000000000000000000002131526245020600220740ustar00rootroot00000000000000[wrap-git] clone-recursive = true url = https://github.com/cyanogilvie/cbor revision = v1.2.1 depth = 1 [provide] dependency_names = cbor cyanogilvie-teabase-9345a87/subprojects/chantricks.wrap000066400000000000000000000002301526245020600232770ustar00rootroot00000000000000[wrap-git] clone-recursive = true url = https://github.com/cyanogilvie/chantricks revision = v1.0.10 depth = 1 [provide] dependency_names = chantricks cyanogilvie-teabase-9345a87/subprojects/dedup.wrap000066400000000000000000000002161526245020600222530ustar00rootroot00000000000000[wrap-git] clone-recursive = true url = https://github.com/cyanogilvie/dedup revision = v0.9.26 depth = 1 [provide] dependency_names = dedup cyanogilvie-teabase-9345a87/subprojects/gc_class.wrap000066400000000000000000000001671526245020600227350ustar00rootroot00000000000000[wrap-git] url = https://github.com/RubyLane/gc_class revision = v1.1 depth = 1 [provide] dependency_names = gc_class cyanogilvie-teabase-9345a87/subprojects/hedley.wrap000066400000000000000000000007031526245020600224250ustar00rootroot00000000000000[wrap-file] directory = hedley-15 source_url = https://codeload.github.com/nemequ/hedley/tar.gz/v15 source_filename = hedley-15.tar.gz source_hash = e91c71b58f59d08c7b8289be8f687866863d934dfaa528e4be30b178139ae863 patch_filename = hedley_15-1_patch.zip patch_url = https://wrapdb.mesonbuild.com/v2/hedley_15-1/get_patch patch_hash = 4fe21441ad90dce22fc2e88b4c2b164ab65682c15858ec710a2b206a5bbe5272 wrapdb_version = 15-1 [provide] hedley = hedley_dep cyanogilvie-teabase-9345a87/subprojects/libtommath.wrap000066400000000000000000000004751526245020600233210ustar00rootroot00000000000000[wrap-file] directory = libtommath-1.3.0 source_url = https://github.com/libtom/libtommath/releases/download/v1.3.0/ltm-1.3.0.tar.xz source_filename = ltm-1.3.0.tar.xz source_hash = 296272d93435991308eb73607600c034b558807a07e829e751142e65ccfa9d08 patch_directory = libtommath [provide] dependency_names = libtommath cyanogilvie-teabase-9345a87/subprojects/packagefiles/000077500000000000000000000000001526245020600226765ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/subprojects/packagefiles/libtommath/000077500000000000000000000000001526245020600250365ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/subprojects/packagefiles/libtommath/doc/000077500000000000000000000000001526245020600256035ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/subprojects/packagefiles/libtommath/doc/build-manual.py000066400000000000000000000062071526245020600305340ustar00rootroot00000000000000#!/usr/bin/env python3 """Build the libtommath PDF manual from LaTeX sources This script is called by meson with the following environment variables set: LATEX, PDFLATEX, MAKEINDEX Only requires standard Python library - no external tools beyond LaTeX itself. """ import os import sys import shutil import subprocess import re from datetime import datetime, timezone def main(): if len(sys.argv) != 4: print("Usage: build-manual.py INPUT OUTDIR OUTPUT", file=sys.stderr) sys.exit(1) input_file = sys.argv[1] outdir = sys.argv[2] output_file = sys.argv[3] # Get tools from environment latex = os.environ.get('LATEX', 'latex') pdflatex = os.environ.get('PDFLATEX', 'pdflatex') makeindex = os.environ.get('MAKEINDEX', 'makeindex') # Convert paths to absolute before changing directories input_file = os.path.abspath(input_file) output_file = os.path.abspath(output_file) # Change to output directory os.chdir(outdir) # Copy input to bn.tex shutil.copy2(input_file, 'bn.tex') # Create backup with same timestamp shutil.copy2('bn.tex', 'bn.bak') # Get modification time of bn.tex and format for PDF mtime = os.stat('bn.tex').st_mtime dt = datetime.fromtimestamp(mtime, tz=timezone.utc) # Format as PDF date string: D:YYYYMMDDHHmmSS+HH'mm' # For UTC, timezone offset is +00'00' date_str = dt.strftime("D:%Y%m%d%H%M%S+00'00'") # Write deterministic PDF header with open('bn-deterministic.tex', 'w') as f: f.write(f"\\def\\fixedpdfdate{{{date_str}}}\n") f.write("\\pdfinfo{\n") f.write(" /CreationDate (\\fixedpdfdate)\n") f.write(" /ModDate (\\fixedpdfdate)\n") f.write("}\n") # Append original content with open('bn.tex', 'r') as orig: f.write(orig.read()) # Replace bn.tex with deterministic version shutil.move('bn-deterministic.tex', 'bn.tex') # Restore original timestamp shutil.copystat('bn.bak', 'bn.tex') # Build the manual with open('bn.ind', 'w') as f: f.write('hello\n') subprocess.run([latex, 'bn'], stdout=subprocess.DEVNULL, check=True) subprocess.run([latex, 'bn'], stdout=subprocess.DEVNULL, check=True) subprocess.run([makeindex, 'bn'], check=True) subprocess.run([latex, 'bn'], stdout=subprocess.DEVNULL, check=True) subprocess.run([pdflatex, 'bn'], stdout=subprocess.DEVNULL, check=True) # Make PDF ID deterministic using Python with open('bn.pdf', 'rb') as f: pdf_data = f.read() # Replace /ID [<...> <...>] with /ID [<0> <0>] pdf_data = re.sub(rb'^/ID \[.*\]$', rb'/ID [<0> <0>]', pdf_data, flags=re.MULTILINE) with open('bn.pdf', 'wb') as f: f.write(pdf_data) # Rename to desired output name shutil.move('bn.pdf', output_file) # Cleanup shutil.move('bn.bak', 'bn.tex') cleanup_files = [ 'bn.aux', 'bn.dvi', 'bn.log', 'bn.idx', 'bn.lof', 'bn.out', 'bn.toc', 'bn.ilg', 'bn.ind', 'bn.tex' ] for f in cleanup_files: try: os.remove(f) except FileNotFoundError: pass if __name__ == '__main__': main() cyanogilvie-teabase-9345a87/subprojects/packagefiles/libtommath/libtommath.def000066400000000000000000000074031526245020600276620ustar00rootroot00000000000000LIBRARY tommath-1 EXPORTS fast_mp_invmod fast_mp_montgomery_reduce fast_s_mp_mul_digs fast_s_mp_mul_high_digs fast_s_mp_sqr mp_2expt mp_abs mp_add mp_add_d mp_addmod mp_and mp_balance_mul mp_clamp mp_clear mp_clear_multi mp_cmp mp_cmp_d mp_cmp_mag mp_cnt_lsb mp_complement mp_copy mp_count_bits mp_decr mp_div mp_div_2 mp_div_2d mp_div_3 mp_div_d mp_dr_is_modulus mp_dr_reduce mp_dr_setup mp_error_to_string mp_exch mp_export mp_expt_d mp_expt_d_ex mp_exptmod mp_exptmod_fast mp_expt_n mp_expt_u32 mp_exteuclid mp_fread mp_from_sbin mp_from_ubin mp_fwrite mp_gcd mp_get_bit mp_get_double mp_get_i32 mp_get_i64 mp_get_int mp_get_l mp_get_ll mp_get_long mp_get_long_long mp_get_mag_u32 mp_get_mag_u64 mp_get_mag_ul mp_get_mag_ull mp_grow mp_import mp_incr mp_init mp_init_copy mp_init_i32 mp_init_i64 mp_init_l mp_init_ll mp_init_multi mp_init_set mp_init_set_int mp_init_size mp_init_u32 mp_init_u64 mp_init_ul mp_init_ull mp_invmod mp_invmod_slow mp_iseven mp_isodd mp_is_square mp_jacobi mp_karatsuba_mul mp_karatsuba_sqr mp_kronecker mp_lcm mp_log_n mp_log_u32 mp_lshd mp_mod mp_mod_2d mp_mod_d mp_montgomery_calc_normalization mp_montgomery_reduce mp_montgomery_setup mp_mul mp_mul_2 mp_mul_2d mp_mul_d mp_mulmod mp_neg mp_n_root mp_n_root_ex mp_or mp_pack mp_pack_count mp_prime_fermat mp_prime_frobenius_underwood mp_prime_is_divisible mp_prime_is_prime mp_prime_miller_rabin mp_prime_next_prime mp_prime_rabin_miller_trials mp_prime_rand mp_prime_random_ex mp_prime_strong_lucas_selfridge mp_radix_size mp_rand mp_rand_digit mp_rand_source mp_read_radix mp_read_signed_bin mp_read_unsigned_bin mp_reduce mp_reduce_2k mp_reduce_2k_l mp_reduce_2k_setup mp_reduce_2k_setup_l mp_reduce_is_2k mp_reduce_is_2k_l mp_reduce_setup mp_root_n mp_root_u32 mp_rshd mp_sbin_size mp_set mp_set_double mp_set_i32 mp_set_i64 mp_set_int mp_set_l mp_set_ll mp_set_long mp_set_long_long mp_set_u32 mp_set_u64 mp_set_ul mp_set_ull mp_shrink mp_signed_bin_size mp_signed_rsh mp_sqr mp_sqrmod mp_sqrt mp_sqrtmod_prime mp_sub mp_sub_d mp_submod mp_tc_and mp_tc_div_2d mp_tc_or mp_tc_xor mp_toom_mul mp_toom_sqr mp_to_radix mp_toradix mp_toradix_n mp_to_sbin mp_to_signed_bin mp_to_signed_bin_n mp_to_ubin mp_to_unsigned_bin mp_to_unsigned_bin_n mp_ubin_size mp_unpack mp_unsigned_bin_size mp_xor mp_zero s_mp_add s_mp_balance_mul s_mp_div_3 s_mp_exptmod s_mp_exptmod_fast s_mp_get_bit s_mp_invmod_fast s_mp_invmod_slow s_mp_karatsuba_mul s_mp_karatsuba_sqr s_mp_log s_mp_log_2expt s_mp_log_d s_mp_montgomery_reduce_fast s_mp_mul_digs s_mp_mul_digs_fast s_mp_mul_high_digs s_mp_mul_high_digs_fast s_mp_prime_is_divisible s_mp_prime_random_ex s_mp_rand_jenkins s_mp_rand_jenkins_init s_mp_rand_platform s_mp_reverse s_mp_sqr s_mp_sqr_fast s_mp_sub s_mp_toom_mul s_mp_toom_sqr KARATSUBA_MUL_CUTOFF DATA KARATSUBA_SQR_CUTOFF DATA TOOM_MUL_CUTOFF DATA TOOM_SQR_CUTOFF DATA ltm_prime_tab DATA mp_s_rmap DATA mp_s_rmap_reverse DATA mp_s_rmap_reverse_sz DATA s_mp_prime_tab DATA s_mp_rand_source DATA cyanogilvie-teabase-9345a87/subprojects/packagefiles/libtommath/meson.build000066400000000000000000000254111526245020600272030ustar00rootroot00000000000000project( 'libtommath', 'c', version: '1.3.0', license: 'Unlicense', default_options: [ 'c_std=c99', ], meson_version: '>=0.63.0', ) cc = meson.get_compiler('c') # Override optimization for debug builds to use -Og instead of -O0 to work # around an issue with clang not optimizing away references to some # conditionally defined functions with forward references if get_option('debug') and get_option('optimization') == '0' and cc.get_id() in [ 'clang', 'clang-cl', ] add_project_arguments( '-Og', language: 'c', ) endif if cc.get_id() in ['msvc', 'clang-cl'] add_project_arguments( '/wd4146', '/wd4127', '/wd4668', '/wd4710', '/wd4711', '/wd4820', '/wd5045', '/wd4305', '/Ox', language: 'c', ) endif if host_machine.system() == 'windows' add_project_arguments( '-D_CRT_SECURE_NO_WARNINGS', '-D_CRT_NONSTDC_NO_DEPRECATE', '-D__STDC_WANT_SECURE_LIB__=1', '-D_CRT_HAS_CXX17=0', language: 'c', ) endif add_project_arguments( cc.get_supported_arguments('-Wno-unused-but-set-variable'), language: 'c', ) # Library sources sources = files( 'bn_cutoffs.c', 'bn_deprecated.c', 'bn_mp_2expt.c', 'bn_mp_abs.c', 'bn_mp_add.c', 'bn_mp_add_d.c', 'bn_mp_addmod.c', 'bn_mp_and.c', 'bn_mp_clamp.c', 'bn_mp_clear.c', 'bn_mp_clear_multi.c', 'bn_mp_cmp.c', 'bn_mp_cmp_d.c', 'bn_mp_cmp_mag.c', 'bn_mp_cnt_lsb.c', 'bn_mp_complement.c', 'bn_mp_copy.c', 'bn_mp_count_bits.c', 'bn_mp_decr.c', 'bn_mp_div.c', 'bn_mp_div_2.c', 'bn_mp_div_2d.c', 'bn_mp_div_d.c', 'bn_mp_dr_is_modulus.c', 'bn_mp_dr_reduce.c', 'bn_mp_dr_setup.c', 'bn_mp_error_to_string.c', 'bn_mp_exch.c', 'bn_mp_expt_n.c', 'bn_mp_exptmod.c', 'bn_mp_exteuclid.c', 'bn_mp_fread.c', 'bn_mp_from_sbin.c', 'bn_mp_from_ubin.c', 'bn_mp_fwrite.c', 'bn_mp_gcd.c', 'bn_mp_get_double.c', 'bn_mp_get_i32.c', 'bn_mp_get_i64.c', 'bn_mp_get_l.c', 'bn_mp_get_mag_u32.c', 'bn_mp_get_mag_u64.c', 'bn_mp_get_mag_ul.c', 'bn_mp_grow.c', 'bn_mp_incr.c', 'bn_mp_init.c', 'bn_mp_init_copy.c', 'bn_mp_init_i32.c', 'bn_mp_init_i64.c', 'bn_mp_init_l.c', 'bn_mp_init_multi.c', 'bn_mp_init_set.c', 'bn_mp_init_size.c', 'bn_mp_init_u32.c', 'bn_mp_init_u64.c', 'bn_mp_init_ul.c', 'bn_mp_invmod.c', 'bn_mp_is_square.c', 'bn_mp_iseven.c', 'bn_mp_isodd.c', 'bn_mp_kronecker.c', 'bn_mp_lcm.c', 'bn_mp_log_n.c', 'bn_mp_lshd.c', 'bn_mp_mod.c', 'bn_mp_mod_2d.c', 'bn_mp_mod_d.c', 'bn_mp_montgomery_calc_normalization.c', 'bn_mp_montgomery_reduce.c', 'bn_mp_montgomery_setup.c', 'bn_mp_mul.c', 'bn_mp_mul_2.c', 'bn_mp_mul_2d.c', 'bn_mp_mul_d.c', 'bn_mp_mulmod.c', 'bn_mp_neg.c', 'bn_mp_or.c', 'bn_mp_pack.c', 'bn_mp_pack_count.c', 'bn_mp_prime_fermat.c', 'bn_mp_prime_frobenius_underwood.c', 'bn_mp_prime_is_prime.c', 'bn_mp_prime_miller_rabin.c', 'bn_mp_prime_next_prime.c', 'bn_mp_prime_rabin_miller_trials.c', 'bn_mp_prime_rand.c', 'bn_mp_prime_strong_lucas_selfridge.c', 'bn_mp_radix_size.c', 'bn_mp_radix_smap.c', 'bn_mp_rand.c', 'bn_mp_read_radix.c', 'bn_mp_reduce.c', 'bn_mp_reduce_2k.c', 'bn_mp_reduce_2k_l.c', 'bn_mp_reduce_2k_setup.c', 'bn_mp_reduce_2k_setup_l.c', 'bn_mp_reduce_is_2k.c', 'bn_mp_reduce_is_2k_l.c', 'bn_mp_reduce_setup.c', 'bn_mp_root_n.c', 'bn_mp_rshd.c', 'bn_mp_sbin_size.c', 'bn_mp_set.c', 'bn_mp_set_double.c', 'bn_mp_set_i32.c', 'bn_mp_set_i64.c', 'bn_mp_set_l.c', 'bn_mp_set_u32.c', 'bn_mp_set_u64.c', 'bn_mp_set_ul.c', 'bn_mp_shrink.c', 'bn_mp_signed_rsh.c', 'bn_mp_sqr.c', 'bn_mp_sqrmod.c', 'bn_mp_sqrt.c', 'bn_mp_sqrtmod_prime.c', 'bn_mp_sub.c', 'bn_mp_sub_d.c', 'bn_mp_submod.c', 'bn_mp_to_radix.c', 'bn_mp_to_sbin.c', 'bn_mp_to_ubin.c', 'bn_mp_ubin_size.c', 'bn_mp_unpack.c', 'bn_mp_xor.c', 'bn_mp_zero.c', 'bn_prime_tab.c', 'bn_s_mp_add.c', 'bn_s_mp_balance_mul.c', 'bn_s_mp_div_3.c', 'bn_s_mp_exptmod.c', 'bn_s_mp_exptmod_fast.c', 'bn_s_mp_get_bit.c', 'bn_s_mp_invmod_fast.c', 'bn_s_mp_invmod_slow.c', 'bn_s_mp_karatsuba_mul.c', 'bn_s_mp_karatsuba_sqr.c', 'bn_s_mp_log.c', 'bn_s_mp_log_2expt.c', 'bn_s_mp_log_d.c', 'bn_s_mp_montgomery_reduce_fast.c', 'bn_s_mp_mul_digs.c', 'bn_s_mp_mul_digs_fast.c', 'bn_s_mp_mul_high_digs.c', 'bn_s_mp_mul_high_digs_fast.c', 'bn_s_mp_prime_is_divisible.c', 'bn_s_mp_rand_jenkins.c', 'bn_s_mp_rand_platform.c', 'bn_s_mp_reverse.c', 'bn_s_mp_sqr.c', 'bn_s_mp_sqr_fast.c', 'bn_s_mp_sub.c', 'bn_s_mp_toom_mul.c', 'bn_s_mp_toom_sqr.c', ) inc = include_directories('.') # Add extra optimization flags to match Makefile and CMake builds # Note: Meson already adds -O3 when optimization=3 (from buildtype=release) # We only need to add the flags Meson doesn't add by default if not get_option('debug') add_project_arguments( cc.get_supported_arguments('-funroll-loops', '-fomit-frame-pointer'), language: 'c', ) endif # When tcl_alloc is enabled, define MP_MALLOC etc. so libtommath declares them # as extern functions rather than using stdlib malloc/free. The consuming Tcl # extension must provide the implementations (tommath_malloc, tommath_realloc, # tommath_calloc, tommath_free) that forward to Tcl's ckalloc/ckrealloc/ckfree. # This is necessary because Tcl frees mp_int digit arrays from bignum Tcl_Objs # with ckfree, so they must have been allocated with ckalloc. tcl_compat_args = [] if get_option('tcl_alloc') tcl_compat_args += [ '-DMP_MALLOC=tommath_malloc', '-DMP_REALLOC=tommath_realloc', '-DMP_CALLOC=tommath_calloc', '-DMP_FREE=tommath_free', ] endif # Match the mp_digit width of the target Tcl. Tcl 8.6 forces 32-bit digits # (unsigned int) while standalone libtommath 1.3.0 defaults to 64-bit on # 64-bit platforms. mp_int structs cross the boundary via Tcl_NewBignumObj, # so the digit width must agree. _mp_digit_size = get_option('mp_digit_size') if _mp_digit_size == 4 tcl_compat_args += '-DMP_32BIT' elif _mp_digit_size == 2 tcl_compat_args += '-DMP_16BIT' elif _mp_digit_size == 1 tcl_compat_args += '-DMP_8BIT' endif # 8 (or 0) → use libtommath's default 64-bit digits on 64-bit platforms libtommath = static_library( 'tommath', sources, install: false, include_directories: inc, c_args: tcl_compat_args + (cc.get_id() in ['msvc', 'clang-cl'] ? [ # MSVC defaults to IEEE754 since VS 2010, but doesn't set the macro. # Can't use add_project_arguments here because that enables tests that contain # literal division by zero, which breaks compilation. '/fp:precise', '-D__STDC_IEC_559__', ] : []), ) # Install headers #install_headers(files('tommath.h')) # Generate pkg-config file #pkg = import('pkgconfig') #pkg.generate( # libtommath, # name: meson.project_name(), # description: 'public domain library for manipulating large integer numbers', # url: 'https://www.libtom.net/LibTomMath/', #) # Create a dependency object for use by other projects # This makes the library usable as a Meson subproject libtommath_dep = declare_dependency( link_with: libtommath, include_directories: inc, ) # Make the dependency available to parent projects meson.override_dependency('libtommath', libtommath_dep) # Build and run unit tests if requested if get_option('tests') if not meson.can_run_host_binaries() error( 'Cannot run tests: cross-compilating and no host binary helper available', ) endif libtommath_for_tests = libtommath if cc.get_id() in ['msvc', 'clang-cl'] if get_option('default_library') == 'shared' error('Static library build is required to run tests with MSVC/clang-cl') endif libtommath_for_tests = libtommath.get_static_lib() endif tommath_test_exe = executable( 'tommath_test', ['demo/test.c', 'demo/shared.c'], link_with: libtommath_for_tests, include_directories: inc, build_by_default: false, ) mtest_opponent_exe = executable( 'mtest_opponent', ['demo/mtest_opponent.c', 'demo/shared.c'], link_with: libtommath_for_tests, include_directories: inc, build_by_default: false, ) # Build mtest - reference implementation for differential testing # Note: mtest.c includes mpi.c directly, so we only compile mtest.c # Have to disable optimization when building mpi.c or the test fails # due to bugs in mpi.c mtest_exe = executable( 'mtest', 'mtest/mtest.c', include_directories: include_directories('mtest'), override_options: ['optimization=0'], c_args: cc.get_id() == 'clang-cl' ? [ # For some reason the optimization=0 override doesn't work properly with clang-cl '/Od', ] : [], build_by_default: false, ) test('tommath_test', tommath_test_exe) # Differential test: mtest generates test cases, mtest_opponent validates them # Usage: mtest | mtest_opponent test( 'mtest_opponent', find_program( 'run_mtest.py', native: true, ), args: [ mtest_exe.full_path(), mtest_opponent_exe.full_path(), # Iteration count can be added using --test-args, default is 1000 ], depends: [mtest_exe, mtest_opponent_exe], timeout: 30, suite: 'differential', ) endif if get_option('benchmarks') if not meson.can_run_host_binaries() error( 'Cannot run benchmarks: cross-compilating and no host binary helper available', ) endif timing_exe = executable( 'timing', 'demo/timing.c', link_with: libtommath, c_args: ['-DTIMER'], include_directories: inc, build_by_default: false, ) # Create logs directory in build root for benchmark output (timings binary segfaults without it) python_mkdir = [ find_program( 'python3', native: true, ), '-c', 'import os, sys; os.makedirs(sys.argv[1]) if not os.path.exists(sys.argv[1]) else None', ] run_command( python_mkdir, meson.project_build_root() / 'logs', check: true, ) benchmark( 'benchmarks', timing_exe, timeout: 30, ) endif # Documentation target - build PDF manual from LaTeX sources if get_option('docs') # Find LaTeX tools (these may not be installed) latex = find_program( 'latex', required: true, ) pdflatex = find_program( 'pdflatex', required: true, ) makeindex = find_program( 'makeindex', required: true, ) custom_target( 'docs', input: 'doc/bn.tex', output: '@0@-@1@.pdf'.format(meson.project_name(), meson.project_version()), command: [ find_program( 'doc/build-manual.py', native: true, ), '@INPUT@', '@OUTDIR@', '@OUTPUT@', ], env: environment( { 'LATEX': latex.full_path(), 'PDFLATEX': pdflatex.full_path(), 'MAKEINDEX': makeindex.full_path(), }, ), console: true, install: false, install_dir: get_option('datadir') / 'doc' / 'libtommath', ) endif cyanogilvie-teabase-9345a87/subprojects/packagefiles/libtommath/meson_options.txt000066400000000000000000000015001526245020600304670ustar00rootroot00000000000000option( 'tests', type: 'boolean', value: false, description: 'Build and run unit tests', ) option( 'benchmarks', type: 'boolean', value: false, description: 'Build and run benchmarks', ) option( 'docs', type: 'boolean', value: false, description: 'Build PDF documentation from LaTeX sources', ) option( 'tcl_alloc', type: 'boolean', value: false, description: 'Use Tcl allocator (ckalloc/ckrealloc/ckfree) via external tommath_malloc/etc. shims. The consuming project must provide the shim function implementations.', ) option( 'mp_digit_size', type: 'integer', value: 0, description: 'Target mp_digit size in bytes. When non-zero, forces the digit width to match (e.g. 4 for Tcl 8.6, 8 for Tcl 9 on 64-bit). 0 means use libtommath defaults.', ) cyanogilvie-teabase-9345a87/subprojects/packagefiles/libtommath/run_mtest.py000066400000000000000000000013271526245020600274330ustar00rootroot00000000000000#!/usr/bin/env python3 import sys import subprocess # Get executables from arguments mtest, mtest_opponent = sys.argv[1:3] # Get iteration count from command line (default 1000) iterations = sys.argv[3] if len(sys.argv) > 3 else '1000' # Run mtest and pipe its output to mtest_opponent mtest_proc = subprocess.Popen([mtest, iterations], stdout=subprocess.PIPE) mtest_opponent_proc = subprocess.Popen([mtest_opponent], stdin=mtest_proc.stdout) # Close mtest stdout in parent to allow proper SIGPIPE handling mtest_proc.stdout.close() # Wait for both processes to complete mtest_opponent_proc.wait() mtest_proc.wait() # Exit with mtest_opponent's exit code (standard pipe behavior) sys.exit(mtest_opponent_proc.returncode) cyanogilvie-teabase-9345a87/subprojects/packagefiles/re2c/000077500000000000000000000000001526245020600235315ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/subprojects/packagefiles/re2c/meson.build000066400000000000000000000105201526245020600256710ustar00rootroot00000000000000# Minimal re2c build from pre-generated bootstrap sources. # Only builds the C-language re2c executable needed for lexer generation. project( 're2c', 'cpp', version: '4.3', license: 'Unlicense', default_options: [ 'cpp_std=c++11', 'warning_level=0', ], meson_version: '>=1.3.0', ) cpp = meson.get_compiler('cpp') # re2c is spawned once per cdef compile; for a JIT that launch cost is paid at # runtime. A dynamically linked C++ binary spends most of its startup in the # dynamic loader (relocating libstdc++/libgcc and resolving symbols). re2c is a # self-contained text transform (no dlopen/NSS/locale needs), so link it fully # statically to drop the loader entirely; fall back to a static C++ runtime # (libc dynamic) where a full static link isn't supported. re2c_link_args = cpp.get_supported_link_arguments('-static') if re2c_link_args.length() == 0 re2c_link_args = cpp.get_supported_link_arguments( '-static-libstdc++', '-static-libgcc', ) endif conf_data = configuration_data() conf_data.set_quoted('PROJECT_VERSION', meson.project_version()) defines = ['-DPACKAGE_VERSION=' + conf_data.get('PROJECT_VERSION')] foreach header : ['sys/types.h', 'sys/stat.h', 'fcntl.h', 'unistd.h', 'io.h'] name = 'HAVE_' + header.underscorify().to_upper() conf_data.set10(name, cpp.has_header(header)) defines += ['-D@0@=@1@'.format(name, conf_data.get(name))] endforeach defines += [ '-DRE2C_STDLIB_DIR=""', ] configure_file( output: 'config.h', configuration: conf_data, ) # Copy bootstrap generated files to build dir so that includes like # "src/parse/lexer.h" resolve via the build dir include path python = find_program('python3') run_command(python, '-c', 'import shutil; shutil.copytree("bootstrap/src", "src", dirs_exist_ok=True)', check: true, ) _pkg_install_dir = get_option('pkg_install_dir') re2c_exe = executable('re2c', [ 'bootstrap/src/default_syntax_c.h', 'bootstrap/src/msg/help_re2c.cc', 'bootstrap/src/msg/ver_to_vernum.cc', 'bootstrap/src/options/parse_opts.cc', 'bootstrap/src/parse/conf_lexer.cc', 'bootstrap/src/parse/conf_parser.cc', 'bootstrap/src/parse/conf_parser.h', 'bootstrap/src/parse/lexer.cc', 'bootstrap/src/parse/lexer.h', 'bootstrap/src/parse/parser.cc', 'bootstrap/src/parse/parser.h', 'src/adfa/adfa.cc', 'src/cfg/cfg.cc', 'src/cfg/compact.cc', 'src/cfg/dce.cc', 'src/cfg/freeze.cc', 'src/cfg/interfere.cc', 'src/cfg/liveanal.cc', 'src/cfg/normalize.cc', 'src/cfg/optimize.cc', 'src/cfg/rename.cc', 'src/cfg/varalloc.cc', 'src/codegen/helpers.cc', 'src/codegen/output.cc', 'src/codegen/pass1_analyze.cc', 'src/codegen/pass2_generate.cc', 'src/codegen/pass3_fixup.cc', 'src/codegen/pass4_render.cc', 'src/debug/dump_adfa.cc', 'src/debug/dump_cfg.cc', 'src/debug/dump_dfa.cc', 'src/debug/dump_dfa_tree.cc', 'src/debug/dump_interf.cc', 'src/debug/dump_nfa.cc', 'src/dfa/closure.cc', 'src/dfa/dead_rules.cc', 'src/dfa/determinization.cc', 'src/dfa/fallback_tags.cc', 'src/dfa/fillpoints.cc', 'src/dfa/find_state.cc', 'src/dfa/minimization.cc', 'src/dfa/tagver_table.cc', 'src/dfa/tcmd.cc', 'src/encoding/ebcdic.cc', 'src/encoding/enc.cc', 'src/encoding/range_suffix.cc', 'src/encoding/utf16.cc', 'src/encoding/utf8.cc', 'src/main.cc', 'src/msg/msg.cc', 'src/msg/warn.cc', 'src/nfa/re_to_nfa.cc', 'src/options/opt.cc', 'src/options/symtab.cc', 'src/parse/ast.cc', 'src/parse/input.cc', 'src/regexp/ast_to_re.cc', 'src/regexp/default_tags.cc', 'src/regexp/fixed_tags.cc', 'src/regexp/nullable.cc', 'src/regexp/regexp.cc', 'src/regexp/split_charset.cc', 'src/skeleton/control_flow.cc', 'src/skeleton/generate_code.cc', 'src/skeleton/generate_data.cc', 'src/skeleton/maxpath.cc', 'src/skeleton/skeleton.cc', 'src/util/file_utils.cc', 'src/util/range.cc', 'src/util/string_utils.cc', ], include_directories: include_directories('.'), cpp_args: defines, link_args: re2c_link_args, install: _pkg_install_dir != '', install_dir: _pkg_install_dir != '' ? _pkg_install_dir : [], ) meson.override_dependency(meson.project_name(), declare_dependency( variables: { 'prog': re2c_exe.full_path(), }, )) meson.override_find_program('re2c', re2c_exe) cyanogilvie-teabase-9345a87/subprojects/packagefiles/re2c/meson.options000066400000000000000000000002161526245020600262660ustar00rootroot00000000000000option('pkg_install_dir', type: 'string', value: '', description: 'Package install directory for the re2c binary (empty = do not install)') cyanogilvie-teabase-9345a87/subprojects/packagefiles/tcl/000077500000000000000000000000001526245020600234605ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/subprojects/packagefiles/tcl/meson.build000066400000000000000000000422561526245020600256330ustar00rootroot00000000000000project('tcl', 'c', version: '9.0.3', default_options: ['c_std=gnu11', 'werror=false', 'warning_level=1'], ) cc = meson.get_compiler('c') is_win = host_machine.system() == 'windows' generic_inc = include_directories('generic') compat_zlib_inc = include_directories('compat/zlib', 'compat/zlib/contrib/minizip') platform_inc = include_directories(is_win ? 'win' : 'unix') override_opts = ['werror=false', 'warning_level=1'] # --- Dependencies --- zlib_dep = dependency('zlib', required: false) tommath_dep = dependency('libtommath', version: '>=1.3.0', allow_fallback: true) if not zlib_dep.found() # Use Tcl's bundled zlib sources bundled_zlib = static_library('tclzlib', 'compat/zlib/adler32.c', 'compat/zlib/compress.c', 'compat/zlib/crc32.c', 'compat/zlib/deflate.c', 'compat/zlib/infback.c', 'compat/zlib/inffast.c', 'compat/zlib/inflate.c', 'compat/zlib/inftrees.c', 'compat/zlib/trees.c', 'compat/zlib/uncompr.c', 'compat/zlib/zutil.c', include_directories: compat_zlib_inc, override_options: override_opts, ) zlib_dep = declare_dependency( link_with: bundled_zlib, include_directories: compat_zlib_inc, ) endif # --- Common compile args --- dll_name = is_win ? 'tcl90.dll' : 'libtcl9.0.so' incdir = meson.project_source_root() / 'generic' builddir = meson.current_build_dir() tcl_library = meson.project_source_root() / 'library' tcl_args = [ '-DBUILD_tcl', '-DCFG_INSTALL_BINDIR="' + builddir + '"', '-DCFG_INSTALL_DOCDIR="' + builddir + '"', '-DCFG_INSTALL_INCDIR="' + incdir + '"', '-DCFG_INSTALL_LIBDIR="' + builddir + '"', '-DCFG_INSTALL_SCRDIR="' + tcl_library + '"', '-DCFG_RUNTIME_BINDIR="' + builddir + '"', '-DCFG_RUNTIME_DLLFILE="' + dll_name + '"', '-DCFG_RUNTIME_DOCDIR="' + builddir + '"', '-DCFG_RUNTIME_INCDIR="' + incdir + '"', '-DCFG_RUNTIME_LIBDIR="' + builddir + '"', '-DCFG_RUNTIME_SCRDIR="' + tcl_library + '"', '-DMP_FIXED_CUTOFFS', '-DMP_PREC=4', '-DPACKAGE_NAME="tcl"', '-DPACKAGE_VERSION="' + meson.project_version() + '"', '-DTCL_WITH_EXTERNAL_TOMMATH', ] if is_win if cc.get_id() != 'msvc' tcl_args += '-DHAVE_NO_SEH=1' endif tcl_args += '-DUNICODE' tcl_args += '-D_UNICODE' tcl_args += '-DTCL_CFGVAL_ENCODING="utf-8"' tcl_args += '-DSTDC_HEADERS=1' tcl_args += '-DZIPFS_BUILD=1' elif not is_win if cc.has_function_attribute('visibility') tcl_args += '-DMODULE_SCOPE=extern __attribute__((__visibility__("hidden")))' tcl_args += '-DHAVE_HIDDEN=1' else tcl_args += '-DMODULE_SCOPE=extern' endif tcl_args += '-D_GNU_SOURCE' tcl_args += '-D_REENTRANT=1' tcl_args += '-D_THREAD_SAFE=1' foreach h : [ 'inttypes.h', 'langinfo.h', 'stdint.h', 'strings.h', 'sys/epoll.h', 'sys/eventfd.h', 'sys/ioctl.h', 'sys/param.h', 'sys/stat.h', 'sys/time.h', 'termios.h', 'unistd.h', ] if cc.has_header(h) tcl_args += '-DHAVE_' + h.underscorify().to_upper() + '=1' endif endforeach foreach pair : [ ['cfmakeraw', ''], ['cpuid', ''], ['freeaddrinfo', ''], ['fts', ''], ['gai_strerror', ''], ['getaddrinfo', ''], ['getcwd', ''], ['getnameinfo', ''], ['gmtime_r', ''], ['localtime_r', ''], ['mkstemp', ''], ['mkstemps', ''], ['posix_spawnp', ''], ['pselect', ''], ['vfork', ''], ['waitpid', ''], ] if cc.has_function(pair[0]) tcl_args += '-DHAVE_' + pair[0].to_upper() + '=1' endif endforeach if cc.has_header_symbol('sys/epoll.h', 'epoll_create') tcl_args += '-DNOTIFIER_EPOLL=1' endif if cc.has_function('eventfd') tcl_args += '-DHAVE_EVENTFD=1' endif if cc.has_member('struct stat', 'st_blocks', prefix: '#include ') tcl_args += '-DHAVE_STRUCT_STAT_ST_BLOCKS=1' endif if cc.has_member('struct stat', 'st_blksize', prefix: '#include ') tcl_args += '-DHAVE_STRUCT_STAT_ST_BLKSIZE=1' endif if cc.has_member('struct tm', 'tm_gmtoff', prefix: '#include ') tcl_args += '-DHAVE_TM_GMTOFF=1' endif if cc.compiles('extern int timezone;\nint main(){return timezone;}') tcl_args += '-DHAVE_TIMEZONE_VAR=1' endif if cc.has_type('intptr_t', prefix: '#include ') tcl_args += '-DHAVE_INTPTR_T=1' endif if cc.has_type('uintptr_t', prefix: '#include ') tcl_args += '-DHAVE_UINTPTR_T=1' endif if cc.sizeof('long') >= 8 tcl_args += '-DTCL_WIDE_INT_IS_LONG=1' endif net_prefix = '#include \n#include \n#include ' foreach s : ['addrinfo', 'in6_addr', 'sockaddr_in6', 'sockaddr_storage'] if cc.has_type('struct ' + s, prefix: net_prefix) tcl_args += '-DHAVE_STRUCT_' + s.to_upper() + '=1' endif endforeach if cc.has_function('pthread_attr_setstacksize', prefix: '#include ') tcl_args += '-DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1' endif if cc.has_function('pthread_atfork', prefix: '#include ') tcl_args += '-DHAVE_PTHREAD_ATFORK=1' endif tcl_args += '-DHAVE_BLKCNT_T=1' tcl_args += '-DHAVE_SIGNED_CHAR=1' tcl_args += '-D_LARGEFILE64_SOURCE=1' tcl_args += '-DNO_UNION_WAIT=1' tcl_args += '-DSTDC_HEADERS=1' tcl_args += '-DTCL_CFGVAL_ENCODING="utf-8"' tcl_args += '-DTCL_LIBRARY="' + tcl_library + '"' tcl_args += '-DTCL_PACKAGE_PATH="' + tcl_library + '"' tcl_args += '-DTCL_SHLIB_EXT=".so"' tcl_args += '-DTCL_UNLOAD_DLLS=1' tcl_args += '-DZIPFS_BUILD=1' if cc.has_function('dladdr', prefix: '#define _GNU_SOURCE\n#include ') tcl_args += '-DHAVE_DLADDR=1' endif endif fs = import('fs') # --- Generated headers --- # tclUuid.h — derived from fossil manifest.uuid manifest_uuid = fs.read('manifest.uuid').strip() uuid_conf = configuration_data() uuid_conf.set('UUID', manifest_uuid) tclUuid_h = configure_file( input: 'tclUuid.h.in', output: 'tclUuid.h', configuration: uuid_conf, ) # --- Source files --- generic_sources = files( 'generic/regcomp.c', 'generic/regerror.c', 'generic/regexec.c', 'generic/regfree.c', 'generic/tclAlloc.c', 'generic/tclArithSeries.c', 'generic/tclAssembly.c', 'generic/tclAsync.c', 'generic/tclBasic.c', 'generic/tclBinary.c', 'generic/tclCkalloc.c', 'generic/tclClock.c', 'generic/tclClockFmt.c', 'generic/tclCmdAH.c', 'generic/tclCmdIL.c', 'generic/tclCmdMZ.c', 'generic/tclCompCmds.c', 'generic/tclCompCmdsGR.c', 'generic/tclCompCmdsSZ.c', 'generic/tclCompExpr.c', 'generic/tclCompile.c', 'generic/tclConfig.c', 'generic/tclDate.c', 'generic/tclDictObj.c', 'generic/tclDisassemble.c', 'generic/tclEncoding.c', 'generic/tclEnsemble.c', 'generic/tclEnv.c', 'generic/tclEvent.c', 'generic/tclExecute.c', 'generic/tclFCmd.c', 'generic/tclFileName.c', 'generic/tclGet.c', 'generic/tclHash.c', 'generic/tclHistory.c', 'generic/tclIcu.c', 'generic/tclIndexObj.c', 'generic/tclInterp.c', 'generic/tclIO.c', 'generic/tclIOCmd.c', 'generic/tclIOGT.c', 'generic/tclIORChan.c', 'generic/tclIORTrans.c', 'generic/tclIOSock.c', 'generic/tclIOUtil.c', 'generic/tclLink.c', 'generic/tclListObj.c', 'generic/tclLiteral.c', 'generic/tclLoad.c', 'generic/tclMain.c', 'generic/tclNamesp.c', 'generic/tclNotify.c', 'generic/tclObj.c', 'generic/tclOptimize.c', 'generic/tclPanic.c', 'generic/tclParse.c', 'generic/tclPathObj.c', 'generic/tclPipe.c', 'generic/tclPkg.c', 'generic/tclPkgConfig.c', 'generic/tclPosixStr.c', 'generic/tclPreserve.c', 'generic/tclProc.c', 'generic/tclProcess.c', 'generic/tclRegexp.c', 'generic/tclResolve.c', 'generic/tclResult.c', 'generic/tclScan.c', 'generic/tclStrIdxTree.c', 'generic/tclStringObj.c', 'generic/tclStrToD.c', 'generic/tclStubInit.c', 'generic/tclThreadAlloc.c', 'generic/tclThread.c', 'generic/tclThreadJoin.c', 'generic/tclThreadStorage.c', 'generic/tclTimer.c', 'generic/tclTomMathInterface.c', 'generic/tclTrace.c', 'generic/tclUtf.c', 'generic/tclUtil.c', 'generic/tclVar.c', 'generic/tclZipfs.c', 'generic/tclZlib.c', ) oo_sources = files( 'generic/tclOOBasic.c', 'generic/tclOO.c', 'generic/tclOOCall.c', 'generic/tclOODefineCmds.c', 'generic/tclOOInfo.c', 'generic/tclOOMethod.c', 'generic/tclOOProp.c', 'generic/tclOOStubInit.c', ) if is_win platform_sources = files( 'win/tclWin32Dll.c', 'win/tclWinChan.c', 'win/tclWinConsole.c', 'win/tclWinError.c', 'win/tclWinFCmd.c', 'win/tclWinFile.c', 'win/tclWinInit.c', 'win/tclWinLoad.c', 'win/tclWinNotify.c', 'win/tclWinPipe.c', 'win/tclWinSerial.c', 'win/tclWinSock.c', 'win/tclWinThrd.c', 'win/tclWinTime.c', ) # tclWinPanic.c provides Tcl_ConsolePanic — linked into both the DLL # and tclsh directly (the symbol isn't dllexport'd) platform_sources += files('win/tclWinPanic.c') tclsh_sources = files('win/tclAppInit.c', 'win/tclWinPanic.c') platform_deps = [ cc.find_library('ws2_32'), cc.find_library('netapi32'), cc.find_library('user32'), cc.find_library('userenv'), ] tclsh_link_args = cc.get_id() != 'msvc' ? ['-mconsole', '-municode'] : [] else platform_sources = files( 'unix/tclEpollNotfy.c', 'unix/tclKqueueNotfy.c', 'unix/tclLoadDl.c', 'unix/tclSelectNotfy.c', 'unix/tclUnixChan.c', 'unix/tclUnixCompat.c', 'unix/tclUnixEvent.c', 'unix/tclUnixFCmd.c', 'unix/tclUnixFile.c', 'unix/tclUnixInit.c', 'unix/tclUnixPipe.c', 'unix/tclUnixSock.c', 'unix/tclUnixThrd.c', 'unix/tclUnixTime.c', ) tclsh_sources = files('unix/tclAppInit.c') platform_deps = [ cc.find_library('dl', required: false), cc.find_library('pthread', required: false), cc.find_library('m', required: false), ] endif # --- Shared library --- build_inc = include_directories('.') tcllib = shared_library( is_win ? 'tcl90' : 'tcl9.0', generic_sources, oo_sources, platform_sources, include_directories: [generic_inc, compat_zlib_inc, platform_inc, build_inc], c_args: tcl_args, dependencies: [zlib_dep, tommath_dep] + platform_deps, override_options: override_opts, name_prefix: is_win ? '' : 'lib', gnu_symbol_visibility: is_win ? 'default' : 'hidden', install: true, # Plain `${prefix}/lib`, not get_option('libdir') — Tcl's own # autoconf install convention is to ignore Debian-style multiarch # subdirs. Downstream Tcl extensions discover libtcl9 via the # tcl.pc / declare_dependency machinery, not via ld config, so it's # cleaner to keep the layout flat regardless of host triple. install_dir: 'lib', install_tag: meson.is_subproject() ? 'deps' : 'runtime', ) # --- Stubs library --- stub_args = cc.get_supported_arguments('-g0', '-fno-lto') + [ '-DCFG_RUNTIME_BINDIR="' + builddir + '"', '-DCFG_RUNTIME_DLLFILE="' + dll_name + '"', '-DCFG_RUNTIME_LIBDIR="' + builddir + '"', '-DMP_FIXED_CUTOFFS', '-DTCL_WITH_EXTERNAL_TOMMATH', ] if not is_win stub_args += '-DMODULE_SCOPE=extern' endif tclstub = static_library('tclstub', 'generic/tclOOStubLib.c', 'generic/tclStubCall.c', 'generic/tclStubLib.c', 'generic/tclStubLibTbl.c', 'generic/tclTomMathStubLib.c', include_directories: [generic_inc, platform_inc], dependencies: tommath_dep.partial_dependency(compile_args: true, includes: true), c_args: stub_args, override_options: override_opts, install: true, # Needed to prevent meson creating a thin archive install_dir: 'lib', install_tag: 'deps', ) # --- ZipFS: embed library scripts --- exe_suffix = is_win ? '.exe' : '' zip_prog = find_program('zip', native: true) srcroot = meson.project_source_root() outdir = meson.current_build_dir() zip_output = 'libtcl@0@.zip'.format(meson.project_version()) tcl_zip = custom_target('tcl-zipfs', output: zip_output, input: tcllib, command: [ 'sh', '-c', 'set -e && ' + 'rm -rf @0@/libtcl.vfs && '.format(outdir) + 'mkdir -p @0@/libtcl.vfs/tcl_library && '.format(outdir) + 'cp -a @0@/library/* @1@/libtcl.vfs/tcl_library/ && '.format(srcroot, outdir) + 'if [ -f @0@/libtcl.vfs/tcl_library/manifest.txt ]; then '.format(outdir) + 'mv @0@/libtcl.vfs/tcl_library/manifest.txt @0@/libtcl.vfs/tcl_library/pkgIndex.tcl; '.format(outdir) + 'fi && ' + 'cd @0@/libtcl.vfs && @1@ -rq @2@/@3@ *'.format(outdir, zip_prog.full_path(), outdir, zip_output), ], ) # --- tclsh --- tclsh_name = 'tclsh' + meson.project_version().split('.')[0] + '.' + meson.project_version().split('.')[1] tclsh_exe = executable(tclsh_name + '-base', tclsh_sources, include_directories: [generic_inc, platform_inc], c_args: tcl_args, # `$ORIGIN/../lib` so the installed tclsh in ${prefix}/bin can find # libtcl9.0.so in ${prefix}/lib without LD_LIBRARY_PATH or system # ldconfig wiring. Set via -Wl,-rpath rather than meson's # install_rpath because the tclsh-zipfs custom_target copies this # binary at build time and the copy is what gets installed — # bypassing meson's install-time rpath patching. Setting the rpath # at link time bakes it into the binary so the copy preserves it. link_args: (is_win ? tclsh_link_args : []) + (is_win ? [] : ['-Wl,-rpath,$ORIGIN/../lib']), link_with: [tcllib, tclstub], dependencies: [zlib_dep, tommath_dep] + platform_deps, override_options: override_opts, ) # Append the zipfs archive to tclsh so it can find its init scripts tclsh = custom_target('tclsh-zipfs', output: tclsh_name + exe_suffix, input: [tclsh_exe, tcl_zip], command: [ 'sh', '-c', 'cp "$1" "$3" && cat "$2" >> "$3" && chmod +x "$3"', 'sh', '@INPUT0@', '@INPUT1@', '@OUTPUT@', ], build_by_default: true, install: true, install_dir: 'bin', install_tag: meson.is_subproject() ? 'deps' : 'runtime', ) if host_machine.system() != 'windows' # Plain `tclsh` symlink so downstream consumers can rely on a # version-agnostic name on PATH. Symlink is created at install # time (the meson.add_install_script below); the build-tree symlink # produced by this custom_target is consumed by `meson devenv`. custom_target( output: 'tclsh' + exe_suffix, command: [find_program('ln', native: true), '-sf', tclsh_name + exe_suffix, '@OUTPUT@'], build_by_default: true, ) meson.add_install_script(find_program('sh', native: true), '-c', 'set -e; cd "$DESTDIR$MESON_INSTALL_PREFIX/bin" && ln -sf @0@@1@ tclsh@1@'.format( tclsh_name, exe_suffix), install_tag: meson.is_subproject() ? 'deps' : 'runtime', ) endif tcl_library = meson.project_source_root() / 'library' exec_prefix = meson.current_build_dir() # Point TCL_LIBRARY at the source tree so tclsh can find init.tcl meson.add_devenv({'TCL_LIBRARY': tcl_library}) # --- Public headers --- # Downstream Tcl extensions need tcl.h + the public stubs decls + the # tommath headers Tcl re-exposes for TclBN. Match the canonical Tcl # install set (the system tcl.pc's Cflags assume these are present). public_headers = files( 'generic/tcl.h', 'generic/tclDecls.h', 'generic/tclOO.h', 'generic/tclOODecls.h', 'generic/tclPlatDecls.h', 'generic/tclTomMath.h', 'generic/tclTomMathDecls.h', ) install_data(public_headers, install_dir: 'include', install_tag: 'deps', ) # --- pkg-config metadata --- pc_conf = configuration_data() pc_conf.set('PREFIX', get_option('prefix')) pc_conf.set('VERSION', meson.project_version()) configure_file( input: 'tcl.pc.in', output: 'tcl.pc', configuration: pc_conf, install: true, install_dir: 'lib' / 'pkgconfig', install_tag: 'deps', ) # --- Dependency for consuming projects --- # # `libdir` here is the *install* libdir, used by consumer install_dir # computations (`tcl_dep.get_variable('libdir') / 'pkgconfig'`, etc.) # so .pc and per-package dirs land in the right place. The build-time # libtclstub for the wrap-fallback case is exposed via `link_with` # below — consumers that need it use `tcl_dep.partial_dependency(links: # true)`, not find_library against this libdir variable. tcl_dep = declare_dependency( include_directories: generic_inc, link_with: tclstub, # tclTomMath.h does `#include "tommath.h"` unless TCL_NO_TOMMATH_H is # defined, so any consumer that pulls in (e.g. for the # TclBN stubs in Tcl 9) needs libtommath's headers on the compile line. # Tcl itself is built with -DTCL_WITH_EXTERNAL_TOMMATH and links against # tommath_dep; we propagate the compile-only parts of that dep through # tcl_dep so downstream packages don't have to re-declare it themselves. dependencies: [tommath_dep.partial_dependency(compile_args: true, includes: true)], version: meson.project_version(), variables: { # Mirror the tcl.pc variables so consumers can use a uniform # tcl_dep.get_variable('NAME') call regardless of whether tcl came # from pkg-config or from this wrap. 'prefix': get_option('prefix'), 'libdir': get_option('prefix') / 'lib', 'exec_prefix': get_option('prefix'), 'source_root': meson.project_source_root(), 'tcl_library': tcl_library, }, ) cyanogilvie-teabase-9345a87/subprojects/packagefiles/tcl/tcl.pc.in000066400000000000000000000013661526245020600252010ustar00rootroot00000000000000# tcl pkg-config source file (wrap fallback build). # # Layout assumes the install pattern produced by this wrap: # tcl9.0 → ${prefix}/lib, tcl headers → ${prefix}/include, # tclsh → ${prefix}/bin. Resolved via ${pcfiledir} so the install # tree is relocatable. prefix=@PREFIX@ exec_prefix=${prefix} libdir=${prefix}/lib includedir=${prefix}/include libfile=libtcl9.0.so Name: Tool Command Language Description: Tcl is a powerful, easy-to-learn dynamic programming language, suitable for a wide range of uses. URL: https://www.tcl-lang.org/ Version: @VERSION@ Requires.private: libtommath >= 1.2.0, zlib >= 1.2.3 Libs: -L${libdir} -ltcl9.0 -ltclstub Libs.private: -ldl -lz -lpthread -lm -ltommath Cflags: -I${includedir} -DTCL_WITH_EXTERNAL_TOMMATH cyanogilvie-teabase-9345a87/subprojects/packagefiles/tcl/tclUuid.h.in000066400000000000000000000000421526245020600256430ustar00rootroot00000000000000#define TCL_VERSION_UUID \ @UUID@ cyanogilvie-teabase-9345a87/subprojects/packagefiles/tcllib/000077500000000000000000000000001526245020600241475ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/subprojects/packagefiles/tcllib/meson.build000066400000000000000000000032641526245020600263160ustar00rootroot00000000000000project('tcllib', version: '2.0', meson_version: '>=1.3.0', ) # Pure-Tcl bundle: tcllib ships ~80 sub-packages under modules/, each # with its own pkgIndex.tcl. The build phase is a no-op (no compile, # no codegen); install copies the whole tree so consumers can drop the # install dir on auto_path. tcl_dep = dependency('tcl') tclver_full = tcl_dep.version() tclver_major = tclver_full.split('.')[0] # Match the upstream tcllib install convention: modules go under # ${prefix}/lib/tcllib/. Tcl's auto_path scanner walks # subdirectories looking for pkgIndex.tcl, so this layout makes # `package require uri`, `package require inifile`, etc. resolve # without needing per-module entries. tm_install_dir = tcl_dep.get_variable('libdir') / 'tcllib' + meson.project_version() install_subdir('modules', install_dir: tm_install_dir, install_tag: meson.is_subproject() ? 'deps' : 'runtime', strip_directory: true, ) # Aggregator pkgIndex.tcl at the tcllib root — see comment in the file # itself. Without this, auto_path's one-level-deep scan finds # tcllib2.0/ but never descends into uri/, inifile/, log/, ... install_data('pkgIndex.tcl', install_dir: tm_install_dir, install_tag: meson.is_subproject() ? 'deps' : 'runtime', ) tcllib_dep = declare_dependency( variables: { # Build-time discovery: the source tree's modules/ is auto_path-able # as-is, so subproject consumers don't need to install first. 'tcl_pkg_path': meson.project_source_root() / 'modules', 'version': meson.project_version(), }, ) meson.override_dependency(meson.project_name(), tcllib_dep) # vim: foldmethod=marker foldmarker=<<<,>>> shiftwidth=2 expandtab cyanogilvie-teabase-9345a87/subprojects/packagefiles/tcllib/pkgIndex.tcl000066400000000000000000000013101526245020600264170ustar00rootroot00000000000000# Aggregator pkgIndex for tcllib's modules tree. # # Each tcllib subpackage (uri/, inifile/, log/, ...) ships its own # pkgIndex.tcl, but Tcl's tclPkgUnknown only walks one level below # auto_path entries. When this file is installed to # ${libdir}/tcllib/pkgIndex.tcl, auto_path traversal will pick # up THIS file (one level under ${libdir}) but not the subpackage # pkgIndexes (two levels deep). # # Workaround: append our own directory to auto_path here. Tcl's # tclPkgUnknown re-syncs against auto_path mid-scan, so this triggers # another pass that walks our subdirectories and finds the # subpackage pkgIndex.tcl files. if {[lsearch -exact $::auto_path $dir] == -1} { lappend ::auto_path $dir } cyanogilvie-teabase-9345a87/subprojects/packagefiles/thread/000077500000000000000000000000001526245020600241455ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/subprojects/packagefiles/thread/meson.build000066400000000000000000000126011526245020600263070ustar00rootroot00000000000000project('thread', 'c', version: '3.0.5', meson_version: '>=1.3.0', ) # Hand-written meson skeleton for the Thread Tcl extension # (https://core.tcl-lang.org/thread). Upstream uses TEA (autoconf + # Makefile.in); this skeleton just compiles the listed PKG_SOURCES # from configure.ac under stubs. Optional GDBM / LMDB / AOLserver # integration is intentionally omitted — the Thread extension builds # fine without them and aws-tcl doesn't use those features. cc = meson.get_compiler('c') fs = import('fs') tcl_dep = dependency('tcl') tclver_full = tcl_dep.version() tclver_parts = tclver_full.split('.') tclver_major = tclver_parts[0] # TEA's PKG_LIB_FILE9 convention for Tcl 9: lib.so # Tcl 8 uses lib.so without the prefix. We only target # Tcl 9 here (the tcl wrap is Tcl 9); hard-coding the prefix keeps the # pkgIndex.tcl substitution simple. lib_basename9 = 'tcl' + tclver_major + 'thread' + meson.project_version() lib_basename8 = 'thread' + meson.project_version() generic_sources = files( 'generic/threadNs.c', 'generic/threadCmd.c', 'generic/threadSvCmd.c', 'generic/threadSpCmd.c', 'generic/threadPoolCmd.c', 'generic/psGdbm.c', 'generic/psLmdb.c', 'generic/threadSvListCmd.c', 'generic/threadSvKeylistCmd.c', 'generic/tclXkeylist.c', ) platform_sources = [] if host_machine.system() != 'windows' platform_sources += files('unix/threadUnix.c') endif c_args = [ '-DUSE_TCL_STUBS=1', '-DBUILD_thread', '-DPACKAGE_NAME="' + meson.project_name() + '"', '-DPACKAGE_VERSION="' + meson.project_version() + '"', '-DMODULE_SCOPE=extern', ] # Stubs: subproject-fallback tcl bundles tclstub into tcl_dep itself, # while a system-resolved tcl_dep advertises its libdir for find_library. deps = [tcl_dep.partial_dependency(compile_args: true, includes: true)] if tcl_dep.type_name() == 'internal' deps += tcl_dep.partial_dependency(links: true) else deps += cc.find_library('tclstub', dirs: [tcl_dep.get_variable('libdir')]) endif # threadUuid.h is generated by upstream's Makefile from manifest.uuid; # generic/threadCmd.c does `#include "threadUuid.h"`. Same pattern as # tclUuid.h in the tcl wrap. Upstream's win/threadUuid.h.in is a # different shape (no @UUID@ placeholder — the makefile concatenates # manifest.uuid onto it), so we ship our own minimal template in the # overlay. manifest_uuid = fs.read('manifest.uuid').strip() uuid_conf = configuration_data() uuid_conf.set('UUID', manifest_uuid) thread_uuid_h = configure_file( input: 'threadUuid.h.in', output: 'threadUuid.h', configuration: uuid_conf, ) inc = [include_directories('generic'), include_directories('.')] pkg_dir_basename = meson.project_name() + meson.project_version() install_pkg_dir = (tcl_dep.type_name() == 'internal' ? 'lib' / pkg_dir_basename : tcl_dep.get_variable('libdir') / pkg_dir_basename) pkg_so = shared_library( lib_basename9, [generic_sources, platform_sources, thread_uuid_h], include_directories: inc, c_args: c_args, dependencies: deps, name_prefix: host_machine.system() == 'windows' ? '' : 'lib', gnu_symbol_visibility: 'default', install: true, install_dir: install_pkg_dir, install_tag: meson.is_subproject() ? 'deps' : 'runtime', ) # pkgIndex.tcl: configure with the lib filename Tcl 9 expects. The # upstream template references both PKG_LIB_FILE8 and PKG_LIB_FILE9; # only the matching branch fires at runtime based on `package vsatisfies`. pkgindex_conf = configuration_data() pkgindex_conf.set('PACKAGE_NAME', meson.project_name()) pkgindex_conf.set('PACKAGE_VERSION', meson.project_version()) pkgindex_conf.set('PKG_LIB_FILE9', 'lib' + lib_basename9 + '.so') pkgindex_conf.set('PKG_LIB_FILE8', 'lib' + lib_basename8 + '.so') configure_file( input: 'pkgIndex.tcl.in', output: 'pkgIndex.tcl', configuration: pkgindex_conf, install: true, install_dir: install_pkg_dir, install_tag: meson.is_subproject() ? 'deps' : 'runtime', ) # pkg-config metadata. Same convention as the other Tcl-extension # wraps: tcl_pkg_path lets downstream consumers locate the install via # `pkg-config --variable=tcl_pkg_path Thread`. pc_conf = configuration_data() pc_conf.set('PACKAGE_NAME', 'thread') pc_conf.set('PACKAGE_VERSION', meson.project_version()) pc_conf.set('PKG_DIR_BASENAME', pkg_dir_basename) configure_file( input: 'thread.pc.in', output: 'thread.pc', configuration: pc_conf, install: true, install_dir: tcl_dep.get_variable('libdir') / 'pkgconfig', install_tag: meson.is_subproject() ? 'deps' : 'runtime', ) # Override-dependency for meson subproject consumers. Variable # `tcl_pkg_path` mirrors the convention used by other Tcl extension # wraps in this tree — points at the directory holding the shared lib # + pkgIndex.tcl (i.e. the build dir while building, the install # pkg_dir after install). thread_dep = declare_dependency( variables: { 'tcl_pkg_path': fs.parent(pkg_so.full_path()), 'version': meson.project_version(), }, ) meson.override_dependency('thread', thread_dep) # Devenv so `meson devenv -C tclsh` picks Thread up. devenv = environment() devenv.prepend('TCLLIBPATH', fs.parent(pkg_so.full_path()), separator: ' ') meson.add_devenv(devenv) # vim: foldmethod=marker foldmarker=<<<,>>> shiftwidth=2 expandtab cyanogilvie-teabase-9345a87/subprojects/packagefiles/thread/thread.pc.in000066400000000000000000000011041526245020600263410ustar00rootroot00000000000000# pkg-config metadata for Thread (the Tcl threads C extension). # # Layout assumes the install pattern produced by this wrap: the # pkgIndex + libtcl9thread.so live in the per-package dir # under the resolving Tcl's libdir (tcl_dep.get_variable('libdir')). # Resolved via ${pcfiledir} so the install tree is relocatable. tcl_pkg_path=${pcfiledir}/../@PKG_DIR_BASENAME@ Name: @PACKAGE_NAME@ Description: The Thread Tcl extension — POSIX thread primitives + thread-shared variables for Tcl interpreters. URL: https://core.tcl-lang.org/thread Version: @PACKAGE_VERSION@ cyanogilvie-teabase-9345a87/subprojects/packagefiles/thread/threadUuid.h.in000066400000000000000000000000451526245020600270200ustar00rootroot00000000000000#define THREAD_VERSION_UUID \ @UUID@ cyanogilvie-teabase-9345a87/subprojects/parse_args.wrap000066400000000000000000000002241526245020600232770ustar00rootroot00000000000000[wrap-git] clone-recursive = true url = https://github.com/RubyLane/parse_args revision = v0.6.3 depth = 1 [provide] dependency_names = parse_args cyanogilvie-teabase-9345a87/subprojects/re2c.wrap000066400000000000000000000004651526245020600220130ustar00rootroot00000000000000[wrap-file] directory = re2c-4.3 source_url = https://github.com/skvadrik/re2c/releases/download/4.3/re2c-4.3.tar.xz source_filename = re2c-4.3.tar.xz source_hash = 51e88d6d6b6ab03eb7970276aca7e0db4f8e29c958b84b561d2fdcb8351c7150 patch_directory = re2c [provide] dependency_names = re2c program_names = re2c cyanogilvie-teabase-9345a87/subprojects/reuri.wrap000066400000000000000000000002161526245020600223000ustar00rootroot00000000000000[wrap-git] clone-recursive = true url = https://github.com/cyanogilvie/reuri revision = v0.16.5 depth = 1 [provide] dependency_names = reuri cyanogilvie-teabase-9345a87/subprojects/rl_http.wrap000066400000000000000000000002141526245020600226240ustar00rootroot00000000000000[wrap-git] clone-recursive = true url = https://github.com/RubyLane/rl_http revision = 1.26 depth = 1 [provide] dependency_names = rl_http cyanogilvie-teabase-9345a87/subprojects/rl_json.wrap000066400000000000000000000004501526245020600226200ustar00rootroot00000000000000[wrap-file] source_url = https://github.com/RubyLane/rl_json/releases/download/v0.17.6/rl_json-v0.17.6.tar.gz source_filename = rl_json-v0.17.6.tar.gz source_hash = c00da959d85ec1895ccf375f7551138d3a53a3d8af8387513b4370e007ca8655 directory = rl_json-v0.17.6 [provide] dependency_names = rl_json cyanogilvie-teabase-9345a87/subprojects/tcl-s2n.wrap000066400000000000000000000004301526245020600224320ustar00rootroot00000000000000[wrap-file] source_url = https://github.com/cyanogilvie/tcl-s2n/releases/download/v0.8.4/s2n-0.8.4.tar.gz source_hash = 15f442dfa2f3f65f930dc9abc5fe7589c9a68e5732f70c58962cc0cbe2d273a9 source_filename = s2n-0.8.4.tar.gz directory = s2n-0.8.4 [provide] dependency_names = tcl-s2n cyanogilvie-teabase-9345a87/subprojects/tcl.wrap000066400000000000000000000004131526245020600217330ustar00rootroot00000000000000[wrap-file] directory = tcl source_url = https://core.tcl-lang.org/tcl/tarball/core-9-0-3/tcl.tar.gz source_filename = tcl-core-9-0-3.tar.gz source_hash = 3d56fe35d1da7b229676c11131272de82cb9cae8fff3ce369e9b1cb5ce1066bd patch_directory = tcl [provide] tcl = tcl_dep cyanogilvie-teabase-9345a87/subprojects/tcllib.wrap000066400000000000000000000004541526245020600224270ustar00rootroot00000000000000[wrap-file] source_url = https://github.com/tcltk/tcllib/archive/refs/tags/tcllib-2-0.tar.gz source_filename = tcllib-2-0.tar.gz source_hash = c239f54cedc2fc11eb9fd5a7bbf2df1e12965937cd7fd1110e17383ec8f5e632 patch_directory = tcllib directory = tcllib-tcllib-2-0 [provide] dependency_names = tcllib cyanogilvie-teabase-9345a87/subprojects/tdom.wrap000066400000000000000000000002171526245020600221160ustar00rootroot00000000000000[wrap-git] clone-recursive = true url = https://github.com/RubyLane/tdom revision = cyan-0.9.6.11 depth = 1 [provide] dependency_names = tdom cyanogilvie-teabase-9345a87/subprojects/thread.wrap000066400000000000000000000004431526245020600224230ustar00rootroot00000000000000[wrap-file] directory = thread source_url = https://core.tcl-lang.org/thread/tarball/thread-3-0-5/thread.tar.gz source_filename = thread-3-0-5.tar.gz source_hash = 8c57eeb95565732ba984da3c647bf7fe032f5ed625c83bafe5131bcc39d67c2d patch_directory = thread [provide] dependency_names = thread cyanogilvie-teabase-9345a87/subprojects/tomcrypt.wrap000066400000000000000000000002271526245020600230350ustar00rootroot00000000000000[wrap-git] clone-recursive = true url = https://github.com/cyanogilvie/tcl-tomcrypt revision = v0.9.8 depth = 1 [provide] dependency_names = tomcrypt cyanogilvie-teabase-9345a87/subprojects/type.wrap000066400000000000000000000004201526245020600221300ustar00rootroot00000000000000[wrap-file] source_url = https://github.com/cyanogilvie/type/releases/download/v0.4/type-v0.4.tar.gz source_filename = type-v0.4.tar.gz source_hash = f95c6a4b8bc484082048fa5a1e37eb561b2f8144944b91e2299b34ff158057bf directory = type-v0.4 [provide] dependency_names = type cyanogilvie-teabase-9345a87/tclstuff.h000066400000000000000000000153661526245020600177330ustar00rootroot00000000000000// Written by Cyan Ogilvie, and placed in the public domain #ifndef _TCLSTUFF_H #define _TCLSTUFF_H #include /* Tcl 8.6 has no Tcl_Size (TIP 660): provide it as Tcl 8.7's tcl.h does. The * guards let this coexist with other polyfills (such as teabase's config.h * #define Tcl_Size int), whichever comes first. */ #if TCL_MAJOR_VERSION < 9 && !defined(TCL_SIZE_MAX) # ifndef Tcl_Size typedef int Tcl_Size; # endif # define TCL_SIZE_MAX ((int)(((unsigned int)-1)>>1)) # ifndef TCL_SIZE_MODIFIER # define TCL_SIZE_MODIFIER "" # endif #endif #define NEW_CMD( tcl_cmd, c_cmd ) \ Tcl_CreateObjCommand( interp, tcl_cmd, \ (Tcl_ObjCmdProc *) c_cmd, \ (ClientData *) NULL, NULL ) // THROW_ERROR / THROW_ERROR_LABEL: the args are strings that are // concatenated to form the error message, which replaces the interp result // (like THROW_PRINTF). Tcl_ResetResult isn't used since that would also clear // an -errorcode set just before the throw. #define THROW_ERROR( ... ) \ do { \ if (interp) { \ Tcl_SetObjResult(interp, Tcl_NewObj()); \ Tcl_AppendResult(interp, __VA_ARGS__, NULL); \ } \ return TCL_ERROR; \ } while(0) #define THROW_PRINTF( ... ) \ do { \ if (interp) Tcl_SetObjResult(interp, Tcl_ObjPrintf(__VA_ARGS__)); \ return TCL_ERROR; \ } while(0) #define THROW_POSIX(msg) \ do { \ int err = Tcl_GetErrno(); \ const char* errstr = Tcl_ErrnoId(); \ if (interp) Tcl_SetErrorCode(interp, "POSIX", errstr, Tcl_ErrnoMsg(err), NULL); \ THROW_PRINTF("%s: %s %s", msg, errstr, Tcl_ErrnoMsg(err)); \ } while(0) #define THROW_ERROR_LABEL( label, var, ... ) \ do { \ if (interp) { \ Tcl_SetObjResult(interp, Tcl_NewObj()); \ Tcl_AppendResult(interp, __VA_ARGS__, NULL); \ } \ var = TCL_ERROR; \ goto label; \ } while(0) #define THROW_PRINTF_LABEL( label, var, ... ) \ do { \ if (interp) Tcl_SetObjResult(interp, Tcl_ObjPrintf(__VA_ARGS__)); \ var = TCL_ERROR; \ goto label; \ } while(0) #define THROW_POSIX_LABEL(label, code, msg) \ do { \ int err = Tcl_GetErrno(); \ const char* errstr = Tcl_ErrnoId(); \ if (interp) Tcl_SetErrorCode(interp, "POSIX", errstr, Tcl_ErrnoMsg(err), NULL); \ THROW_PRINTF_LABEL(label, code, "%s: %s %s", msg, errstr, Tcl_ErrnoMsg(err)); \ } while(0) // convenience macro to check the number of arguments passed to a function // implementing a tcl command against the number expected, and to throw // a tcl error if they don't match. Note that the value of expected does // not include the objv[0] object (the function itself) #define CHECK_ARGS(msg) \ do { \ if (objc != A_objc) { \ if (interp) Tcl_WrongNumArgs(interp, A_cmd+1, objv, msg); \ return TCL_ERROR; \ } \ } while(0) #define CHECK_MIN_ARGS(msg) \ do { \ if (objc < A_args) { \ if (interp) Tcl_WrongNumArgs(interp, A_cmd+1, objv, msg); \ return TCL_ERROR; \ } \ } while(0) #define CHECK_RANGE_ARGS(msg) \ do { \ if (objc < A_args || objc > A_objc) { \ if (interp) Tcl_WrongNumArgs(interp, A_cmd+1, objv, msg); \ return TCL_ERROR; \ } \ } while(0) #define CHECK_ARGS_LABEL2(label, rc) \ do { \ if (objc != A_objc) { \ if (interp) Tcl_WrongNumArgs(interp, A_cmd+1, objv, NULL); \ rc = TCL_ERROR; \ goto label; \ } \ } while(0) #define CHECK_ARGS_LABEL3(label, rc, msg) \ do { \ if (objc != A_objc) { \ if (interp) Tcl_WrongNumArgs(interp, A_cmd+1, objv, sizeof(msg) > 1 ? msg : NULL); \ rc = TCL_ERROR; \ goto label; \ } \ } while(0) #define GET_CHECK_ARGS_LABEL_MACRO(_1,_2,_3,NAME,...) NAME #define CHECK_ARGS_LABEL(...) GET_CHECK_ARGS_LABEL_MACRO(__VA_ARGS__, CHECK_ARGS_LABEL3, CHECK_ARGS_LABEL2)(__VA_ARGS__) #define CHECK_MIN_ARGS_LABEL(label, rc, msg) \ do { \ if (objc < A_args) { \ if (interp) Tcl_WrongNumArgs(interp, A_cmd+1, objv, sizeof(msg) > 1 ? msg : NULL); \ rc = TCL_ERROR; \ goto label; \ } \ } while(0) #define CHECK_RANGE_ARGS_LABEL(label, rc, msg) \ do { \ if (objc < A_args || objc > A_objc) { \ if (interp) Tcl_WrongNumArgs(interp, A_cmd+1, objv, sizeof(msg) > 1 ? msg : NULL); \ rc = TCL_ERROR; \ goto label; \ } \ } while(0) // A rather frivolous macro that just enhances readability for a common case #define TEST_OK( cmd ) \ if (cmd != TCL_OK) return TCL_ERROR #define TEST_OK_LABEL( label, var, cmd ) \ if (cmd != TCL_OK) { \ var = TCL_ERROR; \ goto label; \ } #define TEST_OK_BREAK(var, cmd) if (TCL_OK != (var=(cmd))) break static inline void release_tclobj(Tcl_Obj** obj) { if (*obj) { Tcl_DecrRefCount(*obj); *obj = NULL; } } #define RELEASE_MACRO(obj) if (obj) {Tcl_DecrRefCount(obj); obj=NULL;} #define REPLACE_MACRO(target, replacement) \ do { \ release_tclobj(&target); \ if (replacement) Tcl_IncrRefCount(target = replacement); \ } while(0) static inline void replace_tclobj(Tcl_Obj** target, Tcl_Obj* replacement) { Tcl_Obj* old = *target; #if DEBUG if (*target && (*target)->refCount <= 0) Tcl_Panic("replace_tclobj target exists but has refcount <= 0: %" TCL_SIZE_MODIFIER "d", (*target)->refCount); #endif *target = replacement; if (*target) Tcl_IncrRefCount(*target); if (old) { Tcl_DecrRefCount(old); old = NULL; } } #if DEBUG # include # include # include # include "names.h" # define DBG(...) fprintf(stdout, __VA_ARGS__) # define FDBG(...) fprintf(stdout, __VA_ARGS__) # define DEBUGGER raise(SIGTRAP) # define TIME(label, task) \ do { \ struct timespec first; \ struct timespec second; \ struct timespec after; \ double empty; \ double delta; \ clock_gettime(CLOCK_MONOTONIC, &first); /* Warm up the call */ \ clock_gettime(CLOCK_MONOTONIC, &first); \ clock_gettime(CLOCK_MONOTONIC, &second); \ task; \ clock_gettime(CLOCK_MONOTONIC, &after); \ empty = second.tv_sec - first.tv_sec + (second.tv_nsec - first.tv_nsec)/1e9; \ delta = after.tv_sec - second.tv_sec + (after.tv_nsec - second.tv_nsec)/1e9 - empty; \ DBG("Time for %s: %.1f microseconds\n", label, delta * 1e6); \ } while(0) #else # define DBG(...) /* nop */ # define FDBG(...) /* nop */ # define DEBUGGER /* nop */ # define TIME(label, task) task #endif #define OBJCMD(name) int (name)(ClientData cdata, Tcl_Interp* interp, int objc, Tcl_Obj *const objv[]) #define INIT int init(Tcl_Interp* interp) #define RELEASE void release(Tcl_Interp* interp) #endif cyanogilvie-teabase-9345a87/teabase.m4000066400000000000000000000170551526245020600175730ustar00rootroot00000000000000builtin(include,teabase/ax_gcc_builtin.m4) builtin(include,teabase/ax_cc_for_build.m4) builtin(include,teabase/ax_check_compile_flag.m4) AC_DEFUN([TEABASE_INIT], [ # Test for -fprofile-partial-training, introduced in GCC 10 AX_CHECK_COMPILE_FLAG([-fprofile-partial-training], [AC_SUBST(PGO_BUILD,"-fprofile-use=prof -fprofile-partial-training")], [AC_SUBST(PGO_BUILD,"-fprofile-use=prof")], [-Werror]) ]) AC_DEFUN([ENABLE_DEBUG], [ #trap 'echo "val: (${enable_debug+set}), debug_ok: ($debug_ok), DEBUG: ($DEBUG)"' DEBUG AC_MSG_CHECKING([whether to support debuging]) AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],[Enable debug mode (not symbols, but portions of the code that are only used in debug builds) (default: no)]), [debug_ok=$enableval], [debug_ok=no]) if test "$debug_ok" = "yes" -o "${DEBUG}" = 1; then DEBUG=1 AC_MSG_RESULT([yes]) else DEBUG=0 AC_MSG_RESULT([no]) fi AC_DEFINE_UNQUOTED([DEBUG], [$DEBUG], [Debug enabled?]) #trap '' DEBUG ]) AC_DEFUN([ENABLE_UNLOAD], [ #trap 'echo "val: (${enable_unload+set}), unload_ok: ($unload_ok), UNLOAD: ($UNLOAD)"' DEBUG AC_MSG_CHECKING([whether to support unloading]) AC_ARG_ENABLE(unload, AS_HELP_STRING([--enable-unload],[Add support for unloading this shared library (default: no)]), [unload_ok=$enableval], [unload_ok=no]) if test "$unload_ok" = "yes" -o "${UNLOAD}" = 1; then UNLOAD=1 AC_MSG_RESULT([yes]) else UNLOAD=0 AC_MSG_RESULT([no]) fi AC_DEFINE_UNQUOTED([UNLOAD], [$UNLOAD], [Unload enabled?]) #trap '' DEBUG ]) AC_DEFUN([ENABLE_TESTMODE], [ #trap 'echo "val: (${enable_testmode+set}), testmode_ok: ($testmode_ok), TESTMODE: ($TESTMODE)"' DEBUG AC_MSG_CHECKING([whether to build in test mode]) AC_ARG_ENABLE(testmode, AS_HELP_STRING([--enable-testmode],[Build with whitebox testing hooks exposed (default: no)]), [testmode_ok=$enableval], [testmode_ok=no]) if test "$testmode_ok" = "yes" -o "${TESTMODE}" = 1; then TESTMODE=1 AC_MSG_RESULT([yes]) else TESTMODE=0 AC_MSG_RESULT([no]) fi AC_DEFINE_UNQUOTED([TESTMODE], [$TESTMODE], [Test mode enabled?]) #trap '' DEBUG ]) AC_DEFUN([CHECK_TESTMODE], [ AC_MSG_CHECKING([whether to build in test mode]) AC_ARG_ENABLE(testmode, [ --enable-testmode Build in test mode (default: off)], [enable_testmode=$enableval], [enable_testmode="no"]) AC_MSG_RESULT($enable_testmode) if test "$enable_testmode" = "yes" then AC_DEFINE(TESTMODE) fi ]) AC_DEFUN([TIP445], [ AC_MSG_CHECKING([whether we need to polyfill TIP 445]) saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $TCL_INCLUDE_SPEC" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[Tcl_ObjInternalRep ir;]])],[have_tcl_objintrep=yes],[have_tcl_objintrep=no]) CFLAGS="$saved_CFLAGS" if test "$have_tcl_objintrep" = yes; then AC_DEFINE(TIP445_SHIM, 0, [Do we need to polyfill TIP 445?]) AC_MSG_RESULT([no]) else AC_DEFINE(TIP445_SHIM, 1, [Do we need to polyfill TIP 445?]) AC_MSG_RESULT([yes]) fi ]) AC_DEFUN([CHECK_TCL_GETBYTESFROMOBJ], [ AC_MSG_CHECKING([whether we need to polyfill Tcl_GetBytesFromObj]) saved_CFLAGS="$CFLAGS" saved_LIBS="$LIBS" CFLAGS="$CFLAGS $TCL_INCLUDE_SPEC" LIBS="$LIBS $TCL_STUB_LIB_SPEC" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[Tcl_GetBytesFromObj(NULL, NULL, NULL);]])],[have_getbytes=yes],[have_getbytes=no]) CFLAGS="$saved_CFLAGS" LIBS="$saved_LIBS" if test "$have_getbytes" = yes; then AC_DEFINE(GETBYTES_SHIM, 0, [Do we need to polyfill Tcl_GetBytesFromObj?]) AC_MSG_RESULT([no]) else AC_DEFINE(GETBYTES_SHIM, 1, [Do we need to polyfill Tcl_GetBytesFromObj?]) AC_MSG_RESULT([yes]) fi ]) # All the best stuff seems to be Linux / glibc specific :( AC_DEFUN([CHECK_GLIBC], [ AC_MSG_CHECKING([for GNU libc]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ #if ! (defined __GLIBC__ || defined __GNU_LIBRARY__) # error "Not glibc" #endif ]])],[glibc=yes],[glibc=no]) if test "$glibc" = yes then AC_DEFINE(_GNU_SOURCE, 1, [Always define _GNU_SOURCE when using glibc]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ]) # We need a modified version of TEA_ADD_SOURCES because some of those files will be # generated *after* the macro runs, so it can't test for existence: AC_DEFUN([TEABASE_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) 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) ]) AC_DEFUN([DEDUP_STUBS], [ if test "${STUBS_BUILD}" = "1"; then AC_DEFINE(USE_DEDUP_STUBS, 1, [Use Dedup Stubs]) fi ]) AC_DEFUN([REURI_STUBS], [ if test "${STUBS_BUILD}" = "1"; then AC_DEFINE(USE_REURI_STUBS, 1, [Use ReURI Stubs]) fi ]) #------------------------------------------------------------------------ # HIGHEST_C_STANDARD # # Determines the highest C standard supported by the compiler. # Tests standards in descending order: C23, C17, C11, C99, C90. # # Arguments: # None # # Results: # Sets the following variables: # C_STD_CFLAGS - Compiler flags for the highest supported standard # C_STD_VERSION - The highest supported standard (e.g., "c23", "c17") #------------------------------------------------------------------------ AC_DEFUN([HIGHEST_C_STANDARD], [ AC_MSG_CHECKING([for highest supported C standard]) # Save current CFLAGS SAVE_CFLAGS_STD="$CFLAGS" # Test standards in descending order for std in c23 c17 c11 c99 c90; do CFLAGS="$SAVE_CFLAGS_STD -std=$std" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [C_STD_VERSION="$std" C_STD_CFLAGS="-std=$std" break], []) done # Restore CFLAGS CFLAGS="$SAVE_CFLAGS_STD" if test -n "$C_STD_VERSION"; then AC_MSG_RESULT([$C_STD_VERSION]) else AC_MSG_RESULT([none, using compiler default]) C_STD_CFLAGS="" C_STD_VERSION="default" fi AC_SUBST(C_STD_CFLAGS) AC_SUBST(C_STD_VERSION) ]) #------------------------------------------------------------------------ # CHECK_C23_EMBED # # Checks if the compiler supports the C23 #embed directive. # Should be called after HIGHEST_C_STANDARD if you want to use # the detected standard for testing. # # Arguments: # None # # Results: # Defines HAVE_C23_EMBED if #embed is supported #------------------------------------------------------------------------ AC_DEFUN([CHECK_C23_EMBED], [ AC_MSG_CHECKING([if compiler supports @%:@embed directive]) # Save current CFLAGS SAVE_CFLAGS_EMBED="$CFLAGS" # Use C_STD_CFLAGS if available, otherwise try with current flags if test -n "$C_STD_CFLAGS"; then CFLAGS="$SAVE_CFLAGS_EMBED $C_STD_CFLAGS" fi # Create a temporary test file to embed echo "test" > conftest_embed.txt AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ const char embedded_data@<:@@:>@ = { @%:@embed "conftest_embed.txt" , 0 }; int main(void) { return 0; } ]])], [AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_C23_EMBED], [1], [Define if compiler supports C23 @%:@embed directive]) have_c23_embed=yes], [AC_MSG_RESULT([no]) have_c23_embed=no]) # Clean up rm -f conftest_embed.txt # Restore CFLAGS CFLAGS="$SAVE_CFLAGS_EMBED" ]) cyanogilvie-teabase-9345a87/teabase_bench-0.1.tm000066400000000000000000000363251526245020600213270ustar00rootroot00000000000000package require math::statistics namespace eval ::teabase_bench { namespace export * variable match * variable run {} variable skipped {} variable skip {} # Override this to a new lambda to capture the output variable output { {lvl msg} {puts $msg} } namespace path [concat [namespace path] { ::tcl::mathop }] proc output {lvl msg} { #<<< variable output tailcall apply $output $lvl $msg } #>>> proc _intersect3 {list1 list2} { #<<< set firstonly {} set intersection {} set secondonly {} set list1 [lsort -unique $list1] set list2 [lsort -unique $list2] foreach item $list1 { if {[lsearch -sorted $list2 $item] == -1} { lappend firstonly $item } else { lappend intersection $item } } foreach item $list2 { if {[lsearch -sorted $intersection $item] == -1} { lappend secondonly $item } } list $firstonly $intersection $secondonly } #>>> proc _readfile fn { #<<< set h [open $fn r] try { read $h } finally { close $h } } #>>> proc _writefile {fn dat} { #<<< set h [open $fn w] try { puts -nonewline $h $dat } finally { close $h } } #>>> proc _run_if_set script { #<<< if {$script eq ""} return uplevel 2 $script } #>>> proc _pick {mode variant patterns} { #<<< set chain 0 set found 0 set res [lmap {pat e} $patterns { if {!$chain && ![string match $pat $variant]} continue if {$e eq "-"} { set chain 1 continue } set chain 0 switch -exact -- $mode { first - first! {return $e} all - all! {set found 1; set e} default {error "Invalid _pick mode: ($mode)"} } }] if {!$found && [string match *! $mode]} { error "No pattern matches for \"$variant\"" } set res } #>>> proc _verify_res {variant retcodes expected match_mode got options} { #<<< variable current_bench if {[dict get $options -code] ni $retcodes} { teabase_bench::output error "Error: $got\n[dict get $options -errorinfo]" throw [list BENCH BAD_CODE $current_bench $variant $retcodes [dict get $options -code]] \ "$current_bench/$variant: Expected codes [list $retcodes], got [dict get $options -code]" } switch -- $match_mode { exact { if {$got eq $expected} return } glob { if {[string match $expected $got]} return } regexp { if {[regexp $expected $got]} return } default { throw [list BENCH BAD_MATCH_MODE $match_mode] \ "Invalid match mode \"$match_mode\", should be one of exact, glob, regexp" } } throw [list BENCH BAD_RESULT $current_bench $variant $match_mode $expected $got] \ "$current_bench/$variant: Expected ($match_mode): -----------\n$expected\nGot: ----------\n$got" } #>>> proc _make_stats times { #<<< set res {} foreach stat { arithmetic_mean min max number_of_data sample_stddev sample_var population_stddev population_var } val [math::statistics::basic-stats $times] { dict set res $stat $val } dict set res median [math::statistics::median $times] dict set res harmonic_mean [/ [llength $times] [+ {*}[lmap time $times { / 1.0 $time }]]] dict set res cv [expr {[dict get $res population_stddev] / [dict get $res arithmetic_mean]}] } #>>> proc bench {name desc args} { #<<< variable match variable skip variable run variable skipped variable output variable current_bench # -target_cv - Run until the coefficient of variation is below this, up to -max_time # -max_time - Maximum number of seconds to keep running while the cv is converging # -min_time - Keep accumulating samples for at least this many seconds # -batch - The number of samples to take in a tight loop and average to count as a single sample. "auto" guesses a reasonable value to make a batch take at least 1000 usec. # -window - Consider at most the previous -window measurements for target_cv and the results array set opts { -setup {} -compare {} -cleanup {} -batch auto -match exact -returnCodes {ok return} -target_cv {0.0015} -min_time 0.0 -max_time 4.0 -min_it 30 -window 30 -overhead {} -deps {} } array set opts $args set badargs [lindex [_intersect3 [array names opts] { -setup -compare -cleanup -batch -match -result -results -returnCodes -target_cv -min_time -max_time -min_it -window -overhead -deps }] 0] if {[llength $badargs] > 0} { error "Unrecognised arguments: [join $badargs {, }]" } if {![string match $match $name] || [string match $skip $name]} { lappend skipped $name return } set normalized_codes [lmap e $opts(-returnCodes) { switch -- $e { ok {list 0} error {list 1} return {list 2} break {list 3} continue {list 4} default {set e} } }] set make_script { {batch script} { format {set __bench_i %d; while {[incr __bench_i -1] >= 0} %s} \ [list $batch] [list $script] } } set variant_stats {} set current_bench $name _run_if_set $opts(-setup) try { dict for {variant script} $opts(-compare) { try [join [_pick all $variant $opts(-deps)] \n] on error {errmsg options} { apply $output notice "Skipping variant $current_bench/$variant: $errmsg" continue } # Verify the first result against -result (if given), and estimate an appropriate batchsize to target a batch time of 1 ms to reduce quantization noise <<< set hint [lindex [time { catch {uplevel 1 $script} r o }] 0] unset -nocomplain expected if {[info exists opts(-results)]} { set expected [_pick first! $variant $opts(-results)] } elseif {[info exists opts(-result)]} { set expected $opts(-result) } if {[info exists expected]} { #apply $output debug "Verifying expected output for $current_bench/$variant" _verify_res $variant $normalized_codes $expected $opts(-match) $r $o } set single_empty [list uplevel 1 {}] set single_ex_s [list uplevel 1 $script] if 1 $single_empty ;# throw the first away if 1 $single_ex_s ;# throw the first away set single_overhead [lindex [time $single_empty 1000] 0] #puts stderr "single overhead: $single_overhead" set est_it [expr { max(1, int(round( 100.0/$hint ))) }] #puts stderr "hint: $hint, est_it: $est_it" set extime [lindex [time $single_ex_s $est_it] 0] set extime_comp [expr {$extime - $single_overhead}] #puts stderr "extime: $extime, extime comp: $extime_comp" if {$opts(-batch) eq "auto"} { if {$extime_comp <= 0} { # Can happen for very low overhead set batch 10000 } else { set batch [expr {int(round(max(1, 1000.0/$extime_comp)))}] } #puts stderr "Guessed batch size of $batch based on sample execution time $extime_comp usec" } else { set batch $opts(-batch) } #>>> # Measure the instrumentation overhead to compensate for it <<< #apply $output debug "Measuring overhead for $current_bench/$variant" set times {} set start [clock microseconds] ;# Prime [clock microseconds], start var set overhead_script [join [_pick all $variant $opts(-overhead)] \n] set bscript [apply $make_script $batch $overhead_script] set est [lindex [time {uplevel 1 $bscript} 1] 0] #apply $output debug "Initial overhead estimate: $est" for {set i 0} {$i < int(100000 / $est)} {incr i} { set start [clock microseconds] uplevel 1 $bscript lappend times [- [clock microseconds] $start] } set overhead [::tcl::mathfunc::min {*}[lmap e $times {expr {$e / double($batch)}}]] #apply $output debug [format {%s Overhead: %.3f usec, mean: %.3f for batch %d: %s} $variant $overhead [expr {double([+ {*}$times]) / ([llength $times]*$batch)}] $batch [list $overhead_script]] # Measure the instrumentation overhead to compensate for it >>> set cv {data { # Calculate the coefficient of variation of $data <<< lassign [::math::statistics::basic-stats $data] \ arithmetic_mean min max number_of_data sample_stddev sample_var population_stddev population_var expr { $population_stddev / double($arithmetic_mean) } }} #>>> set begin [clock microseconds] ;# Don't count the first run time or the overhead measurement into the total elapsed time set it 0 set times {} set means {} set cvmeans {} set cvtimes {} set elapsed 0 set bscript [apply $make_script $batch $script] #puts stderr "bscript $variant: $bscript" # Run at least: # - -min_it times # - for half a second # - until the coefficient of variability of the means has fallen below -target_cv, or a max of -max_time seconds while { [llength $times] < $opts(-min_it) || $elapsed < $opts(-min_time) || ($elapsed < $opts(-max_time) && $cvmeans > $opts(-target_cv)) } { set start [clock microseconds] uplevel 1 $bscript set batchtime [- [clock microseconds] $start] lappend times [expr { $batchtime / double($batch) - $overhead }] set elapsed [expr {([clock microseconds] - $begin)/1e6}] set cvtimes [lrange $times end-[+ 1 $opts(-window)] end] ;# Consider the last $opts(-window) data in estimating the variation lappend means [expr {[+ {*}$cvtimes]/[llength $cvtimes]}] set _cv [apply $cv $cvtimes] set cvmeans [apply $cv [lrange $means end-[+ 1 $opts(-window)] end]] #puts stderr "Got time for $variant batch($batch), batchtime $batchtime usec: [format %.4f [lindex $times end]], elapsed: [format %.3f $elapsed] sec[if {[info exists cvmeans]} {format {, cvmeans: %.3f} $cvmeans}][if {[info exists _cv]} {format {, cv: %.3f} $_cv}], mean: [format %.5f [lindex $means end]]" } dict set variant_stats $variant [_make_stats $cvtimes] dict set variant_stats $variant cvmeans $cvmeans dict set variant_stats $variant cv [apply $cv $cvtimes] dict set variant_stats $variant runtime $elapsed dict set variant_stats $variant it [llength $cvtimes] } lappend run $name $desc $variant_stats } finally { _run_if_set $opts(-cleanup) unset current_bench } }; namespace export bench #>>> namespace eval display_bench { namespace export * namespace ensemble create namespace path [concat [namespace path] { ::tcl::mathop }] proc _heading {txt {char -}} { #<<< format {%s %s %s} \ [string repeat $char 2] \ $txt \ [string repeat $char [- 80 5 [string length $txt]]] } #>>> proc short {name desc variant_stats relative {pick median}} { #<<< variable output teabase_bench::output notice [_heading [format {%s: "%s"} $name $desc]] # Gather the union of all the variant names from this and past runs set variants [dict keys $variant_stats] foreach {label past_run} $relative { foreach past_variant [dict keys $past_run] { if {$past_variant ni $variants} { lappend variants $past_variant } } } # Assemble the tabular data lappend rows [list "" "This run" {*}[dict keys $relative]] lappend rows {*}[lmap variant $variants { unset -nocomplain baseline set past_stats [dict values $relative] list $variant {*}[lmap stats [list $variant_stats {*}$past_stats] { if {![dict exists $stats $variant]} { #string cat -- set _ -- } else { set val [dict get $stats $variant $pick] if {![info exists baseline]} { set baseline $val format {%.3f%s} $val [expr { [dict exists $stats $variant cv] ? [format { cv:%.1f%%} [expr {100*[dict get $stats $variant cv]}]] : "" }] } elseif {$baseline == 0} { format x%s inf } else { format {x%.3f%s} [/ $val $baseline] [expr { [dict exists $stats $variant cv] ? [format { cv:%.1f%%} [expr {100*[dict get $stats $variant cv]}]] : "" }] } } }] }] # Determine the column widths set colsize {} foreach row $rows { set cols [llength $row] for {set c 0} {$c < $cols} {incr c} { set this_colsize [string length [lindex $row $c]] if { ![dict exists $colsize $c] || [dict get $colsize $c] < $this_colsize } { dict set colsize $c $this_colsize } } } # Construct the row format description set col_fmts [lmap {c size} $colsize { #string cat %${size}s set _ %${size}s }] set fmt " [join $col_fmts { | }]" set col_count [llength $col_fmts] # Output the row data foreach row $rows { set data [list {*}$row {*}[lrepeat [- $col_count [llength $row]] --]] teabase_bench::output notice [format $fmt {*}$data] } teabase_bench::output notice "" } #>>> } proc run_benchmarks {dir args} { #<<< variable skipped variable run variable match variable skip variable output set match * set skip {} set relative {} set display_mode short set display_mode_args {} set rundata . set consume_args [list \ count { upvar 1 i i args args set from $i incr i $count lrange $args $from [+ $from $count -1] } [namespace current] \ ] # Automatically save and compare with the previous run set args [list {*}{ -relative last last } {*}$args] set i 0 while {$i < [llength $args]} { lassign [apply $consume_args 1] next switch -- $next { -rundata { lassign [apply $consume_args 1] rundata } -load { lassign [apply $consume_args 1] load_script namespace eval :: $load_script } -match { lassign [apply $consume_args 1] match } -skip { lassign [apply $consume_args 1] skip } -relative { lassign [apply $consume_args 2] label rel_fn set rel_fn [file join $rundata $rel_fn] if {[file readable $rel_fn]} { dict set relative $label [_readfile [file join $rundata $rel_fn]] } } -save { lassign [apply $consume_args 1] save_fn set save_fn [file join $rundata $save_fn] } -display { lassign [apply $consume_args 1] display_mode set display_mode_args {} while {[string index [lindex $args $i] 0] ni {"-" ""}} { lappend display_mode_args [apply $consume_args 1] } } default { throw [list BENCH INVALID_ARG $next] \ "Invalid argument: \"$next\"" } } } set stats {} foreach f [glob -nocomplain -type f -dir $dir -tails *.bench] { try { namespace eval _bench_private {namespace path {::teabase_bench}} namespace eval _bench_private [list source [file join $dir $f]] } finally { namespace delete _bench_private } } set save [list {save_fn run} { set save_data $run if {[file readable $save_fn]} { # If the save file already exists, merge this run's data with it # rather than replacing it (keeps old tests that weren't executed # in this run) set newkeys [lmap {relname - -} $save_data {set relname}] set old [_readfile $save_fn] foreach {relname reldesc relstats} $old { if {$relname in $newkeys} continue lappend save_data $relname $reldesc $relstats } } _writefile $save_fn $save_data } [namespace current]] apply $save [file join $rundata last] $run ;# Always save as "last", even if explicitly saving as something else too if {[info exists save_fn]} { apply $save $save_fn $run } foreach {name desc variant_stats} $run { set relative_stats {} foreach {label relinfo} $relative { foreach {relname reldesc relstats} $relinfo { if {$relname eq $name} { lappend relative_stats $label $relstats break } } } try { display_bench $display_mode $name $desc $variant_stats $relative_stats {*}$display_mode_args } trap {TCL LOOKUP SUBCOMMAND} {errmsg options} { puts $options apply $output error "Invalid display mode: \"$display_mode\"" exit 1 } trap {TCL WRONGARGS} {errmsg options} { apply $output error "Invalid display mode params: $errmsg" exit 1 } } } #>>> } # vim: ft=tcl foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4 cyanogilvie-teabase-9345a87/termdebug.vim.in000066400000000000000000000002131526245020600210110ustar00rootroot00000000000000set number set mouse=a set foldlevel=100 packadd termdebug execute '@TERMDEBUG_ARG@ ' . $TESTFLAGS 2windo set nonumber 1windo set nonumber cyanogilvie-teabase-9345a87/tip445.h000066400000000000000000000070451526245020600171250ustar00rootroot00000000000000#ifndef _TIP445_H #define _TIP445_H /* teabase builds set TIP445_SHIM from a configure check (config.h). Without * one (a jitc cdef, say), go by the Tcl version: TIP 445 arrived in 8.7, under * pre-release names (Tcl_FetchIntRep, ...) in the 8.7 alphas. */ #ifndef TIP445_SHIM # define TIP445_SHIM (TCL_MAJOR_VERSION == 8 && (TCL_MINOR_VERSION < 7 || \ (TCL_MINOR_VERSION == 7 && TCL_RELEASE_LEVEL == TCL_ALPHA_RELEASE))) #endif #if TIP445_SHIM && TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 7 /* The 8.7 alphas (a2 - a5) have the API under the names TIP 445 had before * it was finalized: alias them rather than shim (Tcl_InitStringRep and * Tcl_HasStringRep already have their final names there) */ typedef Tcl_ObjIntRep Tcl_ObjInternalRep; # define Tcl_FetchInternalRep Tcl_FetchIntRep # define Tcl_StoreInternalRep Tcl_StoreIntRep # define Tcl_FreeInternalRep Tcl_FreeIntRep #elif TIP445_SHIM #include #include #include #if HAVE_HEDLEY_H # include HEDLEY_DIAGNOSTIC_PUSH HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION #else # if defined(__GNUC__) _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wunused-function\"") # elif defined(__clang__) _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-function\"") # endif #endif /* Just enough of TIP445 to build on Tcl 8.6 */ #ifndef Tcl_ObjInternalRep typedef union Tcl_ObjInternalRep { long longValue; double doubleValue; void* otherValuePtr; struct { void* ptr1; void* ptr2; } twoPtrValue; struct { void* ptr; unsigned long value; } ptrAndLongRep; struct { void* ptr; Tcl_Size size; } ptrAndSizeRep; } Tcl_ObjInternalRep; #endif #ifndef Tcl_FetchInternalRep # define Tcl_FetchInternalRep(obj, type) (Tcl_ObjInternalRep*)(((obj)->typePtr == (type)) ? &(obj)->internalRep : NULL) #endif #ifndef Tcl_FreeInternalRep static inline void Tcl_FreeInternalRep(Tcl_Obj* obj) { if (obj->typePtr) { if (obj->typePtr && obj->typePtr->freeIntRepProc) obj->typePtr->freeIntRepProc(obj); obj->typePtr = NULL; } } #endif #ifndef Tcl_StoreInternalRep static inline void Tcl_StoreInternalRep(Tcl_Obj* objPtr, const Tcl_ObjType* typePtr, const Tcl_ObjInternalRep* irPtr) { Tcl_FreeInternalRep(objPtr); objPtr->typePtr = typePtr; memcpy(&objPtr->internalRep, irPtr, sizeof(Tcl_ObjInternalRep)); } #endif #ifndef Tcl_HasStringRep # define Tcl_HasStringRep(obj) ((obj)->bytes != NULL) #endif #ifndef Tcl_InitStringRep static char* Tcl_InitStringRep(Tcl_Obj* objPtr, const char* bytes, unsigned numBytes) { assert(objPtr->bytes == NULL || bytes == NULL); if (numBytes > INT_MAX) { Tcl_Panic("max size of a Tcl value (%d bytes) exceeded", INT_MAX); } /* Allocate */ if (objPtr->bytes == NULL) { /* Allocate only as empty - extend later if bytes copied */ objPtr->length = 0; if (numBytes) { objPtr->bytes = (char*)attemptckalloc(numBytes + 1); if (objPtr->bytes == NULL) return NULL; if (bytes) { /* Copy */ memcpy(objPtr->bytes, bytes, numBytes); objPtr->length = (int)numBytes; } } else { //TclInitStringRep(objPtr, NULL, 0); objPtr->bytes = ""; objPtr->length = 0; } } else { objPtr->bytes = (char*)ckrealloc(objPtr->bytes, numBytes + 1); objPtr->length = (int)numBytes; } /* Terminate */ objPtr->bytes[objPtr->length] = '\0'; return objPtr->bytes; } #endif #if HAVE_HEDLEY_H HEDLEY_DIAGNOSTIC_POP #else # if defined(__GNUC__) _Pragma("GCC diagnostic pop") # elif defined(__clang__) _Pragma("clang diagnostic pop") # endif #endif #endif // TIP445_SHIM #endif // _TI445_H cyanogilvie-teabase-9345a87/tools/000077500000000000000000000000001526245020600170555ustar00rootroot00000000000000cyanogilvie-teabase-9345a87/tools/check_ver.tcl000066400000000000000000000000451526245020600215110ustar00rootroot00000000000000package require Tcl [lindex $argv 0] cyanogilvie-teabase-9345a87/tools/genStubs.tcl000066400000000000000000001032201526245020600213510ustar00rootroot00000000000000# Copied from the Tcl sources # # genStubs.tcl -- # # This script generates a set of stub files for a given # interface. # # # Copyright © 1998-1999 Scriptics Corporation. # Copyright © 2007 Daniel A. Steffen # # This software is copyrighted by the Regents of the University of # California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState # Corporation and other parties. The following terms apply to all files # associated with the software unless explicitly disclaimed in # individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. # # GOVERNMENT USE: If you are acquiring this software on behalf of the # U.S. government, the Government shall have only "Restricted Rights" # in the software and related documentation as defined in the Federal # Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you # are acquiring the software on behalf of the Department of Defense, the # software shall be classified as "Commercial Computer Software" and the # Government shall have only "Restricted Rights" as defined in Clause # 252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the # authors grant the U.S. Government and others acting in its behalf # permission to use and distribute the software in accordance with the # terms specified in this license. namespace eval genStubs { # libraryName -- # # The name of the entire library. This value is used to compute # the USE_*_STUBS macro and the name of the init file. variable libraryName "UNKNOWN" # interfaces -- # # An array indexed by interface name that is used to maintain # the set of valid interfaces. The value is empty. array set interfaces {} # curName -- # # The name of the interface currently being defined. variable curName "UNKNOWN" # scspec -- # # Storage class specifier for external function declarations. # Normally "EXTERN", may be set to something like XYZAPI # variable scspec "EXTERN" # epoch, revision -- # # The epoch and revision numbers of the interface currently being defined. # (@@@TODO: should be an array mapping interface names -> numbers) # variable epoch {} variable revision 0 # hooks -- # # An array indexed by interface name that contains the set of # subinterfaces that should be defined for a given interface. array set hooks {} # stubs -- # # This three dimensional array is indexed first by interface name, # second by platform name, and third by a numeric offset or the # constant "lastNum". The lastNum entry contains the largest # numeric offset used for a given interface/platform combo. Each # numeric offset contains the C function specification that # should be used for the given entry in the stub table. The spec # consists of a list in the form returned by parseDecl. array set stubs {} # outDir -- # # The directory where the generated files should be placed. variable outDir . } # genStubs::library -- # # This function is used in the declarations file to set the name # of the library that the interfaces are associated with (e.g. "tcl"). # This value will be used to define the inline conditional macro. # # Arguments: # name The library name. # # Results: # None. proc genStubs::library {name} { variable libraryName $name } # genStubs::interface -- # # This function is used in the declarations file to set the name # of the interface currently being defined. # # Arguments: # name The name of the interface. # # Results: # None. proc genStubs::interface {name} { variable curName $name variable interfaces set interfaces($name) {} return } # genStubs::scspec -- # # Define the storage class macro used for external function declarations. # Typically, this will be a macro like XYZAPI or EXTERN that # expands to either DLLIMPORT or DLLEXPORT, depending on whether # -DBUILD_XYZ has been set. # proc genStubs::scspec {value} { variable scspec $value } # genStubs::epoch -- # # Define the epoch number for this library. The epoch # should be incrememented when a release is made that # contains incompatible changes to the public API. # proc genStubs::epoch {value} { variable epoch $value } # genStubs::hooks -- # # This function defines the subinterface hooks for the current # interface. # # Arguments: # names The ordered list of interfaces that are reachable through the # hook vector. # # Results: # None. proc genStubs::hooks {names} { variable curName variable hooks set hooks($curName) $names return } # genStubs::declare -- # # This function is used in the declarations file to declare a new # interface entry. # # Arguments: # index The index number of the interface. # platform The platform the interface belongs to. Should be one # of generic, win, unix, or macosx or aqua or x11. # decl The C function declaration, or {} for an undefined # entry. # # Results: # None. proc genStubs::declare {args} { variable stubs variable curName variable revision incr revision if {[llength $args] == 2} { lassign $args index decl set platformList generic } elseif {[llength $args] == 3} { lassign $args index platformList decl } else { puts stderr "wrong # args: declare $args" return } # Check for duplicate declarations, then add the declaration and # bump the lastNum counter if necessary. foreach platform $platformList { if {[info exists stubs($curName,$platform,$index)]} { puts stderr "Duplicate entry: declare $args" } } regsub -all "\[ \t\n\]+" [string trim $decl] " " decl set decl [parseDecl $decl] if {([lindex $platformList 0] eq "deprecated")} { set stubs($curName,deprecated,$index) [lindex $platformList 1] set stubs($curName,generic,$index) $decl if {![info exists stubs($curName,generic,lastNum)] \ || ($index > $stubs($curName,generic,lastNum))} { set stubs($curName,generic,lastNum) $index } } elseif {([lindex $platformList 0] eq "nostub")} { set stubs($curName,nostub,$index) [lindex $platformList 1] set stubs($curName,generic,$index) $decl if {![info exists stubs($curName,generic,lastNum)] \ || ($index > $stubs($curName,generic,lastNum))} { set stubs($curName,generic,lastNum) $index } } else { foreach platform $platformList { if {$decl ne ""} { set stubs($curName,$platform,$index) $decl if {![info exists stubs($curName,$platform,lastNum)] \ || ($index > $stubs($curName,$platform,lastNum))} { set stubs($curName,$platform,lastNum) $index } } } } return } # genStubs::export -- # # This function is used in the declarations file to declare a symbol # that is exported from the library but is not in the stubs table. # # Arguments: # decl The C function declaration, or {} for an undefined # entry. # # Results: # None. proc genStubs::export {args} { if {[llength $args] != 1} { puts stderr "wrong # args: export $args" } return } # genStubs::rewriteFile -- # # This function replaces the machine generated portion of the # specified file with new contents. It looks for the !BEGIN! and # !END! comments to determine where to place the new text. # # If the file does not exist, it is created from scratch using the # optional before and after text to supply the boilerplate that # would normally surround the generated section. # # Arguments: # file The name of the file to modify. # text The new text to place in the file. # before (optional) Default text before !BEGIN! when creating a new file. # after (optional) Default text after !END! when creating a new file. # # Results: # None. proc genStubs::rewriteFile {file text {before ""} {after ""}} { if {![file exists $file]} { set out [open $file w] fconfigure $out -translation lf -encoding utf-8 if {$before ne ""} { puts $out $before } puts $out "/* !BEGIN!: Do not edit below this line. */" puts $out $text puts $out "/* !END!: Do not edit above this line. */" if {$after ne ""} { puts -nonewline $out $after } close $out return } set in [open ${file} r] fconfigure $in -eofchar "\x1A {}" -encoding utf-8 set out [open ${file}.new w] fconfigure $out -translation lf -encoding utf-8 while {![eof $in]} { set line [gets $in] if {[string match "*!BEGIN!*" $line]} { break } puts $out $line } puts $out "/* !BEGIN!: Do not edit below this line. */" puts $out $text while {![eof $in]} { set line [gets $in] if {[string match "*!END!*" $line]} { break } } puts $out "/* !END!: Do not edit above this line. */" puts -nonewline $out [read $in] close $in close $out file rename -force ${file}.new ${file} return } # genStubs::addPlatformGuard -- # # Wrap a string inside a platform #ifdef. # # Arguments: # plat Platform to test. # # Results: # Returns the original text inside an appropriate #ifdef. proc genStubs::addPlatformGuard {plat iftxt {eltxt {}} {withCygwin 0}} { set text "" switch $plat { win { append text "#if defined(_WIN32)" if {$withCygwin} { append text " || defined(__CYGWIN__)" } append text " /* WIN */\n${iftxt}" if {$eltxt ne ""} { append text "#else /* WIN */\n${eltxt}" } append text "#endif /* WIN */\n" } unix { append text "#if !defined(_WIN32)" if {$withCygwin} { append text " && !defined(__CYGWIN__)" } append text " && !defined(MAC_OSX_TCL)\ /* UNIX */\n${iftxt}" if {$eltxt ne ""} { append text "#else /* UNIX */\n${eltxt}" } append text "#endif /* UNIX */\n" } macosx { append text "#ifdef MAC_OSX_TCL /* MACOSX */\n${iftxt}" if {$eltxt ne ""} { append text "#else /* MACOSX */\n${eltxt}" } append text "#endif /* MACOSX */\n" } aqua { append text "#ifdef MAC_OSX_TK /* AQUA */\n${iftxt}" if {$eltxt ne ""} { append text "#else /* AQUA */\n${eltxt}" } append text "#endif /* AQUA */\n" } x11 { append text "#if !(defined(_WIN32)" if {$withCygwin} { append text " || defined(__CYGWIN__)" } append text " || defined(MAC_OSX_TK))\ /* X11 */\n${iftxt}" if {$eltxt ne ""} { append text "#else /* X11 */\n${eltxt}" } append text "#endif /* X11 */\n" } default { append text "${iftxt}${eltxt}" } } return $text } # genStubs::emitSlots -- # # Generate the stub table slots for the given interface. If there # are no generic slots, then one table is generated for each # platform, otherwise one table is generated for all platforms. # # Arguments: # name The name of the interface being emitted. # textVar The variable to use for output. # # Results: # None. proc genStubs::emitSlots {name textVar} { upvar $textVar text forAllStubs $name makeSlot 1 text {" void (*reserved$i)(void);\n"} return } # genStubs::parseDecl -- # # Parse a C function declaration into its component parts. # # Arguments: # decl The function declaration. # # Results: # Returns a list of the form {returnType name args}. The args # element consists of a list of type/name pairs, or a single # element "void". If the function declaration is malformed # then an error is displayed and the return value is {}. proc genStubs::parseDecl {decl} { if {![regexp {^(.*)\((.*)\)$} $decl all prefix args]} { set prefix $decl set args {} } set prefix [string trim $prefix] if {![regexp {^(.+[ ][*]*)([^ *]+)$} $prefix all rtype fname]} { puts stderr "Bad return type: $decl" return } set rtype [string trim $rtype] if {$args eq ""} { return [list $rtype $fname {}] } foreach arg [split $args ,] { lappend argList [string trim $arg] } if {![string compare [lindex $argList end] "..."]} { set args TCL_VARARGS foreach arg [lrange $argList 0 end-1] { set argInfo [parseArg $arg] if {[llength $argInfo] == 2 || [llength $argInfo] == 3} { lappend args $argInfo } else { puts stderr "Bad argument: '$arg' in '$decl'" return } } } else { set args {} foreach arg $argList { set argInfo [parseArg $arg] if {![string compare $argInfo "void"]} { lappend args "void" break } elseif {[llength $argInfo] == 2 || [llength $argInfo] == 3} { lappend args $argInfo } else { puts stderr "Bad argument: '$arg' in '$decl'" return } } } return [list $rtype $fname $args] } # genStubs::parseArg -- # # This function parses a function argument into a type and name. # # Arguments: # arg The argument to parse. # # Results: # Returns a list of type and name with an optional third array # indicator. If the argument is malformed, returns "". proc genStubs::parseArg {arg} { if {![regexp {^(.+[ ][*]*)([^][ *]+)(\[\])?$} $arg all type name array]} { if {$arg eq "void"} { return $arg } else { return } } set result [list [string trim $type] $name] if {$array ne ""} { lappend result $array } return $result } # genStubs::makeDecl -- # # Generate the prototype for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted declaration string. proc genStubs::makeDecl {name decl index} { variable scspec variable stubs variable libraryName lassign $decl rtype fname args append text "/* $index */\n" if {[info exists stubs($name,deprecated,$index)]} { append text "[string toupper $libraryName]_DEPRECATED(\"$stubs($name,deprecated,$index)\")\n" set line "$rtype" } elseif {[string range $rtype end-5 end] eq "MP_WUR"} { set line "$scspec [string trim [string range $rtype 0 end-6]]" } else { set line "$scspec $rtype" } set count [expr {2 - ([string length $line] / 8)}] if {$count >= 0} { append line [string range "\t\t\t" 0 $count] } set pad [expr {24 - [string length $line]}] if {$pad <= 0} { append line " " set pad 0 } if {$args eq ""} { append line $fname append text $line append text ";\n" return $text } append line $fname set arg1 [lindex $args 0] switch -exact $arg1 { void { append line "(void)" } TCL_VARARGS { set sep "(" foreach arg [lrange $args 1 end] { append line $sep set next {} append next [lindex $arg 0] if {[string index $next end] ne "*"} { append next " " } append next [lindex $arg 1] [lindex $arg 2] if {[string length $line] + [string length $next] \ + $pad > 76} { append text [string trimright $line] \n set line "\t\t\t\t" set pad 28 } append line $next set sep ", " } append line ", ...)" if {[lindex $args end] eq "{const char *} format"} { append line " TCL_FORMAT_PRINTF(" [expr {[llength $args] - 1}] ", " [llength $args] ")" } } default { set sep "(" foreach arg $args { append line $sep set next {} append next [lindex $arg 0] if {[string index $next end] ne "*"} { append next " " } append next [lindex $arg 1] [lindex $arg 2] if {[string length $line] + [string length $next] \ + $pad > 76} { append text [string trimright $line] \n set line "\t\t\t\t" set pad 28 } append line $next set sep ", " } append line ")" } } if {[string range $rtype end-5 end] eq "MP_WUR"} { append line " MP_WUR" } return "$text$line;\n" } # genStubs::makeMacro -- # # Generate the inline macro for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted macro definition. proc genStubs::makeMacro {name decl index} { lassign $decl rtype fname args set lfname [string tolower [string index $fname 0]] append lfname [string range $fname 1 end] set text "#define $fname \\\n\t(" if {$args eq ""} { append text "*" } append text "${name}StubsPtr->$lfname)" append text " /* $index */\n" return $text } # genStubs::makeSlot -- # # Generate the stub table entry for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted table entry. proc genStubs::makeSlot {name decl index} { lassign $decl rtype fname args variable stubs set lfname [string tolower [string index $fname 0]] append lfname [string range $fname 1 end] set text " " if {[info exists stubs($name,deprecated,$index)]} { append text "TCL_DEPRECATED_API(\"$stubs($name,deprecated,$index)\") " } elseif {[info exists stubs($name,nostub,$index)]} { append text "TCL_DEPRECATED_API(\"$stubs($name,nostub,$index)\") " } if {$args eq ""} { append text $rtype " *" $lfname "; /* $index */\n" return $text } if {[string range $rtype end-8 end] eq "__stdcall"} { append text [string trim [string range $rtype 0 end-9]] " (__stdcall *" $lfname ") " } elseif {[string range $rtype 0 11] eq "TCL_NORETURN"} { append text "TCL_NORETURN1 " [string trim [string range $rtype 12 end]] " (*" $lfname ") " } elseif {[string range $rtype end-5 end] eq "MP_WUR"} { append text [string trim [string range $rtype 0 end-6]] " (*" $lfname ") " } else { append text $rtype " (*" $lfname ") " } set arg1 [lindex $args 0] switch -exact $arg1 { void { append text "(void)" } TCL_VARARGS { set sep "(" foreach arg [lrange $args 1 end] { append text $sep [lindex $arg 0] if {[string index $text end] ne "*"} { append text " " } append text [lindex $arg 1] [lindex $arg 2] set sep ", " } append text ", ...)" if {[lindex $args end] eq "{const char *} format"} { append text " TCL_FORMAT_PRINTF(" [expr {[llength $args] - 1}] ", " [llength $args] ")" } } default { set sep "(" foreach arg $args { append text $sep [lindex $arg 0] if {[string index $text end] ne "*"} { append text " " } append text [lindex $arg 1] [lindex $arg 2] set sep ", " } append text ")" } } if {[string range $rtype end-5 end] eq "MP_WUR"} { append text " MP_WUR" } append text "; /* $index */\n" return $text } # genStubs::makeInit -- # # Generate the prototype for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted declaration string. proc genStubs::makeInit {name decl index} { if {[lindex $decl 2] eq ""} { append text " &" [lindex $decl 1] ", /* " $index " */\n" } else { append text " " [lindex $decl 1] ", /* " $index " */\n" } return $text } # genStubs::forAllStubs -- # # This function iterates over all of the platforms and invokes # a callback for each slot. The result of the callback is then # placed inside appropriate platform guards. # # Arguments: # name The interface name. # slotProc The proc to invoke to handle the slot. It will # have the interface name, the declaration, and # the index appended. # onAll If 1, emit the skip string even if there are # definitions for one or more platforms. # textVar The variable to use for output. # skipString The string to emit if a slot is skipped. This # string will be subst'ed in the loop so "$i" can # be used to substitute the index value. # # Results: # None. proc genStubs::forAllStubs {name slotProc onAll textVar {skipString {"/* Slot $i is reserved */\n"}}} { variable stubs upvar $textVar text set plats [array names stubs $name,*,lastNum] if {[info exists stubs($name,generic,lastNum)]} { # Emit integrated stubs block set lastNum -1 foreach plat [array names stubs $name,*,lastNum] { if {$stubs($plat) > $lastNum} { set lastNum $stubs($plat) } } for {set i 0} {$i <= $lastNum} {incr i} { set slots [array names stubs $name,*,$i] set emit 0 if {[info exists stubs($name,deprecated,$i)]} { append text [$slotProc $name $stubs($name,generic,$i) $i] set emit 1 } elseif {[info exists stubs($name,nostub,$i)]} { append text [$slotProc $name $stubs($name,generic,$i) $i] set emit 1 } elseif {[info exists stubs($name,generic,$i)]} { if {[llength $slots] > 1} { puts stderr "conflicting generic and platform entries:\ $name $i" } append text [$slotProc $name $stubs($name,generic,$i) $i] set emit 1 } elseif {[llength $slots] > 0} { array set slot {unix 0 x11 0 win 0 macosx 0 aqua 0} foreach s $slots { set slot([lindex [split $s ,] 1]) 1 } # "aqua", "macosx" and "x11" are special cases: # "macosx" implies "unix", "aqua" implies "macosx" and "x11" # implies "unix", so we need to be careful not to emit # duplicate stubs entries: if {($slot(unix) && $slot(macosx)) || ( ($slot(unix) || $slot(macosx)) && ($slot(x11) || $slot(aqua)))} { puts stderr "conflicting platform entries: $name $i" } ## unix ## set temp {} set plat unix if {!$slot(aqua) && !$slot(x11)} { if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } ## x11 ## set temp {} set plat x11 if {!$slot(unix) && !$slot(macosx)} { if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } ## win ## set temp {} set plat win if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } ## macosx ## set temp {} set plat macosx if {!$slot(aqua) && !$slot(x11)} { if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$slot(unix)} { append temp [$slotProc $name $stubs($name,unix,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } ## aqua ## set temp {} set plat aqua if {!$slot(unix) && !$slot(macosx)} { if {[string range $skipString 1 2] ne "/*"} { # genStubs.tcl previously had a bug here causing it to # erroneously generate both a unix entry and an aqua # entry for a given stubs table slot. To preserve # backwards compatibility, generate a dummy stubs entry # before every aqua entry (note that this breaks the # correspondence between emitted entry number and # actual position of the entry in the stubs table, e.g. # TkIntStubs entry 113 for aqua is in fact at position # 114 in the table, entry 114 at position 116 etc). eval {append temp} $skipString set temp "# if TCL_MAJOR_VERSION < 9\n[string range $temp 0 end-1] /*\ Dummy entry for stubs table backwards\ compatibility */\n# endif /* TCL_MAJOR_VERSION < 9 */\n" } if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } } if {!$emit} { eval {append text} $skipString } } } else { # Emit separate stubs blocks per platform array set block {unix 0 x11 0 win 0 macosx 0 aqua 0} foreach s [array names stubs $name,*,lastNum] { set block([lindex [split $s ,] 1]) 1 } ## unix ## if {$block(unix) && !$block(x11)} { set temp {} set plat unix set lastNum $stubs($name,$plat,lastNum) for {set i 0} {$i <= $lastNum} {incr i} { if {[info exists stubs($name,$plat,$i)]} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } else { eval {append temp} $skipString } } append text [addPlatformGuard $plat $temp {} true] } ## win ## if {$block(win)} { set temp {} set plat win set lastNum $stubs($name,$plat,lastNum) for {set i 0} {$i <= $lastNum} {incr i} { if {[info exists stubs($name,$plat,$i)]} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } else { eval {append temp} $skipString } } append text [addPlatformGuard $plat $temp {} true] } ## macosx ## if {($block(unix) || $block(macosx)) && !$block(aqua) && !$block(x11)} { set temp {} set lastNum -1 foreach plat {unix macosx} { if {$block($plat)} { set lastNum [expr {$lastNum > $stubs($name,$plat,lastNum) ? $lastNum : $stubs($name,$plat,lastNum)}] } } for {set i 0} {$i <= $lastNum} {incr i} { set emit 0 foreach plat {unix macosx} { if {[info exists stubs($name,$plat,$i)]} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] set emit 1 break } } if {!$emit} { eval {append temp} $skipString } } append text [addPlatformGuard macosx $temp] } ## aqua ## if {$block(aqua)} { set temp {} set lastNum -1 foreach plat {unix macosx aqua} { if {$block($plat)} { set lastNum [expr {$lastNum > $stubs($name,$plat,lastNum) ? $lastNum : $stubs($name,$plat,lastNum)}] } } for {set i 0} {$i <= $lastNum} {incr i} { set emit 0 foreach plat {unix macosx aqua} { if {[info exists stubs($name,$plat,$i)]} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] set emit 1 break } } if {!$emit} { eval {append temp} $skipString } } append text [addPlatformGuard aqua $temp] } ## x11 ## if {$block(x11)} { set temp {} set lastNum -1 foreach plat {unix macosx x11} { if {$block($plat)} { set lastNum [expr {$lastNum > $stubs($name,$plat,lastNum) ? $lastNum : $stubs($name,$plat,lastNum)}] } } for {set i 0} {$i <= $lastNum} {incr i} { set emit 0 foreach plat {unix macosx x11} { if {[info exists stubs($name,$plat,$i)]} { if {$plat ne "macosx"} { append temp [$slotProc $name \ $stubs($name,$plat,$i) $i] } else { eval {set etxt} $skipString append temp [addPlatformGuard $plat [$slotProc \ $name $stubs($name,$plat,$i) $i] $etxt true] } set emit 1 break } } if {!$emit} { eval {append temp} $skipString } } append text [addPlatformGuard x11 $temp {} true] } } } # genStubs::emitDeclarations -- # # This function emits the function declarations for this interface. # # Arguments: # name The interface name. # textVar The variable to use for output. # # Results: # None. proc genStubs::emitDeclarations {name textVar} { upvar $textVar text append text "\n/*\n * Exported function declarations:\n */\n\n" forAllStubs $name makeDecl 0 text return } # genStubs::emitMacros -- # # This function emits the inline macros for an interface. # # Arguments: # name The name of the interface being emitted. # textVar The variable to use for output. # # Results: # None. proc genStubs::emitMacros {name textVar} { variable libraryName upvar $textVar text set upName [string toupper $libraryName] append text "\n#if defined(USE_${upName}_STUBS)\n" append text "\n/*\n * Inline function declarations:\n */\n\n" forAllStubs $name makeMacro 0 text append text "\n#endif /* defined(USE_${upName}_STUBS) */\n" return } # genStubs::emitHeader -- # # This function emits the body of the Decls.h file for # the specified interface. # # Arguments: # name The name of the interface being emitted. # # Results: # None. proc genStubs::emitHeader {name} { variable outDir variable hooks variable epoch variable revision set capName [string toupper [string index $name 0]] append capName [string range $name 1 end] if {$epoch ne ""} { set CAPName [string toupper $name] append text "\n" append text "#define ${CAPName}_STUBS_EPOCH $epoch\n" append text "#define ${CAPName}_STUBS_REVISION $revision\n" } append text "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n" emitDeclarations $name text if {[info exists hooks($name)]} { append text "\ntypedef struct {\n" foreach hook $hooks($name) { set capHook [string toupper [string index $hook 0]] append capHook [string range $hook 1 end] append text " const struct ${capHook}Stubs *${hook}Stubs;\n" } append text "} ${capName}StubHooks;\n" } append text "\ntypedef struct ${capName}Stubs {\n" append text " int magic;\n" if {$epoch ne ""} { append text " int epoch;\n" append text " int revision;\n" } if {[info exists hooks($name)]} { append text " const ${capName}StubHooks *hooks;\n\n" } else { append text " void *hooks;\n\n" } emitSlots $name text append text "} ${capName}Stubs;\n\n" append text "extern const ${capName}Stubs *${name}StubsPtr;\n\n" append text "#ifdef __cplusplus\n}\n#endif\n" emitMacros $name text set guard _[string toupper ${name}]DECLS_H rewriteFile [file join $outDir ${name}Decls.h] $text \ "#ifndef $guard\n#define $guard\n" \ "#endif /* $guard */\n" return } # genStubs::emitInit -- # # Generate the table initializers for an interface. # # Arguments: # name The name of the interface to initialize. # textVar The variable to use for output. # # Results: # Returns the formatted output. proc genStubs::emitInit {name textVar} { variable hooks variable interfaces variable epoch upvar $textVar text set root 1 set capName [string toupper [string index $name 0]] append capName [string range $name 1 end] if {[info exists hooks($name)]} { append text "\nstatic const ${capName}StubHooks ${name}StubHooks = \{\n" set sep " " foreach sub $hooks($name) { append text $sep "&${sub}Stubs" set sep ",\n " } append text "\n\};\n" } foreach intf [array names interfaces] { if {[info exists hooks($intf)]} { if {$name in $hooks($intf)} { set root 0 break } } } append text "\n" if {!$root} { append text "static " } append text "const ${capName}Stubs ${name}Stubs = \{\n TCL_STUB_MAGIC,\n" if {$epoch ne ""} { set CAPName [string toupper $name] append text " ${CAPName}_STUBS_EPOCH,\n" append text " ${CAPName}_STUBS_REVISION,\n" } if {[info exists hooks($name)]} { append text " &${name}StubHooks,\n" } else { append text " 0,\n" } forAllStubs $name makeInit 1 text {" 0, /* $i */\n"} append text "\};\n" return } # genStubs::emitInits -- # # This function emits the body of the StubInit.c file for # the specified interface. # # Arguments: # name The name of the interface being emitted. # # Results: # None. proc genStubs::emitInits {} { variable hooks variable outDir variable libraryName variable interfaces # Assuming that dependencies only go one level deep, we need to emit # all of the leaves first to avoid needing forward declarations. set leaves {} set roots {} foreach name [lsort [array names interfaces]] { if {[info exists hooks($name)]} { lappend roots $name } else { lappend leaves $name } } foreach name $leaves { emitInit $name text } foreach name $roots { emitInit $name text } set capName [string toupper [string index $libraryName 0]] append capName [string range $libraryName 1 end] set before "#include \"${libraryName}.h\"\n" set after [join [list \ "" "" \ "MODULE_SCOPE const ${capName}Stubs* const ${libraryName}ConstStubsPtr;" \ "const ${capName}Stubs* const ${libraryName}ConstStubsPtr = &${libraryName}Stubs;" \ "" \ ] "\n"] rewriteFile [file join $outDir ${libraryName}StubInit.c] $text $before $after } # genStubs::init -- # # This is the main entry point. # # Arguments: # None. # # Results: # None. proc genStubs::init {} { global argv argv0 variable outDir variable interfaces if {[llength $argv] < 2} { puts stderr "usage: $argv0 outDir declFile ?declFile...?" exit 1 } set outDir [lindex $argv 0] foreach file [lrange $argv 1 end] { source -encoding utf-8 $file } foreach name [lsort [array names interfaces]] { #puts "Emitting $name" emitHeader $name } emitInits } # lassign -- # # This function emulates the TclX lassign command. # # Arguments: # valueList A list containing the values to be assigned. # args The list of variables to be assigned. # # Results: # Returns any values that were not assigned to variables. if {[namespace which lassign] ne ""} { proc lassign {valueList args} { if {[llength $args] == 0} { error "wrong # args: should be \"lassign list varName ?varName ...?\"" } uplevel [list foreach $args $valueList {break}] return [lrange $valueList [llength $args] end] } } genStubs::init cyanogilvie-teabase-9345a87/tools/interned_deps.py000077500000000000000000000411311526245020600222550ustar00rootroot00000000000000#!/usr/bin/env python3 """ Build version-pinned interned static dependencies from a JSON manifest. Designed to be called from meson custom_targets (or autotools Makefile rules) as a single unified entry point for building C library dependencies that get statically linked into a Tcl extension. The driving goal is reproducibility: a given git rev of the parent package should strictly imply the exact source and build parameters for its dependencies, independent of the developer's shell environment. This script enforces that by: * sanitizing the environment (dropping CFLAGS / CXXFLAGS / LDFLAGS / CPPFLAGS / MAKEFLAGS before invoking cmake / configure / make); * always wiping any stale cmake build dir before re-configuring, which defends against cached flags from a previous run that had environment variables set; * pinning CMAKE_C_FLAGS / CMAKE_CXX_FLAGS to the manifest values (empty by default) so env CFLAGS can't leak into cmake's cache; * hashing the manifest + submodule SHAs + host triple into a stamp file and short-circuiting when nothing relevant has changed. Manifest schema (JSON): { "deps": { "": { "source": "", "builder": "cmake" | "autoconf" | "make", "depends": ["", ...], # optional "defines": { "CMAKE_VAR": "value", ... }, # cmake only "configure_flags": ["--with-foo", ...], # autoconf only "make_env": { "FOO": "bar", ... }, # make only "makefile": "makefile.shared", # make only, default "makefile" "post_install": [ # optional, any builder { "type": "sed", "file": "${prefix}/lib/foo.cmake", "replace": [["search", "replace"], ...] } ] } }, "unsupported_hosts": ["*-*-mingw*", ...] # optional fnmatch patterns } String values in 'defines', 'configure_flags', 'make_env', and 'post_install' may reference ${prefix}, ${host}, or ${source} (the resolved source directory of the current dep) and these will be expanded at runtime. """ import argparse import fnmatch import hashlib import json import os import platform import re import shutil import subprocess import sys from pathlib import Path # Environment variables that would leak build configuration into the # interned dep build if propagated. These are dropped from the env before # every subprocess invocation. If a dep's build genuinely needs one of # these (rare), the manifest should pass it explicitly as a cmake define or # configure flag. ENV_BLOCK = frozenset({ 'CFLAGS', 'CXXFLAGS', 'CPPFLAGS', 'LDFLAGS', 'CMAKE_C_FLAGS', 'CMAKE_CXX_FLAGS', 'MAKEFLAGS', 'MAKELEVEL', }) def sanitized_env(): return {k: v for k, v in os.environ.items() if k not in ENV_BLOCK} def detect_host(): """Return a gcc-style triplet for the current build host.""" for cc in ('cc', 'gcc', 'clang'): try: r = subprocess.run([cc, '-dumpmachine'], capture_output=True, text=True, check=True) return r.stdout.strip() except (subprocess.CalledProcessError, FileNotFoundError): continue # No C compiler found in PATH — fall back to a coarse uname-based triple. m = platform.machine() s = platform.system().lower() if s == 'linux': return f'{m}-pc-linux-gnu' if s == 'darwin': return f'{m}-apple-darwin' if s == 'windows': return f'{m}-pc-mingw64' return f'{m}-unknown-{s}' def host_matches(host, patterns): return any(fnmatch.fnmatch(host, p) for p in patterns) def git_sha(source_dir): """Return HEAD SHA of source_dir as a git tree, or a deep content hash.""" try: r = subprocess.run( ['git', '-C', str(source_dir), 'rev-parse', 'HEAD'], capture_output=True, text=True, check=True) sha = r.stdout.strip() # Also fold in whether the working tree is dirty, so a dev who # hacks on the dep source without committing still gets rebuilds. dirty = subprocess.run( ['git', '-C', str(source_dir), 'status', '--porcelain'], capture_output=True, text=True, check=False).stdout if dirty.strip(): sha += '-dirty-' + hashlib.sha256(dirty.encode()).hexdigest()[:8] return sha except (subprocess.CalledProcessError, FileNotFoundError): pass # Fall back: hash the tree contents. Slow on large trees but correct. h = hashlib.sha256() for p in sorted(Path(source_dir).rglob('*')): if p.is_file(): h.update(str(p.relative_to(source_dir)).encode()) h.update(p.read_bytes()) return h.hexdigest() _INTERP_RE = re.compile(r'\$\{([^}]+)\}') def interpolate(value, vars): """Recursively expand ${name} references in strings inside value.""" if isinstance(value, str): return _INTERP_RE.sub(lambda m: vars.get(m.group(1), m.group(0)), value) if isinstance(value, list): return [interpolate(v, vars) for v in value] if isinstance(value, dict): return {k: interpolate(v, vars) for k, v in value.items()} return value def topo_sort(deps): """Return dep names in build order, respecting 'depends' edges.""" order = [] seen = set() def visit(name, path): if name in seen: return if name in path: raise ValueError(f'dependency cycle: {" -> ".join(path + [name])}') for d in deps[name].get('depends', []): if d not in deps: raise ValueError( f'{name}: depends on unknown {d!r}') visit(d, path + [name]) seen.add(name) order.append(name) for name in deps: visit(name, []) return order class Builder: def __init__(self, name, spec, source_dir, build_dir, prefix, vars, jobs): self.name = name self.spec = spec self.source_dir = source_dir self.build_dir = build_dir self.prefix = prefix self.vars = vars self.jobs = jobs def _log(self, msg): print(f'[interned_deps:{self.name}] {msg}', flush=True) def _run(self, cmd, cwd=None): self._log(' '.join(str(c) for c in cmd)) subprocess.run(cmd, check=True, env=sanitized_env(), cwd=cwd) def build(self): raise NotImplementedError class CmakeBuilder(Builder): def build(self): # Always wipe the build dir before re-configuring. cmake caches # CMAKE_C_FLAGS on first run and never re-evaluates environment on # subsequent runs, so a stale cache from a previous run with env # CFLAGS set (e.g. -fsanitize=address) would silently contaminate # every future build. if self.build_dir.exists(): shutil.rmtree(self.build_dir) self.build_dir.mkdir(parents=True) defines = interpolate(self.spec.get('defines', {}), self.vars) # Pin CMAKE_C_FLAGS / CMAKE_CXX_FLAGS to the manifest values (empty # by default). This overrides whatever cmake would otherwise # inherit from the environment on first configure. defines.setdefault('CMAKE_C_FLAGS', '') defines.setdefault('CMAKE_CXX_FLAGS', '') # Ensure a sensible install prefix is set unless the manifest # supplied one. defines.setdefault('CMAKE_INSTALL_PREFIX', str(self.prefix)) cmd = ['cmake', '-B', str(self.build_dir), '-S', str(self.source_dir)] for k, v in defines.items(): cmd.append(f'-D{k}={v}') self._run(cmd) self._run(['cmake', '--build', str(self.build_dir), '-j', str(self.jobs)]) self._run(['cmake', '--install', str(self.build_dir)]) class AutoconfBuilder(Builder): def build(self): if self.build_dir.exists(): shutil.rmtree(self.build_dir) self.build_dir.mkdir(parents=True) configure = self.source_dir / 'configure' if not configure.exists(): raise FileNotFoundError( f'{self.name}: {configure} not found (run autoreconf?)') args = [str(configure), f'--prefix={self.prefix}'] args.extend(interpolate(self.spec.get('configure_flags', []), self.vars)) self._run(args, cwd=self.build_dir) self._run(['make', f'-j{self.jobs}'], cwd=self.build_dir) self._run(['make', 'install'], cwd=self.build_dir) class MakeBuilder(Builder): def build(self): # 'make' builds happen in-tree (the source dir IS the build dir), # so a stale object from a previous run could otherwise corrupt # the build. Default to running `make clean` first; the manifest # can override with pre_build to a different list of targets, or # disable with an empty list. # # If the manifest doesn't specify a makefile, omit -f and let make # use its standard search order (GNUmakefile, makefile, Makefile). make_base = ['make'] makefile = self.spec.get('makefile') if makefile: make_base += ['-f', makefile] make_env = interpolate(self.spec.get('make_env', {}), self.vars) common = [f'{k}={v}' for k, v in make_env.items()] common.append(f'PREFIX={self.prefix}') for target in self.spec.get('pre_build', ['clean']): self._run(make_base + common + [target], cwd=self.source_dir) self._run(make_base + [f'-j{self.jobs}'] + common, cwd=self.source_dir) self._run(make_base + ['install'] + common, cwd=self.source_dir) BUILDERS = { 'cmake': CmakeBuilder, 'autoconf': AutoconfBuilder, 'make': MakeBuilder, } def sed_hook(hook, vars): file = Path(interpolate(hook['file'], vars)) content = file.read_text() for pattern, replacement in hook['replace']: content = content.replace( interpolate(pattern, vars), interpolate(replacement, vars)) file.write_text(content) HOOKS = { 'sed': sed_hook, } def compute_stamp_hash(manifest_path, deps, host): h = hashlib.sha256() h.update(manifest_path.read_bytes()) h.update(b'\n__host__\n') h.update(host.encode()) for name in sorted(deps): spec = deps[name] sha = git_sha(spec['source']) h.update(f'\n{name}:{sha}'.encode()) return h.hexdigest() def read_stamp(stamp_path): if not stamp_path.exists(): return None try: return json.loads(stamp_path.read_text()) except (json.JSONDecodeError, OSError): return None def write_stamp(stamp_path, stamp_hash, prefix): stamp_path.parent.mkdir(parents=True, exist_ok=True) stamp_path.write_text(json.dumps({ 'hash': stamp_hash, 'prefix': str(prefix), }, indent=2) + '\n') def main(): ap = argparse.ArgumentParser(description=__doc__.strip().split('\n\n')[0]) ap.add_argument('--manifest', required=True, type=Path, help='Path to the JSON manifest') ap.add_argument('--source-root', type=Path, default=Path.cwd(), help='Root directory that dep "source" paths are relative to') ap.add_argument('--prefix', required=True, type=Path, help='Shared install prefix for all deps') ap.add_argument('--build', required=True, type=Path, help='Root directory for per-dep build trees') ap.add_argument('--stamp', required=True, type=Path, help='Stamp file written on success') ap.add_argument('--jobs', type=int, default=os.cpu_count() or 1, help='Parallel build jobs (default: nproc)') ap.add_argument('--host', default=None, help='Target host triple (default: detect)') ap.add_argument('--force', action='store_true', help='Rebuild even if the stamp is up-to-date') ap.add_argument('--copy-artifact', action='append', default=[], metavar='SRC:DEST', help='After a successful build, copy / to ' '. Used to flatten cmake\'s lib/ install layout ' 'into a meson custom_target output namespace. May be ' 'repeated.') args = ap.parse_args() try: manifest = json.loads(args.manifest.read_text()) except (json.JSONDecodeError, OSError) as e: print(f'ERROR: cannot read manifest {args.manifest}: {e}', file=sys.stderr) return 1 deps = manifest.get('deps', {}) if not deps: print(f'ERROR: manifest {args.manifest} has no deps', file=sys.stderr) return 1 host = args.host or detect_host() unsupported = manifest.get('unsupported_hosts', []) if host_matches(host, unsupported): print(f'ERROR: host {host!r} is declared unsupported in ' f'{args.manifest} (matched pattern in unsupported_hosts)', file=sys.stderr) return 1 # Resolve source paths against --source-root. source_root = args.source_root.resolve() for name, spec in deps.items(): spec['source'] = (source_root / spec['source']).resolve() if not spec['source'].is_dir(): print(f'ERROR: {name}: source {spec["source"]} not found', file=sys.stderr) return 1 # Validate --copy-artifact specs up front so a bad arg fails fast. copy_specs = [] for spec in args.copy_artifact: if ':' not in spec: print(f'ERROR: --copy-artifact must be SRC:DEST, got {spec!r}', file=sys.stderr) return 1 src_rel, dest = spec.split(':', 1) copy_specs.append((src_rel, Path(dest))) def do_copy_artifacts(prefix): for src_rel, dest_path in copy_specs: src = prefix / src_rel if not src.is_file(): print(f'ERROR: --copy-artifact source {src} not found', file=sys.stderr) return False dest_path.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(src, dest_path) print(f'[interned_deps] copied {src} -> {dest_path}', flush=True) return True prefix = args.prefix.resolve() stamp_hash = compute_stamp_hash(args.manifest, deps, host) # Stamp is valid only if hash matches AND prefix exists AND every # --copy-artifact destination still exists. This handles the case # where the meson custom_target outputs were wiped (deps-clean) but # the install prefix was somehow left intact. def all_copy_dests_present(): return all(dest.is_file() for _, dest in copy_specs) prior = read_stamp(args.stamp) if (not args.force and prior and prior.get('hash') == stamp_hash and prior.get('prefix') == str(prefix) and prefix.exists() and all_copy_dests_present()): print(f'[interned_deps] stamp up-to-date for {host}, skipping', flush=True) return 0 order = topo_sort(deps) print(f'[interned_deps] host={host} order={order}', flush=True) build_root = args.build.resolve() build_root.mkdir(parents=True, exist_ok=True) prefix.mkdir(parents=True, exist_ok=True) vars = { 'prefix': str(prefix), 'host': host, 'jobs': str(args.jobs), } for name in order: spec = deps[name] vars['source'] = str(spec['source']) builder_cls = BUILDERS.get(spec.get('builder')) if not builder_cls: print(f'ERROR: {name}: unknown builder ' f'{spec.get("builder")!r}', file=sys.stderr) return 1 build_dir = build_root / name b = builder_cls(name, spec, spec['source'], build_dir, prefix, dict(vars), args.jobs) try: b.build() except subprocess.CalledProcessError as e: print(f'ERROR: {name}: build failed ({e})', file=sys.stderr) return 1 for hook in spec.get('post_install', []): hook_fn = HOOKS.get(hook.get('type')) if not hook_fn: print(f'ERROR: {name}: unknown post_install type ' f'{hook.get("type")!r}', file=sys.stderr) return 1 try: hook_fn(hook, vars) except OSError as e: print(f'ERROR: {name}: post_install {hook["type"]} failed: {e}', file=sys.stderr) return 1 if not do_copy_artifacts(prefix): return 1 write_stamp(args.stamp, stamp_hash, prefix) print(f'[interned_deps] build complete, stamp written to {args.stamp}', flush=True) return 0 if __name__ == '__main__': sys.exit(main()) cyanogilvie-teabase-9345a87/tools/make_termdebug_arg.tcl000066400000000000000000000007251526245020600233710ustar00rootroot00000000000000lassign $argv build_dir source_root tclsh package_name package_version puts -nonewline {Termdebug -ex set\ print\ pretty\ on --args } puts -nonewline [string map {{ } {\ }} $tclsh] puts -nonewline " [file join $source_root tests/all.tcl] -singleproc 1 -load " puts -nonewline [string map {{ } {\ }} {apply {{dir n v} {source [file join $dir pkgIndex.tcl]; package require -exact $n $v}} }] puts [string map {{ } {\ }} [list $build_dir $package_name $package_version]] cyanogilvie-teabase-9345a87/tools/test_preamble.tcl000066400000000000000000000024631526245020600224140ustar00rootroot00000000000000# teabase test launcher preamble. # # Invoked as `tclsh test_preamble.tcl `. # Pops off $::argv, appends any $env(TESTFLAGS) tokens # (backwards compatibility with the older runtests.tcl wrapper — a # whitespace-separated list of tcltest configure options), and sources # the real test script in-process. # # Runs in-process (not a subprocess) so `meson test --test-args` flows # through to the test script's argv and `meson test --wrapper valgrind` # follows the tclsh that actually runs the tests (no --trace-children # needed). tcltest's per-file subprocesses under `singleProcess 0` are # spawned with [info nameofexecutable] directly against each .test file, # so this preamble only participates in the top-level process — TESTFLAGS # applied here becomes tcltest config, which tcltest then propagates to # its children via its own Configure-passthrough. if {[llength $argv] < 1} { puts stderr "usage: [info script] \[tcltest_args...\]" exit 2 } set argv [lassign $argv argv0] if {[info exists env(TESTFLAGS)]} { lappend argv {*}$env(TESTFLAGS) } if {"-singleproc" ni $argv} {lappend argv -singleproc 1} # Make [info script] / $argv0 look like the test script was invoked # directly, so any relative-path idioms in it keep working. source $argv0